Reset DMA TD state

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

cross mob
Sanyika
Level 2
Level 2
10 sign-ins 5 replies posted 5 questions asked

Hello,

I use a DMA to transfer SPI to SRAM,

SPI data are of different longs, I want to reset the TD status of DMA. I setup it to increment the dest adress, but I want to reset it manually.

To understand how DMA works I created a quick project with just SPi and 2 DMA components.

Currently this code increments rxBuffer each time it get data

I create an array variable (30 items) to see how it's works.

I think it's not the good way to re-execute DMA channel.

So how to reset TD status (or other tricks) to have just data on the 8 first bytes of the buffer array ?

Thank you for your help

#include <project.h>

void DmaTxConfiguration(void);

void DmaRxConfiguration(void);

/* DMA Configuration for DMA_TX */

#define DMA_TX_BYTES_PER_BURST      (1u)

#define DMA_TX_REQUEST_PER_BURST    (1u)

#define DMA_TX_SRC_BASE             (CYDEV_SRAM_BASE)

#define DMA_TX_DST_BASE             (CYDEV_PERIPH_BASE)

/* DMA Configuration for DMA_RX */

#define DMA_RX_BYTES_PER_BURST      (1u)

#define DMA_RX_REQUEST_PER_BURST    (1u)

#define DMA_RX_SRC_BASE             (CYDEV_PERIPH_BASE)

#define DMA_RX_DST_BASE             (CYDEV_SRAM_BASE)

#define BUFFER_SIZE                 (8u)

#define STORE_TD_CFG_ONCMPLT        (1u)

/* Variable declarations for DMA_TX*/

uint8 txChannel;

uint8 txTD;

/* Variable declarations for DMA_RX */

uint8 rxChannel;

uint8 rxTD;

/* Data buffers */

uint8 txBuffer [BUFFER_SIZE] = {0x0u, 0x01u, 0x02u, 0x03u, 0x04u, 0x05u, 0x06u, 0x07u};

uint8 txSample [BUFFER_SIZE] = {0x10u, 0x11u, 0x12u, 0x13u, 0x04u, 0x15u, 0x06u, 0x07u};

uint8 rxBuffer[30];

int main()

{

    uint8 i;

   

   

    DmaTxConfiguration();

    DmaRxConfiguration();

   

    SPIM_Start();

   

    CyDmaChEnable(rxChannel, STORE_TD_CFG_ONCMPLT);

    CyDmaChEnable(txChannel, STORE_TD_CFG_ONCMPLT);

   

   

    CyGlobalIntEnable;

    for(;;)

    {

        CyDelay(1);

        //SPIM_ClearRxBuffer();

        txSample[6]=i;

        memcpy(txBuffer,txSample,8);

       

    CyDmaChEnable(rxChannel, STORE_TD_CFG_ONCMPLT);

    CyDmaChEnable(txChannel, STORE_TD_CFG_ONCMPLT);

        i++;

       

    }

}

   

/*******************************************************************************

* Function Name: DmaTxConfiguration

********************************************************************************

* Summary:

*  Configures the DMA transfer for TX direction

*  

* Parameters:

*  None.

*

* Return:

*  None.

*

*******************************************************************************/

void DmaTxConfiguration()

{

    /* Init DMA, 1 byte bursts, each burst requires a request */

    txChannel = DMA_TX_DmaInitialize(DMA_TX_BYTES_PER_BURST, DMA_TX_REQUEST_PER_BURST,

                                        HI16(DMA_TX_SRC_BASE), HI16(DMA_TX_DST_BASE));

    txTD = CyDmaTdAllocate();

    /* Configure this Td as follows:

    *  - Increment the source address, but not the destination address  

    */

    CyDmaTdSetConfiguration(txTD, 8, CY_DMA_DISABLE_TD, TD_INC_SRC_ADR);

    /* From the memory to the SPIM */

    CyDmaTdSetAddress(txTD, LO16((uint32)txBuffer), LO16((uint32) SPIM_TXDATA_PTR));

   

    /* Associate the TD with the channel */

    CyDmaChSetInitialTd(txChannel, txTD);

}   

/*******************************************************************************

* Function Name: DmaRxConfiguration

********************************************************************************

* Summary:

*  Configures the DMA transfer for RX direction

*  

* Parameters:

*  None.

*

* Return:

*  None.

*

*******************************************************************************/

