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.

TM4C129X uDMA for EPI

Hi,

We are trying to use uDMA for data received from a CPLD using EPI. We are able to use EPIrea FIFO directly. However, all our efforts to use uDMA for receiving data from the EPI has failed. We have done the following:

MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

MAP_SysCtlDelay(10);

uDMAEnable(); //Enable the uDMA

uDMAControlBaseSet(&g_dmaCtrl[0]); //Set the uDMA control structure
MAP_uDMAChannelAttributeDisable(DMA_CH_USED,
// UDMA_ATTR_USEBURST |
UDMA_ATTR_ALTSELECT |
// UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK
);


MAP_uDMAChannelAttributeEnable( DMA_CH_USED, // Set the attributes for the uDMA software channel.
UDMA_ATTR_USEBURST |
// UDMA_ATTR_ALTSELECT |
UDMA_ATTR_HIGH_PRIORITY
// | UDMA_ATTR_REQMASK
);
uDMAIntRegister(UDMA_INT_ERR, dmaErrorInterrupt);

The above is initialized after the EPI which has the following:

#define EPI_CFG_FLAGS (EPI_GPMODE_CLKPIN /*| EPI_GPMODE_RDYEN */| EPI_GPMODE_DSIZE_16 | EPI_GPMODE_ASIZE_NONE /*| EPI_GPMODE_READ2CYCLE*/) // all reads are 2 cc in tm4c129x
MAP_EPIModeSet(EPI0_BASE, EPI_MODE_GENERAL);
MAP_EPIConfigGPModeSet(EPI0_BASE, EPI_CFG_FLAGS, 0, 0);

//Set the EPI for non blocking reads
#define EPI_ADR_MAP_FLAGS (EPI_ADDR_PER_BASE_NONE | EPI_ADDR_RAM_SIZE_64KB | EPI_ADDR_RAM_BASE_NONE)
MAP_EPIAddressMapSet(EPI0_BASE, EPI_ADR_MAP_FLAGS);

MAP_EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_16, 0);
MAP_EPINonBlockingReadConfigure(EPI0_BASE, 1, EPI_NBCONFIG_SIZE_16, 0);
MAP_EPIFIFOConfig(EPI0_BASE, EPI_FIFO_CONFIG_RX_1_2);
//Stop any read that is started by default
MAP_EPINonBlockingReadStop(EPI0_BASE, 0);
MAP_EPINonBlockingReadStop(EPI0_BASE, 1);
//Disable all the EPI interrupts

MAP_EPIIntDisable(EPI0_BASE, EPI_INT_TXREQ | EPI_INT_ERR |EPI_INT_RXREQ);
//EPIIntEnable(EPI0_BASE, EPI_INT_RXREQ | EPI_INT_DMA_RX_DONE);
EPIIntRegister(EPI0_BASE, dmaTransferInterrupt);


The clock rate is set to 30 MHz and we run at 120 MHz. We have done the design successfuly on lm3s9d96 and ported most of the code as they are almost the same. The question is are there any extra configurations that we need to set for uDMA to be able to use with EPI.

Any types of help is welcome and appreciated.

