8 Replies Latest reply on Dec 9, 2017 1:07 PM by user_365962704

    Problem SPI with DMA

    user_447190282

      I am sending telegrams of different length (normally 1023 byte of 431 byte) with data.  This works fine with my program for +- 104 DMA->SPI transfers.Afterwards the wrong array is send.  I have isolate the problem and simplified my program back to the minimum for testing.  I send 2 arrays with different length and different data with a pause between them. When i send the 2 arrays the data on the output of the SPI is switching between the 2 arrays as expected. BUT after +-104 DMA->SPI transfers it's going wrong. The data on the output is no longer switching between the 2 arrays but its always array 1 is send.  My program is in attachment. I think there is a problem with a memory leak..?...not handled interrupts..?.. I have tried things like clearing pending interrupts  from SPI,different lengths of arrays,... but i cant find the problem.  I hope someone can help me to find the solution.

      So its good:

      good.png

      Here is the transition to bad:

      transition.png

      Here it is bad:

      bad.png

      Thanks in advance,

      Benny

        • 1. Re: Problem SPI with DMA
          user_447190282

          After a lot of research i found that the problem is caused by the re-initialization of the DMA after every DMA transfer.

          But what is the right procedure for  re-initialization of the DMA channel ?

           

          • 2. Re: Problem SPI with DMA
            user_365962704

            Hi,

             

            I have a project using SPI Master and DMA, can't find it right now nor check your project, i will update this reply later today.

            • 3. Re: Problem SPI with DMA
              hima

              You will need to free the DMA channel and TD before reinitializing the DMA. Else extra TDs will get allocated and TD will run out of count. There are APIs for freeing channel and TDs.

               

              Thanks,

              Hima

              • 4. Re: Problem SPI with DMA
                user_365962704

                So i have this piece of code that reconfigure the DMA and waits for the SPI to finish the data transfer.

                 

                This function sends size bytes of the tx_data, the data received is saved in the rx_data array (i assume the size of the rx_data is equal or bigger than the tx_data size)

                 

                void send_spi_dma(const uint8_t* tx_data, uint8_t* rx_data, const size_t size)
                {    
                    const uint8_t DMA_REQUEST_PER_BURST = 0;
                    const uint8_t DMA_BYTES_PER_BURST = 1;
                    uint8_t DMA_Rx_Chan = 0;
                    uint8_t DMA_Tx_Chan = 0;
                    uint8_t DMA_Rx_TD[1] = {0};
                    uint8_t DMA_Tx_TD[1] = {0};
                    
                    // disable the DMAs before reconfiguring them
                    CyDmaChDisable(DMA_Rx_Chan);
                    CyDmaChDisable(DMA_Tx_Chan);
                
                
                    DMA_Rx_Chan =
                        DMA_Rx_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST,
                                             HI16(CYDEV_PERIPH_BASE), HI16(CYDEV_SRAM_BASE));
                    
                    DMA_Tx_Chan =
                        DMA_Tx_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST,
                                             HI16(CYDEV_SRAM_BASE), HI16(CYDEV_PERIPH_BASE));
                        
                    DMA_Rx_TD[0] = CyDmaTdAllocate();
                    DMA_Tx_TD[0] = CyDmaTdAllocate();
                
                
                    CyDmaTdSetConfiguration(DMA_Rx_TD[0], size, CY_DMA_DISABLE_TD,
                                            CY_DMA_TD_INC_DST_ADR);
                    CyDmaTdSetConfiguration(DMA_Tx_TD[0], size, CY_DMA_DISABLE_TD,
                                            CY_DMA_TD_INC_SRC_ADR);
                    
                    CyDmaTdSetAddress(DMA_Rx_TD[0], LO16((uint32)SPI_RXDATA_PTR),
                                      LO16((uint32)&rx_data));
                    CyDmaTdSetAddress(DMA_Tx_TD[0], LO16((uint32)&tx_data),
                                      LO16((uint32)SPI_TXDATA_PTR));
                    
                    CyDmaChSetInitialTd(DMA_Rx_Chan, DMA_Rx_TD[0]);
                    CyDmaChSetInitialTd(DMA_Tx_Chan, DMA_Tx_TD[0]);
                
                
                    // enable the DMAs
                    CyDmaChEnable(DMA_Rx_Chan, 1);
                    CyDmaChEnable(DMA_Tx_Chan, 1);
                
                
                    // Waiting for the /SS to go high
                    UART_PutString("Waiting for the SPI to be done\r\n");
                    while(0 == (SPI_ReadTxStatus() & SPI_STS_SPI_DONE)) {
                    }
                }
                

                 

                as hima says you need to disable the dma, reconfigure it and then enable it again.

                 

                Pls let me know if the code help you.

                • 5. Re: Problem SPI with DMA
                  user_365962704

                  Hi hima,

                   

                  Thanks for the reply, i tested the function just few times so i guess that's why i never got out of TDs and DMA Channels.

                   

                  Where should i free them? at the end of the function after waiting for the SPI transfer is completed?

                   

                  Regards,

                  Carlos

                  • 6. Re: Problem SPI with DMA
                    user_447190282

                    I have found the solution. After the SPI transaction is done, i disable the DMA and Freeing the DMA channel.

                            

                              while(0 == (SPIM_1_ReadTxStatus() & SPIM_1_STS_SPI_DONE))

                                {

                                }

                                CyDmaChDisable(txChannel);

                                CyDmaTdFree(txChannel);

                     

                    @ user_365962704

                    Thanks for posting your code but just disable the DMA before reinitialization is not enough.

                    You must also freeing the channel.

                    I also see that in the beginning of your function you disable the DMA channel. But the first time you disable a DMA channel that is never Initialized.

                    I do not know if this has consequences for the good completion of your program.

                     

                    @Hima

                    Thanks for you reply.

                    After searching in Google after "5LP freeing dma channel " i found the solution here :

                    cannot run DMA2 after 52 times

                     

                    Thanks to ALL

                     

                    Greetings

                     

                    Benny

                    • 7. Re: Problem SPI with DMA
                      user_365962704

                      Thanks for the update, indeed i will get this function to work properly with your suggestions, i guess i will free the dma channel and the TD, and thanks for the link also.

                       

                      Regards,

                      Carlos

                      • 8. Re: Problem SPI with DMA
                        user_365962704

                        Updated my code and seems to be working propperly.

                         

                        spi_dma_5lp.png

                         

                        project attached in case anyone need transfer and get data at the same time.