Do DMA triggers work on trigger level change or just on trigger level itself?

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

cross mob
user_1669321
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

I'm trying to setup a SPI TX by DMA, but I'm unable to trigger my DMA transaction (see more details here: Unable to properly setup DMA channels for SPI operation ).

I have my SPI TX FIFO level set to 1, which means that it should trigger the DMA as soon as it's empty. However, my DMA never gets triggered. So I'm wondering if the DMA would trigger on a level change (from low to high), or if it's enought that the condition is already true when I enable the DMA channel.

0 Likes
1 Solution
BragadeeshV
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hi user_1669321​,

As long as no of elements in the TX FIFO is less than TX FIFO level, TX FIFO level trigger is asserted. When set to 1, unless there is at least one element in the TX FIFO, the TX FIFO level trigger signal is asserted.

When you want to transfer 512 bytes of data (more than that is allowed by X loop), you can make use of the Y loop , which is nothing but Y no of X loops. In your case, if X loop transfers 256 bytes of data, then Y loop can be set to transfer two X loop (256 x 2 = 512 ) bytes of data.

Therefore you can use the following configuration for the X loop and Y loop.

RX DMA Descriptor:

pastedImage_2.png

TX DMA Descriptor:

pastedImage_1.png

To understand X loop and Y loop better I recommend you to refer to the PSoC 6 Architecture TRM where we have provided a detailed explanation.

pastedImage_3.png

I'm also attaching a code example that send sends and receives 512 bytes of data.

You can modify the X loop and Y loop in run time. Refer to the PDL for more information.

Let us know if it helps.

Regards,

Bragadeesh

Regards,
Bragadeesh

View solution in original post

4 Replies
BragadeeshV
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hi user_1669321​,

As long as no of elements in the TX FIFO is less than TX FIFO level, TX FIFO level trigger is asserted. When set to 1, unless there is at least one element in the TX FIFO, the TX FIFO level trigger signal is asserted.

When you want to transfer 512 bytes of data (more than that is allowed by X loop), you can make use of the Y loop , which is nothing but Y no of X loops. In your case, if X loop transfers 256 bytes of data, then Y loop can be set to transfer two X loop (256 x 2 = 512 ) bytes of data.

Therefore you can use the following configuration for the X loop and Y loop.

RX DMA Descriptor:

pastedImage_2.png

TX DMA Descriptor:

pastedImage_1.png

To understand X loop and Y loop better I recommend you to refer to the PSoC 6 Architecture TRM where we have provided a detailed explanation.

pastedImage_3.png

I'm also attaching a code example that send sends and receives 512 bytes of data.

You can modify the X loop and Y loop in run time. Refer to the PDL for more information.

Let us know if it helps.

Regards,

Bragadeesh

Regards,
Bragadeesh

Hi Bragadeesh,

Thanks for the answer. The code you linked is the code example I based my code on (see my other thread: Unable to properly setup DMA channels for SPI operation ).

I didn't use the Y loop, as this doesn't allow me to send, for example, 260 bytes. To achieve this, I implemented a scheme of 2 descriptors that I adjust depending on the number of bytes to be sent/read. So for 260 bytes, the first descriptor would be 256 bytes, which then chains to the second descriptor, which has been set to 4 bytes. I then want the interrupt to trigger at the end of the descriptor chain.

My RX DMA channel works if I manually send SPI bytes by using SPI_WriteArray, but it doesn't work if I use my TX DMA channel.

I guess one difference between the example and my code is that the DMA components' "Trigger deactivation and retriggering" are set to "Retrigger immediately" instead of "Retrigger after 4 Clk_Slow cycles". I tried changing that, but my TX still doesn't get triggered.

I actually probed the SPI lines and the CS never gets asserted.

0 Likes

Hi user_1669321​,

It is recommended to set Trigger deactivation and re triggering to Retrigger after 16 Clk_Slow cycles when using SCB peripheral.

I've modified by code to use two descriptors and to dynamically modify the no of data bytes to transfer.

NOTE: The variable names might be different, but the logic is the same.

BYTE_COUNT is 256 here.

void _SpiDma_ConfigRxTransaction(uint16 len)

