This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: Ping Pong Mode and transmitting large buffers using DMA with EPI

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL

Hello,

I'm trying to transmit multiple large buffers using uDMA Ping Pong Mode, after transmitting for example buffer 1, 2, I swap buffer 1, with buffer 3. 

My question is where the triple buffering needed to be swapped, in which area exactly in the interrupts ?

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Private Typedefs ----------------------------------------------------------*/
#pragma DATA_ALIGN(psDMAControlTable, 1024)
tDMAControlTable psDMAControlTable[64];
#define EPI_DATA_SIZE 1024
#define SYSTEM_CLOCK_120M 120000000
#define EPI_PORT 0xA0000000
uint8_t testttttttttttttt = 0;
int PingCount;
uint16_t send_data[EPI_DATA_SIZE] = { };
uint16_t send_data2[EPI_DATA_SIZE] = {
};
uint16_t send_data3[EPI_DATA_SIZE] = {
};
uint32_t ui32SysClock, g_ui32EPIErrors = 0;
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Hello Ahmed,

    Within the interrupt is one possibility but it doesn't have to be inside of the interrupt. You can also set up the interrupt to track flags about the buffer state along with an application loop that simply checks for which buffer has been filled or emptied and then swaps them. It depends how quick you need the swaps executed. The interrupt would be the fastest method.

    We have an example of how to use Ping Pong mode for two buffers using the ADC peripheral in TivaWare 2.2.0.

    You can find it at [Install Path]\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\adc_udma_pingpong - This will show you how to check for the buffer being filled in an interrupt. If you decide you want to swap within the interrupt, you just need to take the APIs used to enable the next uDMA block transfer from the application loop and use them in the ISR instead.

    I don't see a reason the same logic can't be extended to three or more buffers so that should give you what you need to get the uDMA working as you intend.

    Best Regards,

    Ralph Jacobi

  • Have you got some time to review the code above please ? especially the EPI Interrupt handler, I think the flags there are incorrect.

  • Hello Ahmed,

    We don't do comprehensive code reviews. We can look at sections that are noted to have issues as well as configurations, but not entire programs.

    Regarding your interrupt code as you marked that as an area for concern, you shouldn't need to clear uDMA interrupts with uDMAIntClear. You'd want to clear the EPI interrupt instead. That should be done at the start of the ISR too.

    As far as flags go I am not sure which ones you mean. I would recommend you review the example I provided and implement improvements and then if you are having specific issues you can show your updated code and explain what isn't working.

    Best Regards,

    Ralph Jacobi

  • Checking the uDMA if it's stop/finished inside the interrupt of EPI is correct or not ? that's my question...
    here is the part that is suspicious to me 

    and what does this flag do? EPI_INT_DMA_TX_DONE

    ui32Mode = uDMAChannelModeGet(UDMA_CH21_EPI0TX | UDMA_PRI_SELECT);

    if(ui32Mode == UDMA_MODE_STOP)
    {

    PingCount++;
    }

    ui32Mode = uDMAChannelModeGet(UDMA_CH21_EPI0TX | UDMA_ALT_SELECT);

    if(ui32Mode == UDMA_MODE_STOP)
    {

    PingCount++;


    }

  • Hello Ahmed,

    You can check if its stopped but the code you have is slightly wrong.

    You are using UDMA_CH21_EPI0TX which is the addressing used for uDMAChannelAssign. However most of your APIs need to provide the channel number you are accessing. In TivaWare this would be UDMA_CHANNEL_TMR1B which is the define for channel 21.

    You can see why this is used by looking at Table 9-1 uDMA Channel Assignments in the datasheet: https://www.ti.com/lit/ds/symlink/tm4c1294ncpdt.pdf#page=680

    The EPI 0 TX channel is shared with GPTimer 1B and since only one peripheral can use a specific channel at a time, the define we provided in TivaWare is for UDMA_CHANNEL_TMR1B.

    So the correct API call would be:

    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_TMR1B | UDMA_PRI_SELECT);

    Looking through your code, the same issue applies to a lot of your uDMA configuration.

    Please take the time to refer to our completed uDMA Ping Pong example to see how to properly configure your uDMA peripheral and how to setup the checks in the ISR. Once you have done so if you are still having issues then you can post your updated configurations and I can see if there are any missing steps.

    Best Regards,

    Ralph Jacobi

  • Oh and regarding EPI_INT_DMA_TX_DONE, that is the interrupt flag in the EPI interrupt flag register which corresponds to the uDMA TX being completed.

    Best Regards,

    Ralph Jacobi


  • Thanks for your patience.
    I have reviewed the code, if you can review it:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    void EPIIntHandler(void)
    {
    uint32_t intStatus;
    uint32_t channelModeTX;
    //
    // Handle any EPI error IRQ signals.
    //
    intStatus = EPIIntErrorStatus(EPI0_BASE);
    if(intStatus)
    {
    g_ui32EPIErrors++;
    }
    EPIIntErrorClear(EPI0_BASE, intStatus);
    intStatus = EPIIntStatus(EPI0_BASE, false);
    if(intStatus)
    {
    g_ui32EPIStatus = intStatus;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • and for DMA Init

    void DMA_Init()
    {
    SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

    uDMAEnable();
    while (!(SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)))
    ;

    uDMAControlBaseSet(psDMAControlTable);

    //uDMAChannelAttributeDisable(UDMA_CH20_EPI0RX, UDMA_ATTR_ALL);
    uDMAChannelAttributeDisable(UDMA_CH21_EPI0TX, UDMA_ATTR_ALL);

    uDMAChannelAttributeEnable(UDMA_CH21_EPI0TX, UDMA_ATTR_USEBURST); //single request is not supported

    //uDMAChannelAssign(UDMA_CH20_EPI0RX);
    uDMAChannelAssign(UDMA_CH21_EPI0TX);

    uDMAChannelControlSet(UDMA_CH21_EPI0TX | UDMA_PRI_SELECT,
    UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_1024); // UDMA_ARB_2
    uDMAChannelControlSet(UDMA_CH21_EPI0TX | UDMA_ALT_SELECT,
    UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_1024); // UDMA_ARB_2


    uDMAChannelSelectSecondary(UDMA_DEF_TMR1B_SEC_EPI0TX);

    }

  • Hello, I have followed the example, Would you tell me where is the point in code that the buffer should be swapped, assuming 3 buffers A,B,C.

  • Hello Ahmed,

    Reviewing your code, you still have some issues with your implementation. Please reference my past comments.

    You are using UDMA_CH21_EPI0TX which is the addressing used for uDMAChannelAssign. However most of your APIs need to provide the channel number you are accessing. In TivaWare this would be UDMA_CHANNEL_TMR1B which is the define for channel 21.

    You can see why this is used by looking at Table 9-1 uDMA Channel Assignments in the datasheet: https://www.ti.com/lit/ds/symlink/tm4c1294ncpdt.pdf#page=680

    The EPI 0 TX channel is shared with GPTimer 1B and since only one peripheral can use a specific channel at a time, the define we provided in TivaWare is for UDMA_CHANNEL_TMR1B.

    So the correct API call would be:

    ui32Mode = uDMAChannelModeGet(UDMA_CHANNEL_TMR1B | UDMA_PRI_SELECT);

    Looking through your code, the same issue applies to a lot of your uDMA configuration.

    UDMA_CH21_EPI0TX should only be used for uDMAChannelAssign.

    You need to use UDMA_CHANNEL_TMR1B for the other APIs such as like this:

    Fullscreen
    1
    uDMAChannelAttributeDisable(UDMA_CHANNEL_TMR1B, UDMA_ATTR_ALL);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Would you tell me where is the point in code that the buffer should be swapped, assuming 3 buffers A,B,C.

    Deciding where to handle the buffer swaps is an application specific decision, I can't really guide you on that?

    Best Regards,

    Ralph Jacobi