Thanks 

  • Hi Mil,

    There are two modes for interaction between uDMA and EPI. In one mode the EPI can assert DMARequest and in the other the uDMA is to be uses as a software channel. I believe that the code above is for the SW channel?

    In that case besides the uDMA programming done above you need to

    Configure the control parameters using

    uDMAChannelControlSet

    Set up the transfer parameters using

    uDMAChannelTransferSet

    and then enable the UDMA Channel using

    uDMAChannelEnable

    On Completion of the UDMA Transaction you would get the EPIDMADONE interrupt as the EPI is the path for the DMA Transfer

    Regards

    Amit

  • Thanks for the reply. I believe we are interested in the other mode as we get the data on the EPI and we want to use the ping pong method to get an interrupt when one buffer is full so we can read from the other buffer. we have set all the settings that u mentioned but no success yet.

    We suspect that the channel control table is not initialized properly as reading the ctlbase and altbase addresses and reading the address of the control table doesnt show any chanegs! (one shows 0 and the other FF). 

    To start a read we stop nonblockreading on the two EPI channels and disable the uDMA and then configure the dma for mode, source address, channel setting and transfer, etc. and then  start the nonblock reading. 

    Supposedly, since, the interrupt should be triggered when one buffer is fully transmitted but there are no interrupts coming at all. which may mean the uDMA is not confiured. Am I missing something?

  • Hi Mil,

    Do you mean Software method by CPU and not EPI UDMA request?

    The Control Word for the channel for Primary and Alternate are at the following address

    Control Word Primary = Control Table Address + (Channel Number*0x10)+0x8

    Control Word Alternate = Control Table Address + 0x400 + (Channel Number*0x10)+0x8

    Can you also tell me which UDMA Channel is being used?

    Regards

    Amit

  • yes, the EPI uDMA is being used.  and the channel number is set to 20 which is UDMA_SEC_CHANNEL_EPI0RX. 

  • Hi Mil,

    In that case the DMA Done Interrupt shall be triggered by the EPI. Hence in the EPI Peripheral you have to check if the EPIIM is set for the DMARXDONE.

    Also did you check the Control Table Address offset for the Control word in primary and alternate structure for the corresponding channel?

    Regards

    Amit

  • I dun have access to the board yet but we have done the follwoing to initialzie the table:

    static tDMAControlTable g_dmaCtrl[1024] __attribute__ ((aligned(1024)));

    uDMAControlBaseSet(&g_dmaCtrl[0]);

    I have also noticed this in some examples does it matter if I use i or not?

    uDMAChannelAssign(UDMA_CH20_EPI0RX);

    I have used this also:

     uDMAChannelSelectSecondary(UDMA_DEF_TMR1A_SEC_EPI0RX);

     uDMAChannelEnable(UDMA_CH20_EPI0RX); and this   uDMAChannelDisable(UDMA_CH20_EPI0RX);

    This is my interrupt handler for EPI:

    void dmaTransferInterrupt(void) {

    unsigned long status;


    /*
    EPINonBlockingReadGet8(EPI0_BASE,4,&g_acqCtrl.pdata0[sampleCount]);
    sampleCount+=4;
    */

    status = MAP_EPIIntStatus(EPI0_BASE, true); // Get the interrupt status
    MAP_EPIIntErrorClear(EPI0_BASE, status); // Clear pending errors

    //#if 1


    if (0 == g_acqCtrl.flags) { //Check stop condition

    EPINonBlockingReadStop(EPI0_BASE, 0); // Stop any read that is started
    EPINonBlockingReadStop(EPI0_BASE, 1);
    uDMAChannelDisable(DMA_CH_USED); //Disable the DMA channel

    }else {

    if (NULL != g_acqCtrl.pfnApp) g_acqCtrl.pfnApp(); // increment a counter of how many buffers we have swapped

    if (0 == g_acqCtrl.epiChannel) { // Channel 0

    EPINonBlockingReadStop(EPI0_BASE, 0);

    if (0 != g_acqCtrl.flags) {

    MAP_uDMAChannelControlSet(DMA_CH_USED | UDMA_PRI_SELECT,
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE |
    UDMA_DST_INC_16 | UDMA_ARB_4); // UDMA_ARB_8);

    MAP_uDMAChannelTransferSet(DMA_CH_USED | UDMA_PRI_SELECT,
    DMA_TRANSFER_MODE,
    (void *)(EPI0_BASE + EPI_O_READFIFO0),
    (void *)(g_acqCtrl.pdata0), // + g_acqCtrl.size),
    g_acqCtrl.size);

    g_acqCtrl.buffIn = DMA_BUFF_0; // flag for the the buffer to be written to USB
    g_acqCtrl.epiChannel = 1;
    MAP_EPINonBlockingReadStart(EPI0_BASE, 0, g_acqCtrl.size); //transfer size of 752

    }
    }
    else { // Channel 1

    EPINonBlockingReadStop(EPI0_BASE, 1);
    if (0 != g_acqCtrl.flags) {

    MAP_uDMAChannelControlSet(DMA_CH_USED | UDMA_ALT_SELECT, // Set up the alternate control buffer
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE |
    UDMA_DST_INC_16 | UDMA_ARB_4);

    MAP_uDMAChannelTransferSet(DMA_CH_USED | UDMA_ALT_SELECT,
    DMA_TRANSFER_MODE,
    (void *)(EPI0_BASE + EPI_O_READFIFO0),
    (void *)(g_acqCtrl.pdata1), // + g_acqCtrl.size),
    g_acqCtrl.size);

    g_acqCtrl.buffIn = DMA_BUFF_1;
    g_acqCtrl.epiChannel = 0;
    MAP_EPINonBlockingReadStart(EPI0_BASE, 1, g_acqCtrl.size);
    }

    if (0 != g_acqCtrl.flags) {
    uDMAChannelSelectSecondary(UDMA_DEF_TMR1A_SEC_EPI0RX); //Select secondary peripheral for the uDMA channel and enable the channel
    MAP_uDMAChannelEnable(DMA_CH_USED);
    }

    }
    }

    //#endif
    }

  • Hi Mil,

    You have to check the following things

    1. Control word in the Primary and Alternate Channel are correctly set

    2. When you expect the transfer to have completed what is the EPIRIS content

    Meanwhile I will try to work a simple example of Ping Pong with EPI (I do not have the GP example so will try to use some other mode to get it to work)

    Regards

    Amit

  • Hello Amit,

    I am working on the same project with Mil. We managed to get the uDMA to work. The main problem was
    static tDMAControlTable g_dmaCtrl[1024] __attribute__ ((aligned(1024)));

    It started working once we changed to:

    #pragma DATA_ALIGN(g_dmaCtrl, 1024)
    tDMAControlTable g_dmaCtrl[1024];

    The DMA started working and reading values from the EPI fifo. However, it seems to be very slow. We are trying to transfer data from a CPLD.

    Our setup right now is as follows: The uC enables the CPLD. After a 1ms delay the CPLD will assert a pin (which generates an interrupt on the uC) to announce that it is ready to send out data. In the same time it starts incrementing an 8bit counter form 0-FF and outputs it on the EPI data lines. Once the counter reaches FF it is not incremented further, so the output on the EPI data lines will be FF. The problem we are facing right now is that the counter reaches FF before any values are read by the uDMA.

    The uC is running at 120MHz, the EPI is running at 30MHz and the CPLD is running at 15MHz (it divides the EPI clock by 2). When we got the EPI working (without the uDMA) we were reading values (manually) with a 0x13 delay (i.e. the first value we were reading was 0x13).

    Here is our updated initialization code for the EPI/ uDMA:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    // Enable the uDMA controller.
    //
    uDMAEnable();
    //
    // Point at the control table to use for channel control structures.
    //
    uDMAControlBaseSet(g_dmaCtrl);
    MAP_SysCtlDelay(10);
    //////////////////////
    if (false == MAP_SysCtlPeripheralPresent(SYSCTL_PERIPH_EPI0)) {
    return (-1);
    }

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPI0);

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH); //Enable the GPIO peripherals
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

    //Set the GPIO control for the pins associated with the EPI
    MAP_GPIOPinConfigure(GPIO_PH0_EPI0S0); //D0
    MAP_GPIOPinConfigure(GPIO_PH1_EPI0S1);
    MAP_GPIOPinConfigure(GPIO_PH2_EPI0S2);
    MAP_GPIOPinConfigure(GPIO_PH3_EPI0S3);
    MAP_GPIOPinConfigure(GPIO_PC7_EPI0S4);
    MAP_GPIOPinConfigure(GPIO_PC6_EPI0S5);
    MAP_GPIOPinConfigure(GPIO_PC5_EPI0S6);
    MAP_GPIOPinConfigure(GPIO_PC4_EPI0S7);

    MAP_GPIOPinConfigure(GPIO_PN2_EPI0S29); //RD
    MAP_GPIOPinConfigure(GPIO_PK5_EPI0S31); //CLK


    //Set the GPIO ports for the EPI and Open drain
    MAP_GPIOPadConfigSet(GPIO_PORTH_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 , GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);
    MAP_GPIOPadConfigSet(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_OD);

    GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );
    GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);

    GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_5); // clk
    GPIOPinTypeEPI(GPIO_PORTN_BASE, GPIO_PIN_2); //fix this: only the RD signal
    EPIDividerSet(EPI0_BASE, 2); // setting the EPI clock to 16MHz : EPIClk = (Divider == 0) ? SysClk : (SysClk / (((Divider / 2) + 1) 2))

    #define EPI_CFG_FLAGS (EPI_GPMODE_CLKPIN | EPI_GPMODE_DSIZE_8 | EPI_GPMODE_ASIZE_NONE /*| EPI_GPMODE_READ2CYCLE*/) // all reads are 2 cc in tm4c129x
    MAP_EPIModeSet(EPI0_BASE, EPI_MODE_GENERAL);
    MAP_EPIConfigGPModeSet(EPI0_BASE, EPI_CFG_FLAGS, 0, 0);

    //Set the EPI for non blocking reads
    #define EPI_ADR_MAP_FLAGS (EPI_ADDR_PER_BASE_NONE | EPI_ADDR_RAM_SIZE_64KB | EPI_ADDR_RAM_BASE_NONE)
    MAP_EPIAddressMapSet(EPI0_BASE, EPI_ADR_MAP_FLAGS);

    MAP_EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_8, 0);
    MAP_EPIFIFOConfig(EPI0_BASE, EPI_FIFO_CONFIG_RX_1_2);
    //Stop any read that is started by default
    MAP_EPINonBlockingReadStop(EPI0_BASE, 0);
    // MAP_EPINonBlockingReadStop(EPI0_BASE, 1);
    //Disable all the EPI interrupts

    MAP_EPIIntDisable(EPI0_BASE, EPI_INT_TXREQ | EPI_INT_ERR |EPI_INT_RXREQ);

    ////////////////////////////////////////////////////////////////////////
    uDMAChannelAssign(UDMA_CH20_EPI0RX);
    uDMAChannelAttributeDisable(DMA_CH_USED,
    UDMA_ATTR_USEBURST |
    UDMA_ATTR_ALTSELECT |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK
    );
    uDMAChannelControlSet(DMA_CH_USED | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
    UDMA_ARB_4);

    //

    uDMAChannelTransferSet(DMA_CH_USED | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC,
    (void *)(EPI0_BASE + EPI_O_READFIFO0),
    (void *)(g_acqCtrl.pdata0), g_acqCtrl.size);

    uDMAChannelAttributeEnable(DMA_CH_USED,
       UDMA_ATTR_USEBURST |
       UDMA_ATTR_HIGH_PRIORITY
      );


    uDMAChannelEnable(DMA_CH_USED);
    EPIIntRegister(EPI0_BASE, dmaTransferInterrupt);
     EPIIntEnable(EPI0_BASE, EPI_INT_DMA_RX_DONE);
    uDMAIntRegister(UDMA_INT_ERR, dmaErrorInterrupt);


    Any suggestions?

    Cheers!

    Rares

  • Hi Rares,

    That is good work. I have some confusion regarding the post

    1. When reading the data manually you have a SysCtlDelay(0x13) between reading the data from the EPI. Is that correct?

    2. When the GPIO Interrupt is asserted, do you start the configuration of the UDMA or is the UDMA already configured and the action from the CPU in response to the GPIO Interrupt is to enable the UDMA Channel (uDMAChannelEnable API call)? If the answer to this question is the full configuration, then I would suggest a code change to keep the uDMA channel initialized in terms of Transfer Buffer, Attributes, etc and only set the uDMAChannelEnable when the GPIO Interrupt comes.

    Regards

    Amit

  • Hi Amit,

    Thanks for the reply.

    1) We do not use a  SysCtlDelay(0x13) delay. The first value which we read from the EPI is 0x13. We tried it multiple times and the first value we read is always 0x13. Which basically means that from the moment the CPLD asserts the interrupt pin until we read the first value from the EPI 0x13 15MHz clocks have passed.

    2) We setup the UDMA and EPI at the startup of the program. When the interrupt comes all we do is start the read on the EPI. Here is the code:

    int daStart(char type) {
    EPINonBlockingReadStart(EPI0_BASE, 0, g_acqCtrl.size);

    g_acqCtrl.epiChannel = 0;
    g_acqCtrl.flags |= DATA_ACQ_STARTED;
    uDMAChannelEnable(DMA_CH_USED);

    return 0;
    }

    Cheers!

    Rares

  • Hi Amit,

    Thank you for your help. It turned out we were just setting a flag in the interrupt and we were starting the read inside the main loop, which was taking too long (obviously). Now w'ere back to reading the 0x13 as our first value. 

    The only weird thing is that we get 2-3 interrupts when the DMA when the transfer is finished. But i guess we can live with that for now.

    Cheers!

    Rares

  • Hi Rares,

    That's look fine and correct.So when CPU reads back to back it gets data like 0x13, 0x26 and so om?

    So when the UDMA reads the data it always get 0xFF. Is that correct?

    Regards

    Amit

  • Hi Rares,

    Our posts crossed path. For the multiple interrupt issue, can you print the value of the EPIMIS in the Interrupt routine every time it jumps to the interrupt handler. Secondly, in the interrupt routine can you first disable the UDMA Channel, then clear the interrupt and add SysCtlDelay after clearing the Interrupt Status.

    I do not have the ISR code so it is more speculative

    Regards

    Amit

  • Hi Amit,

    Sorry for the confusion. The first value we read is 0x13 followed by 0x14,0x15, 0x16 etc. So the values we read are correct but there is a delay of 0x13 * 66ns = 1.266 us between the time the CPLD asserts the interrupt pin and the time we read the first byte on the EPI.

    We also managed to fix the multiple interrupt by manually stopping the read by calling  EPINonBlockingReadStop(EPI0_BASE, 0);

    Thank you for all your help. 

    Cheers!

    Rares

  • Hi Rares,

    The value read is expected as by the time the CPU enables the EPI, there would have been some Data Transition from the CPLD.

    As for the second part, I am still not convinced why the EPI RXDMADONE Interrupt is firing multiple times, if you clear it well in the Interrupt Routine. By using the EPI Stop you have prevented any further requests, but why in the first place is the request getting generated if the total transfers are done is not right either.

    Regards

    Amit

  • HI Amit Ashara i am using EPI for LCD controling and i want to use uDMA in order to transfer data to LCD via EPI but i need clarification that which method i should do SW channel or EPITX channel ?


    Please help on this as I have used the EPI for LCD i need to transfer the data of LCD via uDMA please give help on the same i having following situation that i am using the EPI in FIFO mode and ain HB8 mode and i have to put the data at location 0xC0000000 and now i want to fetch the data from that lcation to the LCD memory using uDMA but i am confused to use the channel whther by SW_channel or EPITX_channel in order to generate the interrupt of uDMA

    i used the following Configuration

    void UDMA_Intialization(void)
    {
    //
    // Enable the uDMA controller at the system level. Enable it to continue
    // to run while the processor is in sleep.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    //
    // Enable the uDMA controller.
    //
    ROM_uDMAEnable();
    }

    //************************************************************************************
    //************************************************************************************
    //
    // EPI0 by uDMA INITIALIZATION
    //
    //************************************************************************************
    //************************************************************************************
    void InitEPI0Transfer(void)
    {
    //
    // Enable the UART for operation, and enable the uDMA interface for both TX
    // and RX channels.
    //
    ROM_IntEnable(INT_UDMA);

    //
    // Point at the control table to use for channel control structures.
    //
    ROM_uDMAControlBaseSet(ui8ControlTable);

    //
    // Put the attributes in a known state for the uDMA software channel.
    // These should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_SEC_CHANNEL_EPI0TX,
    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
    (UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK));

    ROM_uDMAChannelControlSet(UDMA_SEC_CHANNEL_EPI0TX,
    UDMA_SIZE_16 | UDMA_SRC_INC_NONE |
    UDMA_DST_INC_8 | UDMA_ARB_1);
    // //
    // // Now the uDMA EPI0 TX channel are primed to start a
    // // transfer. As soon as the channels are enabled, the peripheral will
    // // issue a transfer request and the data transfers will begin.
    // //
    //
    // ROM_uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0TX);
    }


    my interrupt routine

    void
    uDMAIntHandler(void)
    {
    uint32_t ui32Mode;
    uint32_t g_ui32BadISR;

    InitEPI0Transfer();
    //
    // Check for the primary control structure to indicate complete.
    //
    ui32Mode = ROM_uDMAChannelModeGet(UDMA_SEC_CHANNEL_EPI0TX);

    {
    //if(!ROM_uDMAChannelIsEnabled(UDMA_SEC_CHANNEL_EPI0TX))
    {
    ROM_uDMAChannelTransferSet(UDMA_SEC_CHANNEL_EPI0TX,UDMA_MODE_BASIC,(void*)0xC0000000,g_ulSrcBuf,sizeof(g_pusEPI));
    //
    // Initiate another transfer.
    //
    //ROM_uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0TX);
    }

    }
    }
    //
    // Now the uDMA EPI0 TX channel are primed to start a
    // transfer. As soon as the channels are enabled, the peripheral will
    // issue a transfer request and the data transfers will begin.
    //
    ROM_uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0TX);
    ROM_uDMAChannelRequest(UDMA_SEC_CHANNEL_EPI0TX);
    }
  • Hello Smit,

    It depends. What is the LCD controller that you have on the device. Is it LCD controller of TM4C129 or you have created a bit banged LCD controller.

    Regards
    Amit