Problem SPI with DMA

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

cross mob
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

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

0 Likes
1 Solution
Anonymous
Not applicable

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 ?

View solution in original post

0 Likes
8 Replies
Anonymous
Not applicable

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 ?

0 Likes

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.

0 Likes

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

0 Likes

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

0 Likes
Anonymous
Not applicable

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

0 Likes

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

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

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.

0 Likes

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.

0 Likes