void DmaRxConfiguration()

{

    /* Init DMA, 1 byte bursts, each burst requires a request */

    rxChannel = DMA_RX_DmaInitialize(DMA_RX_BYTES_PER_BURST, DMA_RX_REQUEST_PER_BURST,

                                     HI16(DMA_RX_SRC_BASE), HI16(DMA_RX_DST_BASE));

    rxTD = CyDmaTdAllocate();

   

    /* Configure this Td as follows:

    *  - Increment the destination address, but not the source address

    */

    CyDmaTdSetConfiguration(rxTD, 30, CY_DMA_DISABLE_TD, TD_INC_DST_ADR);

    /* From the SPIM to the memory */

    CyDmaTdSetAddress(rxTD, LO16((uint32)SPIM_RXDATA_PTR), LO16((uint32)rxBuffer));

    /* Associate the TD with the channel */

    CyDmaChSetInitialTd(rxChannel, rxTD);

}

  

/* [] END OF FILE */

0 Likes
1 Solution
himam_31
Employee
Employee
50 likes received 25 likes received 10 likes received

Hello,

Basically you can try nested DMA approach. You can have a DMA channel modify the DMA configuration registers of the other DMA channel.

If your DMA channel number is x and preserve TD is enabled then PHUB_TDMEMx_ORIG_TD0. So the PHUB_TDMEM register with the channel number will hold the data temporarily when the TD is being executed. The working register will be that TDMEM register.

When preserve TD is enabled DMAC will use separate working register CHn_SEP_TD0/1 to preserve the original TD chain.CHn_SEP_TD0/1 is stored in TDMEM. In other words the slot in TDMEM that equals the channel number becomes reserved for DMAC's private use. Instead of processing the original TDs in place, DMAC will copy the original TDs to this separate working area and process them there.

For example if the channel number for the DMA channel is zero, and preserve TD is enabled then the working set of registers will be, PHUB_TDMEM0_ORIG_TD0. The xfrcnt of this register will hold the intermediate value.So if you read this value( xfrcnt -> [0:12]) , you will get the intermediate count.

You can use this register and modify the DMA source and destination address runtime too.

Thanks,

Hima

View solution in original post

4 Replies
himam_31
Employee
Employee
50 likes received 25 likes received 10 likes received

Hello,

Can you please elaborate the requirement? In the following code snippet you are configuring the DMA channel for transferring 30 bytes. Do you want the array to get reset back to index zero when 8 bytes are transferred?

CyDmaTdSetConfiguration(rxTD, 30, CY_DMA_DISABLE_TD, TD_INC_DST_ADR);

Thanks,

Hima

0 Likes

Hello Hima

Yes right, I want to reset-it when I received my data, it's not always 8 bytes, it can be more than less, it's while I can not use 8 byte.

This code it's just to understand how to use DMA. I know data while always be 8 bytes, but if I can reset the array index with this code, I can use it to get different length of data.

Thanks

0 Likes
himam_31
Employee
Employee
50 likes received 25 likes received 10 likes received

Hello,

Basically you can try nested DMA approach. You can have a DMA channel modify the DMA configuration registers of the other DMA channel.

If your DMA channel number is x and preserve TD is enabled then PHUB_TDMEMx_ORIG_TD0. So the PHUB_TDMEM register with the channel number will hold the data temporarily when the TD is being executed. The working register will be that TDMEM register.

When preserve TD is enabled DMAC will use separate working register CHn_SEP_TD0/1 to preserve the original TD chain.CHn_SEP_TD0/1 is stored in TDMEM. In other words the slot in TDMEM that equals the channel number becomes reserved for DMAC's private use. Instead of processing the original TDs in place, DMAC will copy the original TDs to this separate working area and process them there.

For example if the channel number for the DMA channel is zero, and preserve TD is enabled then the working set of registers will be, PHUB_TDMEM0_ORIG_TD0. The xfrcnt of this register will hold the intermediate value.So if you read this value( xfrcnt -> [0:12]) , you will get the intermediate count.

You can use this register and modify the DMA source and destination address runtime too.

Thanks,

Hima

Thank you very much for your answer

0 Likes