{

    if(len <= BYTE_COUNT )

    {

        /*Set up RX Descriptor 1*/

        Cy_DMA_Descriptor_SetXloopSrcIncrement(&rxDma_Descriptor_1, 0);

        Cy_DMA_Descriptor_SetXloopDstIncrement(&rxDma_Descriptor_1, 1UL);

        Cy_DMA_Descriptor_SetXloopDataCount(&rxDma_Descriptor_1, len);

        Cy_DMA_Descriptor_SetNextDescriptor(&rxDma_Descriptor_1, NULL);

   

        /*Set up TX Descriptor 1*/

        Cy_DMA_Descriptor_SetXloopSrcIncrement(&txDma_Descriptor_1,1UL);

        Cy_DMA_Descriptor_SetXloopDstIncrement(&txDma_Descriptor_1, 0);

        Cy_DMA_Descriptor_SetXloopDataCount(&txDma_Descriptor_1, len);

        Cy_DMA_Descriptor_SetNextDescriptor(&txDma_Descriptor_1, NULL);

   

        /*Set up SRC and DEST addr for TX DMA*/

        Cy_DMA_Descriptor_SetSrcAddress(&txDma_Descriptor_1, (uint8_t *)txBuffer);

        Cy_DMA_Descriptor_SetDstAddress(&txDma_Descriptor_1, (void *)&mSPI_HW->TX_FIFO_WR);

   

        /*Set up SRC and DEST addr for RX DMA*/

        Cy_DMA_Descriptor_SetSrcAddress(&rxDma_Descriptor_1, (void *)&mSPI_HW->RX_FIFO_RD);

        Cy_DMA_Descriptor_SetDstAddress(&rxDma_Descriptor_1, (uint8_t *)rxBuffer);

   

        /*Set Descriptor for Channel -> Important step*/

        Cy_DMA_Channel_SetDescriptor(rxDma_HW, rxDma_DW_CHANNEL,&rxDma_Descriptor_1);

        Cy_DMA_Channel_SetDescriptor(rxDma_HW, txDma_DW_CHANNEL,&txDma_Descriptor_1);

   

        /*Enable DMA_channels*/

        Cy_DMA_Channel_Enable(rxDma_HW, rxDma_DW_CHANNEL);

        Cy_DMA_Channel_Enable(txDma_HW, txDma_DW_CHANNEL);

    }

    else

    {

        /*Set up RX Descriptor 1*/

        Cy_DMA_Descriptor_SetXloopSrcIncrement(&rxDma_Descriptor_1, 0);

        Cy_DMA_Descriptor_SetXloopDstIncrement(&rxDma_Descriptor_1, 1UL);

        Cy_DMA_Descriptor_SetXloopDataCount(&rxDma_Descriptor_1, BYTE_COUNT );

        Cy_DMA_Descriptor_SetNextDescriptor(&rxDma_Descriptor_1, &rxDma_Descriptor_2);

   

        /*Set up RX Descriptor 2*/

        Cy_DMA_Descriptor_SetXloopSrcIncrement(&rxDma_Descriptor_2, 0);

        Cy_DMA_Descriptor_SetXloopDstIncrement(&rxDma_Descriptor_2, 1UL);

        Cy_DMA_Descriptor_SetXloopDataCount(&rxDma_Descriptor_2, (len - BYTE_COUNT));

        Cy_DMA_Descriptor_SetNextDescriptor(&rxDma_Descriptor_2, NULL);

   

        /*Set up TX Descriptor 1*/

        Cy_DMA_Descriptor_SetXloopSrcIncrement(&txDma_Descriptor_1,1UL);

        Cy_DMA_Descriptor_SetXloopDstIncrement(&txDma_Descriptor_1, 0);

        Cy_DMA_Descriptor_SetXloopDataCount(&txDma_Descriptor_1, BYTE_COUNT);

        Cy_DMA_Descriptor_SetNextDescriptor(&txDma_Descriptor_1, &txDma_Descriptor_2);

   

        /*Set up TX Descriptor 2*/

        Cy_DMA_Descriptor_SetXloopSrcIncrement(&txDma_Descriptor_2,1UL);

        Cy_DMA_Descriptor_SetXloopDstIncrement(&txDma_Descriptor_2, 0);

        Cy_DMA_Descriptor_SetXloopDataCount(&txDma_Descriptor_2, (len - BYTE_COUNT));

        Cy_DMA_Descriptor_SetNextDescriptor(&txDma_Descriptor_2, NULL);

   

        /*Set up SRC and DEST addr for TX DMA DESC 2*/

        Cy_DMA_Descriptor_SetSrcAddress(&txDma_Descriptor_2, (uint8_t *)&txBuffer[BYTE_COUNT]);

        Cy_DMA_Descriptor_SetDstAddress(&txDma_Descriptor_2, (void *)&mSPI_HW->TX_FIFO_WR);

   

        /*Set up SRC and DEST addr for RX DMA DESC 2*/

        Cy_DMA_Descriptor_SetSrcAddress(&rxDma_Descriptor_2, (void *)&mSPI_HW->RX_FIFO_RD);

        Cy_DMA_Descriptor_SetDstAddress(&rxDma_Descriptor_2, (uint8_t *)&rxBuffer[BYTE_COUNT]);

   

        /*Set Descriptor for Channel -> Important step*/

        Cy_DMA_Channel_SetDescriptor(rxDma_HW, rxDma_DW_CHANNEL,&rxDma_Descriptor_1);

        Cy_DMA_Channel_SetDescriptor(txDma_HW, txDma_DW_CHANNEL,&txDma_Descriptor_1);

   

        /*Enable DMA_channels*/

        Cy_DMA_Channel_Enable(rxDma_HW, rxDma_DW_CHANNEL);

        Cy_DMA_Channel_Enable(txDma_HW, txDma_DW_CHANNEL);

    }

}

Please refer to the attached project for TX and RX DMA initial configurator settings. The attached project works at my end. Please confirm.

EDITS: Trigger deactivation and re triggering was incorrectly said as 4 clk_slow cycles, but it s recommended to set the Trigger deactivation and re triggering settings to Retrigger after 16 Clk_Slow cycles when using SCB peripheral.

,

Regards,

Bragadeesh

Regards,
Bragadeesh

Thanks for helping me understand the DMA channels better.

I managed to simplify my descriptors to fully use the FIFOs of the SPI channel.

On the other hand, my error for the TX DMA was stupid: I forgot an ampersand.

SPI_TX_DMA_Start((const void *) &_spiReadToken, (const void *) SPI_HW->TX_FIFO_WR);

instead of

SPI_TX_DMA_Start((const void *) &_spiReadToken, (const void *) &SPI_HW->TX_FIFO_WR);