6 Replies Latest reply on May 12, 2017 11:32 AM by user_342122993

    FIFO-based triggering

    piotr.wyderski_2406846

      Now things get really interesting! I have a datapath-based component (you helped me to develop it in the Parallel port thread). Its function is as follows: idle a trigger arrives (51kHz if that matters). Then issue 9 consecutive DMA transfers on the same channel to an 8-bit GPIO port, generating externally visible strobes after each transfer. and sampling the status of an external 1-bit input (through the carry chain), collects the last 8 results and store the final 8 bits into an output FIFO. The datapath FSM manages all that. This, together with a Count7-based fixed duty cycle two channel (with deadbanding) 500kHz PWM generator fits within a single UDB.

         

      The question is about triggering. The trigger signal pulse will have unknown duration (now 50% @ f=1/51kHz, which is long in terms of the 64MHz datapath clock), but synchronized, so a resettable edge detector is required. It can be easily written in Verilog, but it would eat up one PLD macrocell. So I've invented the following: since one FIFO is unused, it could be configured to internal dynamic mode (d1_load=0). Then its write strobe (f1_load) is connected to the trigger signal, the write data source could be anything except of CPU/DMA, according to the manual (now: A1) and f1_bus_stat indicates whether the FIFO is not empty. Then the system starts with f1_bus_stat high (empty FIFO), the trigger causes it to load something into the FIFO (the fetched value has no meaning), f1_bus_stat gets low and datapath starts its job. In the final state D1 is loaded from the FIFO, which makes it empty again. The result is a resettable edge detector based on the FIFO; moreover, it can buffer up to 4 trigger signals should they arrive before the datapath's job completion (cannot happen here, but still a potentially useful feature).

         

      The scope confirms it works like a charm, but since it abuses the FIFO so much beyond its designed purpose, there is a question whether the whole approach is legal in terms of the specification.

        • 1. Re: FIFO-based triggering
          bhwj

          Hi Piotr ,

             

          It is not illegal ,but I have not FIFO used in this manner as its purpose is different.It is a good idea if you do not want to use PLDs but some may feel it is a convoluted way of achieving a edge detector.

             

          But I'm wondering how you removed the byte from FIFO in the last state ,In the dynamic FIFO control mode, d0_load and d1_load are not available for their normal use in loading the D0/D1 registers from F0/F1. 

          • 2. Re: FIFO-based triggering
            piotr.wyderski_2406846

            The byte is removed in the last stage by fetching it to A0 (and then xoring A0 with A0 in the next stage, as the value is unpredictable. See the attached DCT dump. In the meantime I changed the value of 9 iterations to 16, because it allows me to do more in the next stage. Another interesting trick is to use A0_A0 in the comparator section. Then I can use .cl1() directly as one of my strobes (STCP, it is for NPIC6C596) and force it low where necessary (because A0 < A0 always results in 0), without using any PLD resources. The remaining strobe (SHCP) is directly encoded in the highest bit of cs_addr, sparing another macrocell. Very compact, but undebuggable without a scope. :)

               

             

               


            //`#start header` -- edit after this line, do not edit this line
            // ========================================
            //
            // Copyright YOUR COMPANY, THE YEAR
            // All Rights Reserved
            // UNPUBLISHED, LICENSED SOFTWARE.
            //
            // CONFIDENTIAL AND PROPRIETARY INFORMATION
            // WHICH IS THE PROPERTY OF your company.
            //
            // ========================================
            `include "cypress.v"
            //`#end` -- edit above this line, do not edit this line
            // Generated on 05/05/2017 at 00:06
            // Component: PowerBusController_v1_0
            module PowerBusController_v1_0 (
                output  drq_in,
                output  drq_out,
                output  shcp,
                output  stcp,
                input   clock,
                input   data_in,
                input   n_reset,
                input   nrq_out,
                input   trigger
            );

               

            //`#start body` -- edit after this line, do not edit this line

               

            localparam STATE_IDLE                           = 3'b000;
            localparam STATE_PERFORM_DMA                    = 3'b001;
            // One vacant state encoding here               = 3'b010;
            localparam STATE_PREPARE_STROBES                = 3'b011;
            localparam STATE_GENERATE_STROBES               = 3'b100;
            localparam STATE_FETCH_INPUT                    = 3'b101;
            localparam STATE_AWAIT_F1_NOT_FULL              = 3'b110;
            localparam STATE_STORE_INPUT                    = 3'b111;

               


            wire ce0;
            wire cl0;
            wire ce1;
            wire cl1;
            wire z0;
            wire z1;
            wire f0_not_empty;
            wire f1_full;

               

            reg [2:0] state;  // The current sequencer state

               

            assign drq_out = (state == STATE_PERFORM_DMA);
            assign shcp = state[2];
            assign stcp = cl1;

               

            wire f1_load_strobe = (state == STATE_STORE_INPUT);

               

            initial begin
                state <= STATE_IDLE;
            end

               

            // ==================== DMA State Machine: ====================

               

            always @ (posedge clock /*iff n_reset*/) begin
                
                if (!n_reset) begin
                
                    // Synchronous reset of the module
                    
                    state <= STATE_IDLE;
                    
                end else begin
                           
                    // Normal operation
                           
                    case(state)
                    
                        STATE_IDLE: begin

               

                            if (f0_not_empty) begin
                                state <= STATE_PERFORM_DMA;
                            end                
                        end

               

                        STATE_PERFORM_DMA: begin
                            
                            // BUG: NRQ is asserted after the entire TRANSACTION, not a single burst!!!
                            // Pretend it worked correctly, to be reworked later. Cypress should really make it configurable.
                            
                            state <= STATE_PREPARE_STROBES;
                        end
                        
                        STATE_PREPARE_STROBES: begin
                        
                            state <= STATE_GENERATE_STROBES;
                        end
                        
                        
                        STATE_GENERATE_STROBES: begin
                            
                            if (ce0) begin
                                state <= STATE_FETCH_INPUT;
                            end

               

                        end
                        
                        STATE_FETCH_INPUT: begin
                        
                            if (!z0) begin
                            
                                state <= STATE_PERFORM_DMA;
                                
                            end else begin

               

                                state <= f1_full ? STATE_AWAIT_F1_NOT_FULL : STATE_STORE_INPUT;
                            end                
                        end
                        
                        STATE_AWAIT_F1_NOT_FULL: begin
                        
                            if (!f1_full) begin
                                state <= STATE_STORE_INPUT;
                            end
                        end
                                    
                        STATE_STORE_INPUT: begin
                        
                            state <= STATE_IDLE;
                        end
                        
                    endcase
                    
                end
                
            end

               

            //        Your code goes here

               

            cy_psoc3_dp8 #(.a0_init_a(0), .a1_init_a(0), .d0_init_a(2),
            .d1_init_a(16),
            .cy_dpconfig_a(
            {
                `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGA, /*CFGRAM0:      STATE_IDLE*/
                `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGA, /*CFGRAM1:      STATE_PERFORM_DMA*/
                `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGA, /*CFGRAM2:      unused*/
                `CS_ALU_OP__SUB, `CS_SRCA_A0, `CS_SRCB_D0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGA, /*CFGRAM3:      STATE_PREPARE_STROBES*/
                `CS_ALU_OP__SUB, `CS_SRCA_A0, `CS_SRCB_D0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGB, /*CFGRAM4:      STATE_GENERATE_STROBES*/
                `CS_ALU_OP__ADD, `CS_SRCA_A1, `CS_SRCB_A1,
                `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC__ALU,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGB, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGB, /*CFGRAM5:      STATE_FETCH_INPUT*/
                `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGB, /*CFGRAM6:      STATE_AWAIT_F1_NOT_FULL*/
                `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0,
                `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE,
                `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA,
                `CS_CMP_SEL_CFGB, /*CFGRAM7:      STATE_STORE_INPUT*/
                8'hFF, 8'h00,  /*CFG9:                        */
                8'hFF, 8'h0F,  /*CFG11-10:                        */
                `SC_CMPB_A0_D1, `SC_CMPA_A0_A0, `SC_CI_B_ROUTE,
                `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_ENBL,
                `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI,
                `SC_SI_A_DEFSI, /*CFG13-12:                        */
                `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
                1'h0, `SC_FIFO1__A1, `SC_FIFO0__A0,
                `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
                `SC_FB_NOCHN, `SC_CMP1_NOCHN,
                `SC_CMP0_NOCHN, /*CFG15-14:                        */
                7'h00, `SC_FIFO0_DYN_ON,2'h00,
                `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX,`SC_FIFO__EDGE,
                `SC_FIFO__SYNC /*CFG17-16:                        */
            ,`SC_EXTCRC_DSBL,`SC_WRK16CAT_DSBL}
            )) strobe_datapath(
                    /*  input                   */  .reset(1'b0),
                    /*  input                   */  .clk(clock),
                    /*  input   [02:00]         */  .cs_addr(state),
                    /*  input                   */  .route_si(1'b0),
                    /*  input                   */  .route_ci(data_in),
                    /*  input                   */  .f0_load(trigger),
                    /*  input                   */  .f1_load(f1_load_strobe),
                    /*  input                   */  .d0_load(1'b0),
                    /*  input                   */  .d1_load(1'b0),
                    /*  output                  */  .ce0(ce0),
                    /*  output                  */  .cl0(cl0),
                    /*  output                  */  .z0(z0),
                    /*  output                  */  .ff0(),
                    /*  output                  */  .ce1(ce1),
                    /*  output                  */  .cl1(cl1),
                    /*  output                  */  .z1(z1),
                    /*  output                  */  .ff1(),
                    /*  output                  */  .ov_msb(),
                    /*  output                  */  .co_msb(),
                    /*  output                  */  .cmsb(),
                    /*  output                  */  .so(),
                    /*  output                  */  .f0_bus_stat(f0_not_empty),
                    /*  output                  */  .f0_blk_stat(),
                    /*  output                  */  .f1_bus_stat(drq_in),
                    /*  output                  */  .f1_blk_stat(f1_full)
            );
            //`#end` -- edit above this line, do not edit this line
            endmodule
            //`#start footer` -- edit after this line, do not edit this line
            //`#end` -- edit above this line, do not edit this line

            • 3. Re: FIFO-based triggering
              bhwj

              I was confused initially as you mentioned  "In the final state D1 is loaded from the FIFO" , Its clear now .as I mentioned this is not illegal and its good that you are making  use  of the unused functionality in Datapaths .This also allows better routing and placement .

                 

              Note that the PLD structure  has 12 inputs which feed across 8 product terms (PT) in the AND array and output of the PTs are inputs into the OR array giving out 4 outputs . So for example if all inputs are used up to generate single output ,reset of the resources cannot be used .

              • 4. Re: FIFO-based triggering
                user_342122993

                Piotr,

                   

                // BUG: NRQ is asserted after the entire TRANSACTION, not a single burst!!!

                   

                // Pretend it worked correctly, to be reworked later. Cypress should really make it configurable.

                   

                - This is not a bug, but a "feature" ( PSoC4 does not have it). Since the amount of data to transfer is only 9 samples per DMA cycle, you can chain 9 TD, so that each TD will add nrq pulse after moving a byte. Demo project attached (not tested, but should work).

                   

                   

                   

                   

                • 5. Re: FIFO-based triggering
                  piotr.wyderski_2406846

                  Odissey1,

                     

                  - This is not a bug, but a "feature". Yes, sometimes it is a feature, but sometimes you need a transfer confirmation after a single burst, not after the entire TD. My use case is "Transfer 9 bytes in a single burst per trigger from consecutive locations of an array of 9*1024 bytes. Let datapath know that all the 9 bytes have been transferred and move the DMA 'cursor' to the next bundle of 9 bytes. Wait for the trigger, repeat. When finished, issue an interrupt". So, I need both NRQ and BRQ (let's call it so, a notification after each burst completion), even configurable behavior of NRQ wouldn't suffice. The 9 TD approach is very interesting, but it doesn't handle the "autoincrement to 1024, then stop" phase safely and this, I dare to say, quite typical use case has no proper hardware support and requires Byzantine constructions like feeding a FIFO from one DMA channel (to handle the "1024" case) and consuming the bytes from the other end by a second DMA channel ("the 9 bytes" case).

                     

                  If there was a single BRQ flag from the same channel...

                     

                  BTW, how do you draw these beautiful waveforms? By hand or is there a dedicated utility in Creator?

                  • 6. Re: FIFO-based triggering
                    user_342122993
                            Piotr, Typically, individual "BRQ" (single element transfer completed) is not required, because one can count trq requests (hoping that each trq will end in DMA completion), instead of BRQ. There are probably several other solutions using chained DMA, indexed DMA, etc. - see Cypress AN Advanced DMA Topics... http://www.cypress.com/documentation/application-notes/an84810-psoc-3-and-psoc-5lp-advanced-dma-topics Take a look on this example, where Datapath directly calculates next array index (not consecutive one) and uses DMA1 to pass this index to working DMA2 (which actually performs data transfer). http://www.cypress.com/blog/psoc-sensei-blog/direct-digital-synthesis-indexed-dma Unfortunately, the above example was written for older PSoC5, and doesn't work on PSoC5LP. My attempt to update DMA code ended in conclusion that there is underlying issue with Datapath operation, which also needs updating. P.S. waveforms are hand-drawn using line tools, pen width 1.5, start/end stroke squared, then grouped together. Dbl-click the line tool to make multiple lines.