6 Replies Latest reply on Jun 21, 2019 6:41 AM by NoriakiT_91

    Send a 32bit register value to datapath with DMA

    TaYu_4314136

      My environment is CY8CKIT-059 PSoC 5LP Prototyping Kit and PSoC Creator 4.2 on Windows 10.

       

      I want to send a 32bit value from CPU(C lang) to Datapath.

       

      First of all, I created a sending program(OneDrive) by interrupt and it works(See sreg_out.cysym in an archived file).

       

      And I tryed to make this program correspond to DMA, but it is not successful currently.

       

      dma.png

       

      #include "project.h"
      const uint32_t patterns[] = {
          0b11111111000000001111111100000000,
          0b11110000111100001111000011110000,
          0b11001100110011001100110011001100,
          0b10101010101010101010101010101010,   
          0b11001100110011001100110011001100,
          0b11110000111100001111000011110000,
      };
      uint8_t send_buffer[2][24];
      /* Defines for sreg_dma */
      #define sreg_dma_BYTES_PER_BURST 4
      #define sreg_dma_REQUEST_PER_BURST 1
      #define sreg_dma_SRC_BASE (CYDEV_SRAM_BASE)
      #define sreg_dma_DST_BASE (CYDEV_PERIPH_BASE)
      /* Variable declarations for sreg_dma */
      /* Move these variable declarations to the top of the function */
      uint8 sreg_dma_Chan;
      uint8 sreg_dma_TD[2];
      void InitDma()
      {
          /* DMA Configuration for sreg_dma */
          sreg_dma_Chan = sreg_dma_DmaInitialize(sreg_dma_BYTES_PER_BURST, sreg_dma_REQUEST_PER_BURST, 
              HI16(sreg_dma_SRC_BASE), HI16(sreg_dma_DST_BASE));
          sreg_dma_TD[0] = CyDmaTdAllocate();
          sreg_dma_TD[1] = CyDmaTdAllocate();
          CyDmaTdSetConfiguration(sreg_dma_TD[0], 24, sreg_dma_TD[1], sreg_dma__TD_TERMOUT_EN | CY_DMA_TD_INC_SRC_ADR);
          CyDmaTdSetConfiguration(sreg_dma_TD[1], 24, sreg_dma_TD[0], sreg_dma__TD_TERMOUT_EN | CY_DMA_TD_INC_SRC_ADR);
          CyDmaTdSetAddress(sreg_dma_TD[0], LO16((uint32)send_buffer[0]), LO16((uint32)sreg_out_DMA_PTR));
          CyDmaTdSetAddress(sreg_dma_TD[1], LO16((uint32)send_buffer[1]), LO16((uint32)sreg_out_DMA_PTR));
          CyDmaChSetInitialTd(sreg_dma_Chan, sreg_dma_TD[0]);
          CyDmaChEnable(sreg_dma_Chan, 1);
      }
      CY_ISR(OnInterruptSO)
      {
      }
      int main(void)
      {
          CyGlobalIntEnable;
          
          memcpy(send_buffer[0], patterns, 24);
          memcpy(send_buffer[1], patterns, 24);
          InitDma();
          //so_isr_StartEx(OnInterruptSO);
          for(;;)
          {
          }
      }
      

       

      According to this discussion, PSoC 5LP seems that it supports 32bit DMA transferring. However, I don't make much progress because there is no concrete exsamples(Official documents detailed that 8bit DMA transfer).

       

      Please tell me if you know a good solution.

        • 1. Re: Send a 32bit register value to datapath with DMA
          NoriakiT_91

          In the sreg_out.h file,

           

          #ifndef __`$INSTANCE_NAME`_H__
          #define __`$INSTANCE_NAME`_H__
          
          #define `$INSTANCE_NAME`_DMA_PTR ((reg32*)`$INSTANCE_NAME`_dp_u3__F0_REG)
          #define `$INSTANCE_NAME`_SetValue(v) CY_SET_REG32(`$INSTANCE_NAME`_dp_u0__F0_REG, v)
          
          #endif
          

           

          Why are you using `$INSTANCE_NAME`_dp_u3__F0_REG instead of `$INSTANCE_NAME`_dp_u0__F0_REG ?

           

          If you want to access the F0 register as a 32-bit register, the lower address (u0) should be used.

           

          Regards,

          Noriaki

          • 2. Re: Send a 32bit register value to datapath with DMA
            TaYu_4314136

            Thank you for the reply.

             

            Original code was "u0__F0_REG". But with this code, the signal will stop. Therefore, I specified an incorrect value further.

             

            I fixed this code and update an archive file(It has not worked yet).

            • 3. Re: Send a 32bit register value to datapath with DMA
              NoriakiT_91

              I don't know if UDB can be used for 32-bit DMA transfer because UDBs are connected to the PHUB with 16-bit spoke.

              GS004141.png

              This table is contained in the "PSoC 5LP Architecture TRM, Document No. 001-78426"  If UDB cannot be accessed by a 32-bit DMA, two 16-bit DMAs should be issued and the sreg_out component is triggered by the second access.

               

              I found a strange description in the Verilog file.

               

              }))dp(
                  /*  input              */  .clk(clock),
                  /*  input   [02:00]    */  .cs_addr(pg_state),
                  /*  input              */  .route_si(1'b0),
                  /*  input              */  .route_ci(1'b0),
                  /*  input              */  .f0_load(1'b0),
                  /*  input              */  .f1_load(1'b0),
                  /*  input              */  .d0_load(1'b0),
                  /*  input              */  .d1_load(1'b0),
                  /*  output  [03:00]    */  .f0_bus_stat(f0_not_empty),
                  /*  output  [03:00]    */  .f0_blk_stat(f0_full),
                  /*  output  [03:00]    */  .f1_bus_stat(),
                  /*  output  [03:00]    */  .f1_blk_stat(),
                  /* output [03:00] */            .so(so_32)
              );
              

               

              At the port list of the "dp" instance, the 4-bit bus f0_bus_stat[3:0] is assigned to f0_not_empty but the f0_not_empty is not declared as a bus.  In this case, only the LSB bit f0_bus_stat[0] is assigned to f0_not_empty and is used in the state machine.  If 32-bit access is divided into two 16-bit accesses, f0_bus_stat[3] could be used by the state machine.

               

              Regards,

              Noriaki

              • 4. Re: Send a 32bit register value to datapath with DMA
                NoriakiT_91

                I found a strange point.  All figures come from the "PSoC 5LP Architecture TRM, Document No. 001-78426"

                 

                    `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0,
                    1'h0, `SC_FIFO1_BUS, `SC_FIFO0_BUS,
                    `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN,
                    `SC_FB_NOCHN, `SC_CMP1_NOCHN,
                    `SC_CMP0_NOCHN, /*CFG15-14:   */
                

                 

                You are setting the F0_INSEL to BUS.  This means you are using the FIFO0 in "Input Mode"

                GS004145.png

                GS004146.png

                If the FIFO0 is used as "Input Mode" the status bits f0_bus_stat and f0_blk_stat are used as "Not Full" and "Empty" respectively.

                GS004147.png

                So, if you want to detect that the FIFO0 has at least one data, f0_blk_stat should be used as f0_empty

                 

                Regards,

                Noriaki

                • 5. Re: Send a 32bit register value to datapath with DMA
                  TaYu_4314136

                  I upload a latest version here.

                   

                  According to the data presented by you, PSoC DMA may not support 32bit. If there is no further progress, I'll try to implement this function with 8bit DMA transfer. Thanks.

                  • 6. Re: Send a 32bit register value to datapath with DMA
                    NoriakiT_91

                    Today, I have tried the DMA transfer in 32-bit.  As the conclusion, UDB cannot be used for 32-bit access but 16-bit DMA is available.  So, I recommend to support 16-bit patterns.

                     

                    I have modified your Verilog code as follows.

                     

                    reg [2:0] pg_state;
                    wire [3:0] so_32;
                    reg [4:0] out_count;
                    wire [3:0] f0_empty;
                    wire [3:0] f0_not_full;
                    

                     

                    so_32, f0_empty, and f0_not_full are declared as wire signals because these signals are used as the output of the datapath.

                     

                    always @(posedge clock)
                    begin
                        case(pg_state)
                        PG_IDLE:
                        begin
                            if(f0_empty == 4'b0000)
                            begin
                                pg_state <= PG_COPY_F0;
                            end
                        end
                        PG_COPY_F0:
                        begin
                            out_count <= 5'd0;
                            pg_state <= PG_SHIFTOUT;
                        end
                        PG_SHIFTOUT:
                        begin
                            out_count <= out_count + 5'd1;
                            if(out_count == 5'd31)
                            begin
                                pg_state <= PG_IDLE;
                            end
                        end
                        endcase
                    end
                    

                     

                    In the always clause, non-blocking assignments are used for reg elements.  As the result, the out_count register is compared with 5'd31 instead of 5'd0.

                    In line 06, the state transition condition is modified to (f0_empty == 4'b0000) This means all FIFO has data at least one byte each.

                     

                    assign isr = (f0_not_full == 4'b1111);
                    assign data = so_32[3];
                    

                     

                    The isr signal is made from f0_not_full.  This logic means all FIFO has a room at least one byte.  When f0_empty is used here, the logic means all FIFO has no data.  FIFO cannot be used FIFO.

                     

                    Regards,

                    Noriaki