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.

TM4C129 EPI HB16 uDMA write not starting

Other Parts Discussed in Thread: TM4C129XNCZAD, TMS320C6472

Hi,

I'm having trouble getting the EPI uDMA write to function properly.

I have EPI write (no uDMA) working, EPI read (no uDMA) working and EPI uDMA read working.

From my tests it seems that the EPI uDMA is not even starting!

Please help.

Khaled.

3264.main.c
Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//define the uDMA control table
#if defined(ewarm)
#pragma data_alignment=1024
unsigned char ucControlTable[1024];
#elif defined(ccs)
#pragma DATA_ALIGN(ucControlTable, 1024)
tDMAControlTable ucControlTable[1024];
#else
unsigned char ucControlTable[1024] __attribute__ ((aligned(1024)));
#endif
volatile uint16_t *g_pusEPIFPGA; // Pointer for EPI memory window.
uint32_t u32DataIn[100];
uint32_t u32DataOut[100];
uint32_t numSuccess;
uint32_t numFail;
/**********************************************************************
**********************************************************************/
int main(void) {
uint16_t i;
uint32_t status;
uint16_t errorIndex;
SystemInit(); //system setup
GPIO_Init(); //setup GPIO
uDMA_Init(); //setup the uDMA
EPI_Init(); //setup EPI HPI interface
//test the access to the DSP/HPI interface
numFail = 0; numSuccess = 0;
while(1) {
//fill with dummy data
for(i = 0; i < 100; i++) {
u32DataIn[i] = i;
u32DataOut[i] = 0x0BAD0BAD;
}
EPI_HPI_write ( u32DataIn, 100, (uint32_t *) HPI_MEM_DAC_TX_START);
while((!EPIdone())) { } //wait until uDMA is done
EPI_HPI_read ((uint32_t *) HPI_MEM_DAC_TX_START, 100, u32DataOut);
while((!EPIdone())) { } //wait until uDMA is done
//compare
for(i = 0, errorIndex = 0xFFFF; i < 100; i++) {
if(u32DataIn[i] != u32DataOut[i]) numFail++;
else numSuccess++;
}//for all
// status = EPI_HPI_uDMA_write( u32DataIn, 100, (uint32_t *) HPI_MEM_DAC_TX_START);
// while((!EPIdone())) { } //wait until uDMA is done
status &= EPI_HPI_uDMA_read ((uint32_t *) HPI_MEM_DAC_TX_START, 100, u32DataOut);
// SysCtlDelay(gSysCtlClock * 1e-3);
// wait for uDMA interrupt
// wait for uDMA to finish
while((!EPIdone())) { } //wait until uDMA is done
//compare
for(i = 0, errorIndex = 0xFFFF; i < 100; i++) {
if(u32DataIn[i] != u32DataOut[i]) numFail++;
else numSuccess++;
}//for all
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • Hi Saab,

    How do you trigger the DMA transfer, HW interrupts or SW? If you use SW trigger, you need to issue a transfer request by setting bit 30 of the DMA channel SW request register (DMASWREG).

    Regards,
    QJ
  • Hi,
    I will give it a try, but I think its something else since my EPI uDMA read works without setting this bit! unless...
    Khaled.
  • Hi QJ,
    Did the change and it worked :-)

    But what is the relation? I checked the documentation and DMASWREG /bit 30 should be set to initiate a memory-to-memory transfer and not a peripheral transfer:
    "This function could be used for performing a memory-to-memory transfer, or if for some reason a transfer needs to be initiated by software instead of the peripheral associated with that channel."

    So what it worked? and is it documented anywhere?
    Khaled.
  • Hi QJ,

    I was too hasty in my test: Its still not working.

    It should be something simple since the EPI uDMA read IS WORKING, and both EPI uDMA read and EPI uDMA write have very similar code.

    Khaled.

  • Hi All,
    I'm running out of options: I tried every single code combination that I can think of and I checked over a two dozen posts regarding the EPI interface and the uDMA interface. I need some help, and I need it soon.
    thanks.
    Khaled.
  • Hello Khaled,

    I checked the code. The issue is that the EPINonBlockingReadConfigure is not using the correct address. The address that must be used to read the data from the external device/memory should be in the same address map as configured using EPIAddressMapSet. As an example

    EPIAddressMapSet(EPI0_BASE, EPI_ADDR_RAM_SIZE_64KB | EPI_ADDR_PER_BASE_C);

    is used then then

    EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_16, 0xC0000000);

    Must be used instead of

    EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_16, 0);

    Regards
    Amit
  • Hi Amit

    thanks for you reply, but the uDMA read is working just fine, its the uDMA write that I have trouble with.

    If I use non uDMA read or non uDMA write function, all is OK: I can write data and read it back.

    If I use the uDMA read all seems to be OK as well: I can use the non uDMA write followed by the uDMA read and its working.

    Khaled.

  • Hello Khaled

    In the code given the API call EPIDMATxCount is commented out. Also the Interrupt for DMA Done for TX is also commented. How would the CPU know that the DMA has completed transfer?

    Regards
    Amit
  • Hi Amit,

    I was testing with different configurations to see which one works. Tried both EPIDAMTxCount commented out and not commented and neither worked.

    As for the DMA Done, I did not get that far. I'm still trying to get the data across to the destination devise. One I have that part working, I can worry about uDMA done.

    Khaled.

  • Hello Khaled

    Since I do not have a similar setup, I would require the following information

    1. The EPI register dump for all EPI registers
    2. The uDMA register dump for all DMA registers
    3. The uDMA primary control table in SRAM for the values programmed in the channel control structures, when the write does not occur

    Regards
    Amit
  • Hi Amit

    Here are the 3 information captured just before calling uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0TX) that should write the data.

    I'm attaching the same information captured just before calling uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0RX) that should read the data.

  • Hello Khaled

    The data sheet specs the following
    "A μDMA request is asserted by the EPI WRFIFO when the TXCNT value of the EPIDMATXCNT register is greater than zero and the WTAV bit field of the EPIWFIFOCNT register is less than the programmed threshold trigger, WRFIFO, of the EPIFIFOLVL register"

    In the configuration above the WTAV is more than WRFIFO.

    I am trying to setup a TX transfer with SDRAM and uDMA to see if that indeed is the cause...

    Regards
    Amit
  • Ok, but what caused the WTAV register to have a larger value than WRFIFO? how much larger are we talking about? is a single word larger or multiples?
    thanks.
    Khaled.
  • Hello Khaled

    I tried a SDRAM data transfer using the DMA and Write Request from the EPI and it works as expected. Attached is the reference code. The code is for a DK-TM4C129X (TM4C129XNCZAD) coupled with a SDRAM Board

    dktm4c129_sdram_performance_example.c
    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    //*****************************************************************************
    //
    // sdram.c - Example demonstrating how to configure the EPI bus in SDRAM
    // mode.
    //
    // Copyright (c) 2014 Texas Instruments Incorporated. All rights reserved.
    // Software License Agreement
    //
    // Redistribution and use in source and binary forms, with or without
    // modification, are permitted provided that the following conditions
    // are met:
    //
    // Redistributions of source code must retain the above copyright
    // notice, this list of conditions and the following disclaimer.
    //
    // Redistributions in binary form must reproduce the above copyright
    // notice, this list of conditions and the following disclaimer in the
    // documentation and/or other materials provided with the
    // distribution.
    //
    // Neither the name of Texas Instruments Incorporated nor the names of
    // its contributors may be used to endorse or promote products derived
    // from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    // This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_epi.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/epi.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "utils/uartstdio.h"
    //*****************************************************************************
    //
    //! \addtogroup epi_examples_list
    //! <h1>EPI SDRAM Mode (sdram)</h1>
    //!
    //! This example shows how to configure the TM4C129 EPI bus in SDRAM mode. It
    //! assumes that a 64Mbit SDRAM is attached to EPI0.
    //!
    //! For the EPI SDRAM mode, the pinout is as follows:
    //! Address11:0 - EPI0S11:0
    //! Bank1:0 - EPI0S14:13
    //! Data15:0 - EPI0S15:0
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Regards

    Amit

  • Hi Amit,

    Thanks for the effort that you are putting into this, but my problem is still un-resolved.

    I tried to adapt you code to HB16 interface but nothing has changed: The uDMA write is still not working.

    I'm not sure what will be the next step, but our customers are waiting for the new board and I can't give the go ahead until this interface is working!

    Khaled.

  • Hello Khaled

    Is the iRDY holding off the bus?

    Regards
    Amit
  • I will probe it and get back to you. But most likely its not. As I mentioned before the following accesses are working fine:  Non uDMA read, Non uDMA write, and uDMA read.

    The only non working access is the uDMA write.

    If it was the iRDY, I would have seen the problem with the Non uDMA write as well.

    Both Non uDMA write and uDMA write functions shares the same code until the last few instruction.

    In the non uDMA case I do a direct write

    for(i = 0; i < count; i++) {

    word            = src_p[i];

    *g_pusEPIFPGA =  (word         ) & 0xFFFF; g_pusEPIFPGA++;

    *g_pusEPIFPGA = (word >> 16) & 0xFFFF; g_pusEPIFPGA++;

    EPIWriteFIFOEmpty(TRUE); //wait write fifo to be empty

    }

    In the uDMA case write I program the uDMA to send the data

    EPIDMATxCount( EPI0_BASE,count * 2);

    uDMAChannelTransferSet( UDMA_CH21_EPI0TX, UDMA_MODE_BASIC, src_p, (void *)g_pusEPIFPGA, count * 2);

    uDMAChannelEnable( UDMA_CH21_EPI0TX);

  • Hello Khaled

    Since you have proven that non-uDMA read write and uDMA read work fine, the interface is OK. It is a software configuration that is not working which has to be analyzed.

    I would suggest checking it with a SDRAM board if you have access to one?

    Regards
    Amit
  • Hi Amit,

    I fully agree with you: its a configuration problem. But what? that is what is driving me crazy. I checked every instruction and every register but I'm not able to find the error. I was hoping that you will be able to find it for me.


    I don't have an SDRAM that is connected to the HB16 bus. This is a home made board that connect the Cortex M4 to Ti's TMS320C6472 HPI bus.

    However, as per your instructions, I did asked our technician to solder probes to the HB16 control bus (including the iRDY). I should be able to have the modified board today.

    Khaled.

  • Hello Khaled

    I would suggest soldering the probes on the all the critical signals so that we can see what is happening on the bus for the control signals.

    Regards
    Amit
  • Hello Amit

    Did as you have suggested and I think I have the first clue: The address bus is not toggling when performing a uDMA write!

    In my case, I"m using a single address bus A0 to act as a half word strobe to the TM320C6472: A0 is low for the 1th 16bits, and high for the second 16bits.

    Now the question, is why?

    Khaled.

  • Hello Amit,

    I think I found the solution. I have to increment the destination address as follow:

    uDMAChannelControlSet(UDMA_SEC_CHANNEL_EPI0TX,  //WFIFO

            UDMA_SIZE_16          |      //data size

            UDMA_SRC_INC_16       |      //source address increment

       UDMA_DST_INC_16       |      //destination address increment

       UDMA_ARB_1);                 //arbitration size

    I will do some more tests to confirm.

    Khaled

  • Hello Khaled,

    Then it must be the device that is not responding to back-2-back access?

    Regards
    Amit
  • Hello Amit,
    Its not the external device.
    The Cortex was not incrementing the address bus when uDMA write is performed.
    I made the SAME error as before when I was writing the non uDMA Epi read and write functions (see previous post where you solved for me the manual increment of the EPI address bus): e2e.ti.com/.../1288134

    Now again, the M4, the DMA engine has to be explicitly configured to increment.
    Khaled.
  • Hi Amit,
    One last issue with the HB16.
    Now that I have uDMA write transferring data properly, the EPI interrupt handler keep triggering endlessly with EPI_INT_DMA_TX_DONE flag.
    I'm not able to clear it.
    There is a EPIIntErrorClear(EPI0_BASE, intStatus) function to clear the error flag, but no function to clear the uDMA done flag!

    Khaled.
  • Hello Khaled

    You have to use the API as follows.

    EPIIntErrorClear(EPI0_BASE, EPI_INT_ERR_DMAWRIC);

    Regards
    Amit
  • Hi Amit,
    That did not work.
    Tried
    intStatus = EPIIntStatus(EPI0_BASE, true);
    EPIIntErrorClear(EPI0_BASE, intStatus);

    and tried
    intStatus = EPIIntStatus(EPI0_BASE, true);
    EPIIntErrorClear(EPI0_BASE, EPI_INT_ERR_DMAWRIC);

    but I EPI handler keeps on triggering.
    Khaled.
  • Hello Khaled

    Can you check if the write counter in EPI is 0?

    Regards
    Amit
  • Hi Amit

    Here is the registers values captured as soon as I enter the EPI handler.

    Khaled.

  • Hello Khaled,

    The EPI register WFIFOCOUNT is not "0". Hence the EPI is requesting the DMA for more data, but since the DMA transfer size has decremented to 0 and the channel mode automatically turned to STOP, the DMA Done is being asserted by the DMA which is what is causing the Interrupt to fire again.
    You need to make sure that the Transfer Size in the control structure of the DMA and the WFIFOCOUNT register value is correctly programmed

    Regards
    Amit
  • Hi Amit,

    I'm confused. I thougth that the EPI WFIFOCNT == 4 means the the fifo IS empty.

    Here is my Epi init and Epi uDMA write function. could you please take a look.

     

    void EPI_HPI_uDMA_write(uint32_t *src_p, uint32_t  count, uint32_t *dst_p) {

     // Set pointer to EPI memory mapped window.
     g_pusEPIFPGA = (uint16_t *)0xC0000000;

     //write the data
     EPIDMATxCount(EPI0_BASE, count * 2);
     uDMAChannelTransferSet(UDMA_CH21_EPI0TX, UDMA_MODE_BASIC, src_p, (void *)g_pusEPIFPGA, count*2);
     uDMAChannelEnable(UDMA_CH21_EPI0TX);
    }


    void EPI_Init(void) {
        g_pusEPIFPGA = (uint16_t *)0xC0000000;
        EPIModeSet(EPI0_BASE,
                   EPI_MODE_DISABLE);
        EPIDividerSet(EPI0_BASE,
                   EPI_DIV_FACTOR_DATA);
        EPIModeSet(EPI0_BASE,
                   EPI_MODE_HB16);
        EPIConfigHB16Set(    EPI0_BASE,
    //             EPI_HB16_USE_TXEMPTY          |     //Tx fifo empty enable
    //             EPI_HB16_USE_RXFULL           |     //Rx fifo full enable
    //             EPI_HB16_BURST_TRAFFIC        |     //burst mode enabled
                   EPI_HB16_IN_READY_EN          |     //IRDY enabled
                   EPI_HB16_IN_READY_EN_INVERTED |     //IRDY polarity inverted
                   EPI_HB16_MODE_ADDEMUX         |     //sets up data and address as separate
                   EPI_HB16_CSCFG_ALE            |     //EPIS030 to operate as an address latch (ALE)
                   EPI_HB16_ALE_HIGH             |     //sets the address latch active high
                   EPI_HB16_WRWAIT_0             |     //sets write wait state to 2 EPI clocks.
                   EPI_HB16_RDWAIT_0             ,     //sets read wait state to 2 EPI clocks.
                   0xF0);                              //FIFO mode    maximum number of clocks
        EPIConfigHB16TimingSet(EPI0_BASE,
                   0            ,                        //specifies the chip select to configure[0-3]
                   EPI_HB16_IN_READY_DELAY_1     |       //sets the stall on input ready (EPIS032)
                                                         //to start 1 EPI clock after signaled
                   EPI_HB16_WRWAIT_MINUS_ENABLE  |       //1 EPI clock write wait state reduction
                   EPI_HB16_RDWAIT_MINUS_ENABLE);        //1 EPI clock read wait state reduction
        EPIAddressMapSet(EPI0_BASE,
                   EPI_ADDR_PER_BASE_C   |
                   EPI_ADDR_PER_SIZE_64KB);
        EPIFIFOConfig(EPI0_BASE,
                   EPI_FIFO_CONFIG_TX_1_2 |
                   EPI_FIFO_CONFIG_RX_1_2);
        EPINonBlockingReadConfigure(EPI0_BASE,
                   0,
                   EPI_NBCONFIG_SIZE_16,
                   0);

        //-------------------------------------------------------------
        // Setup the EPI interrupt to service the NBRFIFO and the WFIFO
        //-------------------------------------------------------------
        EPIIntDisable(EPI0_BASE,
                   EPI_INT_RXREQ      |
                   EPI_INT_TXREQ      |
                   EPI_INT_ERR);
        EPIIntErrorClear(EPI0_BASE,
                   EPI_INT_ERR_WTFULL |
                   EPI_INT_ERR_RSTALL |
                   EPI_INT_ERR_TIMEOUT);

        EPIIntEnable(EPI0_BASE,
    //             EPI_INT_RXREQ       |    //read FIFO above trigger level
    //             EPI_INT_TXREQ       |    //transmit FIFO below trigger level
                   EPI_INT_DMA_TX_DONE |    //transmit DMA completes
                   EPI_INT_DMA_RX_DONE |    //read DMA completes
                   EPI_INT_ERR);            //error condition
        IntEnable(INT_EPI0);

        //-------------------------------------------------------------
        // Configure the uDMA for the EPI read and write
        //-------------------------------------------------------------
        uDMAChannelAssign(    UDMA_CH20_EPI0RX);
        uDMAChannelAssign(    UDMA_CH21_EPI0TX);

        uDMAChannelAttributeDisable(UDMA_CH20_EPI0RX, UDMA_ATTR_ALL);
        uDMAChannelAttributeDisable(UDMA_CH21_EPI0TX, UDMA_ATTR_ALL);
        uDMAChannelSelectSecondary( UDMA_DEF_TMR1A_SEC_EPI0RX |
                                    UDMA_DEF_TMR1B_SEC_EPI0TX);
        uDMAChannelAttributeEnable( UDMA_CH20_EPI0RX,           //NBRFIFO
                                    UDMA_ATTR_USEBURST |        //single request is not supported
                                    UDMA_ATTR_HIGH_PRIORITY);   //needed for ADC transfers
        uDMAChannelAttributeEnable( UDMA_CH21_EPI0TX,           //WFIFO
                                    UDMA_ATTR_USEBURST);        //single request is not supported
        uDMAChannelControlSet(      UDMA_CH20_EPI0RX,           //NBRFIFO
                                    UDMA_SIZE_16       |        //data size
                                    UDMA_SRC_INC_NONE  |        //no source address increment
                                    UDMA_DST_INC_16    |        //destination address increment
                                    UDMA_ARB_4);                //arbitration size
        uDMAChannelControlSet(      UDMA_CH21_EPI0TX,           //WFIFO
                                    UDMA_SIZE_16       |        //data size
                                    UDMA_SRC_INC_16    |        //source address increment
                                    UDMA_DST_INC_16    |        //destination address increment
                                    UDMA_ARB_2);                //arbitration size
        //-------------------------------------------------------------
        //setup the uDMA interrupts
        //-------------------------------------------------------------
        IntEnable(INT_UDMA);
        IntEnable(INT_UDMAERR);
    }


    Khaled

  • Hello Khaled,

    I was looking at the EPI DMATXCNT register when I wrote the WFIFOCNT register. The whole explanation is the same, except replace WFIFOCNT with DMATXCNT register.

    Regards
    Amit
  • Hi Amit,

    I think that I found a solution: I changed the order or the commands and moved EPIDMATxCount( ) call to the end(see below).
    Does that make sens?

    void EPI_HPI_uDMA_write(uint32_t *src_p, uint32_t count, uint32_t *dst_p) {

    // Set pointer to EPI memory mapped window.
    g_pusEPIFPGA = (uint16_t *)0xC0000000;

    //write the data
    uDMAChannelTransferSet(UDMA_CH21_EPI0TX, UDMA_MODE_BASIC, src_p, (void *)g_pusEPIFPGA, count * 2);
    uDMAChannelEnable(UDMA_CH21_EPI0TX);
    EPIDMATxCount(EPI0_BASE, count * 2);
    }
    Khaled
  • Hello Khaled,

    It does make sense. The EPIDMATxCnt generates the DMA request. If the channel is not configured and enabled, then EPI generates request which results in DMA Done interrupt as the DMA does not know what to do with the transfer request.

    Regards
    Amit
  • Fair enough, but when dealing with all the Cortex M4 interfaces, it seems that each interface has a special way and special commands to make it run properly! This is a draw back and TI should change how uDMA is setup and make it the SAME for all.
    It time consuming and thus costly to figure out the setup for each interface.

    This is said, thanks Amit. You were very helpful. I have been stuck on this particular interface for 2 weeks now and I could have been stuck for another 2 weeks if it was not for your involvement.

    Khaled.
  • Hello Khaled

    We are working on an application note, where uDMA interaction with each of the modules will be better explained with examples that span re-entrant loops. This module has been one of the little explained module and I agree, it need explanation.

    Regards
    Amit