FIFO-based triggering

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
PiWy_2406846
Level 3
Level 3

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.

0 Likes
6 Replies
bharadhwajas_91
Employee
Employee
First like received First like given

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. 

0 Likes
lock attach
Attachments are accessible only for community members.
PiWy_2406846
Level 3
Level 3

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

0 Likes
bharadhwajas_91
Employee
Employee
First like received First like given

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 .

0 Likes
lock attach
Attachments are accessible only for community members.
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

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).

   

   

   

   

0 Likes
PiWy_2406846
Level 3
Level 3

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?

0 Likes
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted
        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-topi... 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.   
0 Likes