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.

CCS/TMS320C5515: DMA interrupt seems to stop working when running stand alone

Part Number: TMS320C5515


Tool/software: Code Composer Studio

I'm using CCSv7 with DSP/BIOS 5.42.2.10. I have I2S0 feeding data to DMA0 through a ping/pong buffer generating interrupts that are serviced by an isr for further processing. The project is working great while attached to the emulator (USB560v2) but when I load it on to the custom board NOR flash and run stand alone, the interrupts are apparently not generated. (I'm using a print statement to my OLED display to show any ISR activity). I am not using any gel file with the emulator. The I2S signal is present (checked with oscilloscope). Other interrupts work (INT0 for example). I can't see what would be different between the two setups. I even tried a manual hard reset on the DSP. Any ideas what to check would be welcome! Thanks.

  • Hi Cam,

    I´ve done a lot with this stuff decades ago (TMS320C5416) - but should be similar thing...

    A print statement within the isr is no good idea at first.... just having a gobal counter variable in the irq and the print statement in a task would be the right choice.

    (print may take very long, may use lots of stack, might be not designed to be called from irq and so on)

    The stuff has to be started in the right order:

    allocate memory

    setup & enable dma

    register irq

    configure i2s and start i2s

    In operation - the I2S0 informs DMA using an event that a new value is ready for transfer

    If the DMA reads this event - its cleared automatically.

    (if nobody clears it - transmission will stop because dma only works on setting the flag - but its already "on" - and I2S cant generate a new event because its already "on")

    If you start I2S without working and setup DMA - the dma would have missed it - so clearing the bit in your startup code would re-initiate the story.

    With the emulator you can select in the debug settings if dma should be stopped/started on debugging - if this is active - its possible that the emulator resumes the DMA in a way its working...

    You can connect to an already running target by just loading the symbols to the emulator... 

    I would suggest connecting with the target started from flash, loading coresponding symbols only - stop the target - and compare register settings, flags ov involved events and device status...

    rgds,

    Wolfgang

  • Hey Wolfgang,

    Thanks. I know what you mean about heavily loaded statements in the ISR. I was desperate to find a way to peek inside when running stand alone and it seemed to work while on the emulator. Your suggestion of connecting to a running target was a great one. I hadn't thought of that or needed to do it, but now I know and it is helping. It does appear now that the ISR is being called since I could reach a breakpoint after connecting to the running target. The ISR sends a semaphore to a task that then performs an fft. I'm now seeing that the ROM hwafft_br and hwafft_512pts are acting strangely and giving back a final 0 filled array result. Interestingly, I can reproduce this in the emulator alone. If I allow the gel to execute GEL_Reset() and nothing else, the br and fft work fine. However, if I don't use the reset, I get the same 0 filled array result. I checked MPNMC and it is cleared. I am using the Eratta form of these functions. Hmmm. I wonder what the GEL_Reset() does differently?
  • Another typical problem with these devices (I assume similarity to 5416) was that the DMA ENABLE Register was on Address "0x00000000".
    So any typical 0-pointer fault ended up in all DMA channels released. (and zeroing or filling the memory within a debugstep).. So a memory-write breakpoint to address 0 was obligatory.. But in such case - everything would be gone... You know that you need special irq pro- and epilog if you need to execute special dsp/bios (semaphore) code ? I would start with running "hello world" from flash... Maybe there is a problem on clocking up the device - wrong clock multiplier... need more time until pll stabilizese. The _TIMING_ of the reset is definitly slower if running from gel as every command is released doing peek&poke... Do you copy and execute your code in the sram ? Never trust a bootloader - you can read out the memory with jtag and compare both binary blobs... rgds, have fun !
  • Ok, I put my display statement in the task that receives a semaphore from the dma isr routine. It doesn't get displayed, so I'm back to believing that the ISR is not running when operating stand alone. The effect of the fft routine appears to be another distraction.
  • Thanks Wolfgang. DMA enable is not at 0x0 so that should be fine. The SEM module is part of the DSP/BIOS and works great so I don't need anything extra there. Clocking is fine because I derive my uart from it and it works great. Maybe reset timing is an issue, but I do a lot before starting up the dma. The bootloader seems to be doing fine too in all other aspects. I connected to the running target and the dma isr started working and continues after disconnect. Just not from boot.
  • Keep things simple.... How do you configure IIS port ? Event-Flags ?JHow started ? Connect with debugger to running target and try to start streaming by tweaking peripheral register bits... on some parts you can do that without stopping the core... The ISR runs the FFT ? ... so if fft calculation takes longer than reception of one block - the stuff would stop working....> Run the FFT in a SWI or TSK, use the HWI for triggering only...
  • i2S port and DMA configurations are quite straight forward and similar to the TI examples. Working great with the emulator. The ISR is not running the FFT. The ISR uses the SEM module of the DSP/BIOS to signal a TSK that then processes the data with the FFT. Unfortunately, only stop mode is allowed with CCSv7 and the 5515 DSP so I can't get streaming data.
  • What about having a timer which runs slower than your buffer swapping - and gets reset every time a buffer is swapped...

    Every time the timer is triggered (which should not happen, normally if everythings working) - the timer should reset i2s peripheral - and DMA eventing mechanisms...

    As indicated in the first mail . i2s should be started if everythings working properly and initialized... 

    Do you use static drivers for I2S config ? they should have a start/stop restart mechnism - which should be triggered very late.

  • OK, I have C:\ti\c55_lp\c55_csl_3.08\ccs_v6.x_examples\dma\CSL_DMA_PingPongExample running on my board with the addition of my display functions so I can see on my screen what is going on when running stand alone. I'm running into the same problem. It gets stuck at

    while(count != 2);

    which is waiting for the dma to set the flag. My display prints for the ping and pong in the ISR (where the pre-existing printf statements are) are not showing up.

    Works fine with the emulator.

    I'll play around with a timed reset.
  • Hi Cam,

    Could you attach to this thread a file with minimal code which causes the issue if this is not confidential of course? This would help to get an idea about the issue.

    Regards,
    Tsvetolin Shulev

  • Hi Tsvetolin,

    Here is a snippet that works in the emulator but not on the device. It is a slightly modified version of CSL_DMA_PingPongExample. I have included code that writes to my OLED attached to the LCD port of the c5515 so I can see the result when running stand alone on the device.

    #include "csl_dma.h"
    #include "csl_intc.h"
    #include <stdio.h>
    #include "display_control.h"

    #define CSL_DMA_BUFFER_SIZE 512

    /* Reference the start of the interrupt vector table */
    extern void VECSTART(void);
    /* prototype declaration for ISR function */

    /**
    * \brief DMA Interrupt Service routine
    *
    * \param none
    *
    * \return none
    */
    interrupt void dma_isr(void);

    #pragma DATA_ALIGN (dmaPingDstBuf, 4)
    Uint16 dmaPingDstBuf[CSL_DMA_BUFFER_SIZE];
    #pragma DATA_ALIGN (dmaPongDstBuf, 4)
    Uint16 dmaPongDstBuf[CSL_DMA_BUFFER_SIZE];

    /* Declaration of the buffer */
    #pragma DATA_ALIGN (dmaPingSrcBuf, 4)
    Uint16 dmaPingSrcBuf[CSL_DMA_BUFFER_SIZE];

    #pragma DATA_ALIGN (dmaPongSrcBuf, 4)
    Uint16 dmaPongSrcBuf[CSL_DMA_BUFFER_SIZE];

    static int count ;
    static int isrEntryCount = 0;

    CSL_DMA_Handle dmaHandle;
    CSL_DMA_Config dmaConfig;
    CSL_DMA_Config getdmaConfig;

    CSL_Status status;

    /**
    * \brief Tests DMA Ping-Pong Mode transfers
    *
    * \param none
    *
    * \return none
    */
    /////INSTRUMENTATION FOR BATCH TESTING -- Part 1 --
    ///// Define PaSs_StAtE variable for catching errors as program executes.
    ///// Define PaSs flag for holding final pass/fail result at program completion.
    volatile Int16 PaSs_StAtE = 0x0001; // Init to 1. Reset to 0 at any monitored execution error.
    volatile Int16 PaSs = 0x0000; // Init to 0. Updated later with PaSs_StAtE when and if
    ///// program flow reaches expected exit point(s).
    /////

    #define PERIPHSEL0 *(ioport volatile unsigned *)0x1C00 // PERIPHSEL0 (Peripheral Pin Mapping Register 0)


    void println(char buffer[22])
    {
    static int line=3;
    display_set_char_row_col(line,0);
    display_printstring(" ");
    display_set_char_row_col(line--,0);
    display_printstring(buffer);
    if (line<0)
    line=3;
    }

    void main(void)
    {
    PERIPHSEL0 = 0x5100; // parallel port: mode 5, serial port1: mode 0, serial port0: mode 1

    display_init();
    println("hello");

    #if (defined(CHIP_C5505_C5515) || defined(CHIP_C5504_C5514) || defined(CHIP_C5517) || defined(CHIP_C5535) || defined(CHIP_C5545))

    CSL_DMA_ChannelObj dmaObj;
    Uint16 chanNumber;
    Uint16 index;

    printf("\nDMA PING-PONG MODE TEST!\n");

    dmaConfig.pingPongMode = CSL_DMA_PING_PONG_ENABLE;
    dmaConfig.autoMode = CSL_DMA_AUTORELOAD_DISABLE;
    dmaConfig.burstLen = CSL_DMA_TXBURST_4WORD;
    dmaConfig.trigger = CSL_DMA_SOFTWARE_TRIGGER;
    dmaConfig.dmaEvt = CSL_DMA_EVT_NONE;
    dmaConfig.dmaInt = CSL_DMA_INTERRUPT_ENABLE;
    dmaConfig.chanDir = CSL_DMA_READ;
    dmaConfig.trfType = CSL_DMA_TRANSFER_MEMORY;
    dmaConfig.dataLen = CSL_DMA_BUFFER_SIZE * 4;
    dmaConfig.srcAddr = (Uint32)dmaPingSrcBuf;
    dmaConfig.destAddr = (Uint32)dmaPingDstBuf;

    IRQ_globalDisable();

    IRQ_clearAll();

    IRQ_disableAll();

    IRQ_setVecs((Uint32)&VECSTART);
    IRQ_clear(DMA_EVENT);

    IRQ_plug (DMA_EVENT, &dma_isr);

    IRQ_enable(DMA_EVENT);
    IRQ_globalEnable();

    status = DMA_init();
    if (status != CSL_SOK)
    {
    printf("DMA_init() Failed \n");
    println("init failed");

    /////INSTRUMENTATION FOR BATCH TESTING -- Part 2 --
    ///// Reseting PaSs_StAtE to 0 if error detected here.
    PaSs_StAtE = 0x0000; // Was intialized to 1 at declaration.
    /////
    }

    println("main loop start");

    for( chanNumber = 0; chanNumber < CSL_DMA_CHAN_MAX; chanNumber++)
    {
    count = 0;
    printf("\nTest for DMA Channel Number: %d\n", chanNumber);
    println("dma start");

    for(index = 0; index < CSL_DMA_BUFFER_SIZE; index++)
    {
    dmaPingSrcBuf[index] = index;
    dmaPongSrcBuf[index] = 2*index;

    dmaPingDstBuf[index] = 0x0000;
    dmaPongDstBuf[index] = 0x0000;
    }

    dmaHandle = DMA_open((CSL_DMAChanNum)chanNumber,&dmaObj, &status);
    if (dmaHandle == NULL)
    {
    printf("DMA_open() Failed \n");
    println("hello 2");
    break;
    }

    status = DMA_config(dmaHandle, &dmaConfig);
    if (status != CSL_SOK)
    {
    printf("DMA_config() Failed \n");
    println("hello 3");
    break;
    }

    status = DMA_start(dmaHandle);
    if (status != CSL_SOK)
    {
    printf("DMA_start() Failed \n");
    println("hello 4");
    break;
    }

    println("waiting");
    while(count != 2);
    println("done waiting");

    status = DMA_close(dmaHandle);
    if (status != CSL_SOK)
    {
    printf("DMA_close() Failed \n");
    println("hello 5");
    break;
    }

    status = DMA_reset(dmaHandle);
    if (status != CSL_SOK)
    {
    printf("DMA_reset() Failed \n");
    println("hello 6");
    break;
    }

    for(index = 0; index < CSL_DMA_BUFFER_SIZE; index++)
    {
    if(dmaPingSrcBuf[index] != dmaPingDstBuf[index])
    {
    printf("Ping Buffer Miss Matched at Position %d\n", index);
    println("ping mismatch");
    break;
    }

    if(dmaPongSrcBuf[index] != dmaPongDstBuf[index])
    {
    printf("Pong Buffer Miss Matched at Position %d\n", index);
    println("pong mismatch");
    break;
    }
    }

    if(index == CSL_DMA_BUFFER_SIZE)
    {
    printf("Test Successful\n");
    println("dma success");
    }
    }

    IRQ_clearAll();
    IRQ_disableAll();
    IRQ_globalDisable();

    if(isrEntryCount == 32)
    {
    printf("\n\nDMA PING-PONG MODE TEST PASSED!!\n");
    println("isr pass");
    }
    else
    {
    printf("\n\nDMA PING-PONG MODE TEST FAILED!!\n");
    println("isr fail");
    /////INSTRUMENTATION FOR BATCH TESTING -- Part 2 --
    ///// Reseting PaSs_StAtE to 0 if error detected here.
    PaSs_StAtE = 0x0000; // Was intialized to 1 at declaration.
    /////
    }

    #else

    printf("\n\nINVALID TEST FOR THE CHIP VERSION!!\n");
    /////INSTRUMENTATION FOR BATCH TESTING -- Part 2 --
    ///// Reseting PaSs_StAtE to 0 if error detected here.
    PaSs_StAtE = 0x0000; // Was intialized to 1 at declaration.
    /////

    #endif
    /////INSTRUMENTATION FOR BATCH TESTING -- Part 3 --
    ///// At program exit, copy "PaSs_StAtE" into "PaSs".
    PaSs = PaSs_StAtE; //If flow gets here, override PaSs' initial 0 with
    ///// // pass/fail value determined during program execution.
    ///// Note: Program should next exit to C$$EXIT and halt, where DSS, under
    ///// control of a host PC script, will read and record the PaSs' value.
    /////
    }

    /**
    * \brief DMA Interrupt Service routine
    *
    * \param none
    *
    * \return none
    */
    interrupt void dma_isr(void)
    {
    int ifrValue;

    ifrValue = CSL_SYSCTRL_REGS->DMAIFR;
    CSL_SYSCTRL_REGS->DMAIFR |= ifrValue;

    #if (defined(CHIP_C5505_C5515) || defined(CHIP_C5504_C5514) || defined(CHIP_C5517) || defined(CHIP_C5535) || defined(CHIP_C5545))

    if ((DMA_getLastTransferType (dmaHandle, &status)) == 1)
    {
    printf("Pong Set Transfer Completed\n");
    display_set_char_row_col(2, 0);
    println("Pong done");

    }
    else
    {
    printf("Ping Set Transfer Completed\n");
    display_set_char_row_col(2, 0);
    println("Ping done");
    }

    #endif

    ++count;
    ++isrEntryCount;
    }
  • update:

    I took out the printf statements just to keep it clean but they should be benign.
    The target got stuck on "waiting"
    When I attached to the running target with the emulator, it was in the ISR and if I continued the program, it finished normally.
    So, something about connecting the emulator fixes the problem. Target config?
  • What is behavior if running CSL_DMA_PingPongExample (without any modifications) stand alone on your board? Are you observing stop working?

    Regards,
    Tsvetolin Shulev
  • Do you have an idea how I can tell without modifying the code to see the progress on the display?
  • Ahhh, yes, it is necessary to have some indication that the board is still working. But on other hand I suspect printing on display could causing the issue. Probably some LED blinking can be used as working indication.

    Regards,
    Tsvetolin Shulev
  • I reproduced the problem on the C5515ezDSP board. I used the I2C interface to the display on it instead of the LCD interface on mine so it is somewhat different. So, to sum up, when I run the PingPongExample from the emulator, the dma and their interrupts work fine. When I load it on the board and boot from NOR flash, it hangs waiting.

    PingPongExample-ezDSP2.zip

  • So, I'm isolating the problem a little more. Here is a very simple project with a single dma and interrupt. It will work on the emulator if you don't use the usbstk55.gel file. The interrupt won't work when loaded in the C5515ezDSP board or if you specify the usbstk55.gel file in the target config. DMA_testing_not_working_when_loaded.zip

  • I commented out code in the gel file to determine that running GEL_Reset () will prevent the dma isr from working. According to online information, GEL_Reset() should be the same as the default reset behaviour on the device. This makes sense because the interrupt doesn't work in both situations. Does anyone know what is different about running the emulator without a GEL_reset? Is there an initialization of some kind going on?
  • OK, so now I resolved the difference with the GEL file by putting in a global interrupt enable (__asm(" BCLR INTM"); into the code at the beginning. However, the interrupt still won't run on the target without an emulator connection.
  • Tsvetolin, are you still there?
  • Solved!!

    Buried in the TMS320C5515 Silicon Rev 2 Errata is the answer.
    Since the emulator does not use the bootloader, the ports pertaining to the DMA and FFT are turned on under emulation whereas they are off when booted stand alone. 

    2.1.5 Bootloader Disables Peripheral Clocks
    After hardware reset on silicon revision 2.0 C551x devices, the DSP boots via the bootloader code in
    ROM. During the boot process, the bootloader queries each peripheral to determine if it can boot from the
    peripheral. At that time, the required peripheral’s clock will be enabled for the query and then disabled
    when the bootloader is finished with the peripheral. By the time the bootloader releases control to the user
    code, all peripheral clocks will be off and all domains in the ICR, except the CPU domain, will be idled.
    After the boot process is complete, the user is responsible for enabling and programming the required
    clock configuration for the DSP.

    For example on the C5515 device, the bootloader disables both the MPORT and FFTHWA. To enable the
    MPORT and FFT HWA, write 0x000E to the ICR registers and issue an “idle” command.

    Assembly Code Example:
    *port(#0x0001) = #(0x000E)
    idle

    C Code Example:
    *(ioport volatile unsigned *)0x0001 = 0x000E;
    asm(" idle"); // must add at least one blank before idle in " ".