Ping Pong DMA

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

cross mob
Anonymous
Not applicable

 Hello All,

   

 I am trying to establish a Ping pong DMA to transfer data alternatively from two buffers. Buffer Size is 1000k(1MB). Can anyone give me any idea to perform this task?

   

Thanks.

1 Solution
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

​AdityaK, Bob is right that the maximum transfer is 4095 bytes from a single TD but you can have multiple TDs to transfer the total length you need.  What is the source of your data buffers -- a filter? ADC?  Is your input array the same size as your output array? I have used pointers in each TD to reference a specific offset into the source or destination buffer. Be sure to reinitialize these pointers for each burst. For example:

   

uint16 *pA[4];  // Array of pointers to segments of data array from Filter A

void set_pointers()  // Sets the pointers to the output arrays
{    
    uint16 j;
    for (j = 0; j < SEGMENTS; j++) // and if SEGMENTS is #defined as 4 ...
    {
        pA = &(Filter_Ch_A[LENGTH*j]); // pointers to the four segments of Filter A data used in DMA TDs
    }
}

   

Then each TD uses one of the pA pointers. See them used in the last four lines in this code:

   

The following might be the reverse direction of what you are doing but it can be modified for your need.

   

/* DMA Configuration for dma_out_A */
    /* Create a TD[5] that ENDs to avoid memory corruptions if the main loop is too slow to stop it */    
    dma_out_A_Chan = dma_out_A_DmaInitialize(dma_out_A_BYTES_PER_BURST, dma_out_A_REQUEST_PER_BURST, 
        HI16(dma_out_A_SRC_BASE), HI16(dma_out_A_DST_BASE));
    dma_out_A_TD[0] = CyDmaTdAllocate();
    dma_out_A_TD[1] = CyDmaTdAllocate();
    dma_out_A_TD[2] = CyDmaTdAllocate();
    dma_out_A_TD[3] = CyDmaTdAllocate();
    dma_out_A_TD[4] = CyDmaTdAllocate();
    CyDmaTdSetConfiguration(dma_out_A_TD[0], 2*LENGTH, dma_out_A_TD[1], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[1], 2*LENGTH, dma_out_A_TD[2], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[2], 2*LENGTH, dma_out_A_TD[3], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[3], 2*LENGTH, dma_out_A_TD[4], dma_out_A__TD_TERMOUT_EN | TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[4], 32, dma_out_A_TD[0], TD_AUTO_EXEC_NEXT);
    CyDmaTdSetAddress(dma_out_A_TD[0], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[0]));
    CyDmaTdSetAddress(dma_out_A_TD[1], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[1]));
    CyDmaTdSetAddress(dma_out_A_TD[2], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[2]));
    CyDmaTdSetAddress(dma_out_A_TD[3], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[3]));
    CyDmaTdSetAddress(dma_out_A_TD[4], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)overflow_A));
    CyDmaChSetInitialTd(dma_out_A_Chan, dma_out_A_TD[0]);
    CyDmaChEnable(dma_out_A_Chan, 1)

View solution in original post

6 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

I think I have red that the maximum amount to transfer with a single TD is limited to 4095 bytes. Have a look into this appnote

   

Deeper information you will find here.

   

 

   

Happy coding

   

Bob

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

Out of curiosity: do you have a secret PSoC device with 1MB RAM? Or do you use external memory?

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Some ref material -

   

 

   

    

   

          

   

http://www.cypress.com/?rID=37793     AN52705     Getting Started with DMA

   

http://www.cypress.com/?rID=82680     AN84810     PSoC® 3 and PSoC 5LP Advanced DMA Topics

   

http://www.cypress.com/?rID=44335     AN61102 PSoC® 3 and PSoC 5LP - ADC Data Buffering Using DMA

   

http://video.cypress.com/video-library/search/dma/     Videos on DMA

   

https://www.youtube.com/results?search_query=dma+psoc Videos on DMA (some overlap)

   

 

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

 Thanks Dana

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

You are always welcome!

   

 

   

Dana.

0 Likes
JeCo_264681
Level 5
Level 5
100 replies posted 50 replies posted 25 replies posted

​AdityaK, Bob is right that the maximum transfer is 4095 bytes from a single TD but you can have multiple TDs to transfer the total length you need.  What is the source of your data buffers -- a filter? ADC?  Is your input array the same size as your output array? I have used pointers in each TD to reference a specific offset into the source or destination buffer. Be sure to reinitialize these pointers for each burst. For example:

   

uint16 *pA[4];  // Array of pointers to segments of data array from Filter A

void set_pointers()  // Sets the pointers to the output arrays
{    
    uint16 j;
    for (j = 0; j < SEGMENTS; j++) // and if SEGMENTS is #defined as 4 ...
    {
        pA = &(Filter_Ch_A[LENGTH*j]); // pointers to the four segments of Filter A data used in DMA TDs
    }
}

   

Then each TD uses one of the pA pointers. See them used in the last four lines in this code:

   

The following might be the reverse direction of what you are doing but it can be modified for your need.

   

/* DMA Configuration for dma_out_A */
    /* Create a TD[5] that ENDs to avoid memory corruptions if the main loop is too slow to stop it */    
    dma_out_A_Chan = dma_out_A_DmaInitialize(dma_out_A_BYTES_PER_BURST, dma_out_A_REQUEST_PER_BURST, 
        HI16(dma_out_A_SRC_BASE), HI16(dma_out_A_DST_BASE));
    dma_out_A_TD[0] = CyDmaTdAllocate();
    dma_out_A_TD[1] = CyDmaTdAllocate();
    dma_out_A_TD[2] = CyDmaTdAllocate();
    dma_out_A_TD[3] = CyDmaTdAllocate();
    dma_out_A_TD[4] = CyDmaTdAllocate();
    CyDmaTdSetConfiguration(dma_out_A_TD[0], 2*LENGTH, dma_out_A_TD[1], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[1], 2*LENGTH, dma_out_A_TD[2], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[2], 2*LENGTH, dma_out_A_TD[3], TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[3], 2*LENGTH, dma_out_A_TD[4], dma_out_A__TD_TERMOUT_EN | TD_INC_DST_ADR | TD_AUTO_EXEC_NEXT);
    CyDmaTdSetConfiguration(dma_out_A_TD[4], 32, dma_out_A_TD[0], TD_AUTO_EXEC_NEXT);
    CyDmaTdSetAddress(dma_out_A_TD[0], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[0]));
    CyDmaTdSetAddress(dma_out_A_TD[1], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[1]));
    CyDmaTdSetAddress(dma_out_A_TD[2], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[2]));
    CyDmaTdSetAddress(dma_out_A_TD[3], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)pA[3]));
    CyDmaTdSetAddress(dma_out_A_TD[4], LO16((uint32)Filter_HOLDA_PTR), LO16((uint32)overflow_A));
    CyDmaChSetInitialTd(dma_out_A_Chan, dma_out_A_TD[0]);
    CyDmaChEnable(dma_out_A_Chan, 1)