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.

DMA not working when booting from SPI EEPROM, works when running from debugger

Hi all,

I'm looking for some advice or any technique I can use to debug this problem:

We have a 5505 pulling data from codec into RAM across I2S0 using channels 0 and 1.  The testing of this took place primarily when debugging the target with an XDS100 emulator connected to the board (i.e. running from RAM).  When the code is written into EEPROM and the built-in bootloader loads the code, the image runs but DMA does not behave in the same way - we never get our DMA interrupt.  In my reading of the documentation it states that SPI transfers do not (can not) use the DMA controller, so it's not the bootloader somehow leaving the DMA in a bad state.  In any case, we are re-initializing the DMA subsystem with the appropriate CSL_DMA calls (DMA_init).

Thanks in advance,

Rich

  • Some more update if anyone is still thinking about this problem:

     

    Normal 0 false false false EN-US X-NONE X-NONE MicrosoftInternetExplorer4

    ·         It doesn’t appear that the problems we’ve seen have anything to do with the actual copying of the image

    o   I am able to reproduce the problem in the debugger.  The steps to do this are:

    §  Load the program (or if you’d like, use what’s already in eeprom by just connecting to the target)

    §  Reset the CPU (do not use ‘restart’)

    §  Hit F8 or RUN when you see that the CPU reset puts the program counter in the bootloader area (0xFF6ADC)

    §  The code will run, completely executing the DMA initialization routines (I tested with GPIO).  But no DMA interrupts will occur.

    §  Now HALT and RUN and dma interrupts appear as does audio moments later.

    o   The key to this is that the problem occurs when there is no interruption of the CPU between the bootloader and the application image running.    For some reason halting anywhere (be it ‘main’ or anywhere after) and continuing allows DMA to suddenly kick in.

    ·         It doesn’t appear that the problems have to do with registers being set improperly by the bootloader and/or not reset properly by the application.  I did some register dumps when paused right before the dma starts working and after it starts working and noticed nothing in particular – mostly differences in timer counts, the dma destination address (makes sense, since it auto-increments), real-time clock counts, etc.  The key here is that there were no differences in DMA registers or PLL/clock registers.

     

    With all that said, I just noticed that where I break affects whether or not the audio gets detected.  I have no idea if this means anything, but if I break at the entry point of the application image (_c_int00), we never get a “StreamIsOn” to evaluate true, and therefore get no xmit or i2s line activity.  If I break at main (or later) and continue from there, we do.

  • Here are a few thoughts:

     

    • Are you configuring the DMA before configuring the I2S?  A common mistake I see a lot of people make is to configure the I2S first and so the first event ends up getting missed/dropped by the DMA controller and then the I2S never generates another because nothing ever serviced the first!
    • You mention that if you halt and then run it seems to fix things.  Do you have any watch windows or memory windows open when you halt?  Perhaps a memory read from the debugger (e.g. to I2SRX register) is kickstarting the transfers.
    • For viewing registers the memory window has a selection box where you can choose Program, Data, or I/O memory space.  Are you saying that even when you choose I/O memory space it still shows you values from Program space, or did you perhaps miss that box?
  • I moved the DMA init above the i2s and codec init but still see the same issues.

    I also tried closing the memory window so that a read of the i2srx register when halting wouldn't kick off something unknowingly.  The issue was still there.

     

    I probably wasn't very clear when I was mentioning the memory window.  I was able to get the memory window to display everything just fine.  But I originally had tried to dump register contents using the register view.  Unfortunately, it took a little while to realize that the register view window does not provide accurate results for peripheral registers because it is looking in program memory space instead of i/o space.

     

  • Have you done any further looking into where you need to halt in order for things to work properly?  Have you tried putting a long spin loop in the code (as a substitute for halting)?  For example:

    volatile unsigned long dummy_loop;

    for (dummy_loop=0; dummy_loop<100000000; dummy_loop++);

    Don't forget to make the variable volatile or the compiler might get rid of it!

    Also, to be clear I don't expect the dummy_loop to be a final solution, just a means of trying to narrow down the issue, i.e. is it timing related, etc.

  • Can I ask a basic question or two? 

    When I use the debugger and reset the CPU, the PC points to bootloader code in ROM.  If ROM executes, it's going to use what's in EEPROM every time, isn't it? How does the debugger determine when you want the bootloader to pull code from it's nonvolatile source and when it should execute what has just been loaded into RAM?

    I feel like I'm missing some information.

  • If you do a reset and execute from the boot ROM it will always do the exact same thing, i.e. run through the list of boot sources trying to find an image.

    if you do not want to execute the boot ROM code you can do a reset followed by a restart which will point the CPU to whatever has been designated the "entry point" to your program, generally _c_int00.

  • I gave this a try right at the beginning of 'main'.  I noticed the delay on the scope (several seconds in my case), but the end result was the same.  That seems to indicate that it is still something the debugger is altering somehow when the system is halted and continued.

  • Solution:

     

    Add this to top of 'main':

     

    Normal 0 false false false EN-US X-NONE X-NONE MicrosoftInternetExplorer4

    --------------------------------------------------------------

      *((volatile ioport unsigned *)(0x0001)) = 0x000E;   // Enable periph clocks in idle control register

      asm("\tnop_16");                   // flush the pipeline

      asm("\tnop_16");      

      asm("\tnop_16");      

      asm("\tnop_16");      

      asm("\tnop_16");      

      asm("\tnop_16");      

      asm("\tidle");                     // execute IDLE instr to apply changes

    --------------------------------------------------------------

  • Glad to hear you fixed it!  How did you figure that one out?  Brute force comparison of registers?  Did you ever figure out how connecting with CCS made a difference, i.e. did you miss  a gel file or something?

    In any case, I'm glad to hear you fixed it.  Also, thank you for reporting back your solution.

    Best regards,
    Brad

     

  • Sorry, the fix was found in the user's guide for the DSP (sprufp0a.pdf) section 5.5, clock management.  It describes how to set the Idle control register.  I had read about the ICR a days or two ago, but didn't realize that the CSL didn't take care of that task when calling the _init routines of the various peripherals.  I don't know how feasible it would be to provide feedback in the return status when calling DMA_init that the DMA isn't getting a clock.  I sort of assumed when I got CSL_SOK back from all of those configuration routines that things were set up properly.

  • I'm glad Richard got his application running.  I have been 3/4 successful – part of my application runs automatically upon power-up (via boot-loading from NOR Flash on the C5515 ezDSP); part requires a restart via the emulator, but then does run OK.

     

    Here's my situation:

     

    Source data is input from I2S via continuously running (auto-reload) ping-pong DMA, initiated at startup.  I2S Input DMA interrupts trigger bursts of processing.

     

    Accumulated processing results are output to the UART via sporadically initiated (not auto-reload) DMA, pending the interrupt that occurred when the preceding UART output DMA transfer completed.

     

    This all runs as soon as the board is powered up and the application is loaded from NOR Flash by the boot loader and started.

     

    Input data is also copied to another buffer and sent back to I2S via continuously running (auto-reload) ping-pong DMA.  Each copy operation is initiated by the I2S Input DMA interrupt, pending the interrupt that occurred when the preceding I2S Output DMA transfer completed.  Outward-bound DMA is initiated when both banks of the copy buffer have been filled from input buffer.  (The two initial copy operations do not pend on the I2S Output DMA interrupt.)

     

    I2S Output does not work at power-up.  (There is a brief burst of noise at the output.) After Target->Connect Target, with a GEL file doctored to take no action, followed by Target->Run, it still fails, because it merely resumes execution where it was suspended upon connection.

     

    If symbols have been loaded from the corresponding .out file and Target->Connect is followed by Target->Restart (again, with no GEL activity), returning the PC to the entry point for my application, Target->Run results in fully functional operation.

     

    Similarly, if Target->Connect is followed by Target->Reset->CPU Reset, returning the PC to the boot loader in ROM, Target->Run causes boot loader to reload the application from Flash and start fresh, again with full functionality.

     

    Since my initialization code resets all peripherals, I’m puzzled as to why having run the code once, without success, would somehow set the stage to run it successfully the next time.  Does power-up reset involve a race condition with power supplies that leaves the DMA controller or the peripherals in an odd state?

     

    I have included the ICR + NOP + idle operations Richard cites in my initialization C code, along with clock generator and peripheral initialization, modeled after InitSystem() in USB_Stick_Sample\src\main.c (similar to Peripheral_Reset() and ProgramPLL_100MHz() in usbstk5515.gel).  I have also incorporated a customized version of csl_init\c5515_init.asm *, modified by me to run before _c_int00 in same manner as reset_isr in USB_Stick_Sample\asm\vector.asm.  (This duplicates some of the initialization procedures that occur later in my C code.)

    Any clues?

    Dan

     

    *  See Hyun Kim’s posting in: C5515 CSL - Is the Idle Control (ICR) and Idle Status (ISTR) defined in LOWPOWER CSL

    http://e2e.ti.com/support/dsp/tms320c5000_power-efficient_dsps/f/109/p/59334/212336.aspx#212336

     

  • D E Ungar,

    Here's a strategy to help you track down the dependency:

    1. Put some kind of spin-loop in your code such that at power-on it waits for you to connect and change the (volatile) variable to make it exit the spin loop and move on.
    2. Try putting a breakpoint somewhere "way down the line" in your code. Run to that breakpoint.  Restart and run.  (Should work correctly.)
    3. Now do a power-up again and repeat the procedure, but this time put the breakpoint a lot sooner.  Does it still fail?
    4. You want to keep repeating the procedure until you can pin-point the exact code that is required to execute in order for things to work correctly on the restart.  I assume you must have something configured in the wrong order on power-up.

    Best regards,
    Brad

  • An update:

    If I connect to target after power-up, when I hear no I2S audio out, and set breakpoints, I find that I am getting interrupts for I2S inbound and outbound DMA and my code is executing the copy to the outbound I2S buffer.  BUT, when the output is "silent," both the input and copy-buffer data differ from what I see when I hear proper audio via the I2S output.  I have not examined the UART output recently, since the wire I had tacked onto the PCB to pick up its output broke loose, but it appears that my problem is with the initialization of the codec or the I2S port configuration and, in the "silent" case I would surmise that I am also processing "silent" data and outputting its processed version through the UART.

    Since the data coming from the codec via I2S appears to be garabage, does anyone have any ideas why it would clean up upon re-executing my startup code via Target->Restart, Target->Run?

    Dan

     

  • Brad,

    Thanks for the spin-loop trick.  I will give it a try in the near future.  In the meantime, my resources have been redirected, much as I'd like to keep poking at this.  (Since I have to re-flash about 100KB via the XDS100 everytime I try this, it's a slow process.)

    Dan

     

  • OK, I'm getting clues, but still no joy.

     

    If I power up the 'C5515 ezDSP and allow my application to load from Flash and run, I get only a brief burst of noise out.

    • I then connect to target, load symbols, insert a breakpoint in my main DSP/BIOS task loop, run to it and record the PC.
    • I next put a breakpoint at the end of my aic3204 codec configuration routine, which I lifted wholesale from Spectrum Digital example project usbstk5515_BSL_RevA\usbstk5515_v1\tests\aic3204, force the PC to the start of the routine and run it.
    • Now I restore the PC to its previous value, disable the breakpoints and run.
    • Voila I get good sound.

     

    I therefore thought that perhaps the hot DSP was configuring the codec (via I2C) during  main()  before it was ready, so I added an arbitrary USBSTK5515_waitusec( 100000 ) from the usbstk5515 BSL (~100 mS wait loop) before doing so, but to no avail.

    I then also re-executed the codec configuration routine in my main DSP/BIOS task, immediately before entering my primary processing loop, but still got no recognizable sound.

     

    Then, I noticed that in the Digital Spectrum sample code the codec is initialized before the I2S peripheral.  I tried a single codec initialization early in the program (during  main() ), followed by I2S configuration some operations later, but still no good. 
    Finally, I added the ~100 mS wait back in before codec initialization; still no good.

    I was still able to get each of these configurations to work by breaking in and re-running codec configuration via the emulator.

     

    Any thoughts?

  • Well, another good hypothesis shot down:

    I noticed that the Digital Spectrum aic3204 example code calls BSL function USBSTK5515_I2C_init( ) before configuring the codec via the I2C peripheral, so I did so also, but it made no difference.

    Breaking in and re-executing the codec configuration after the code has loaded from Flash and is running still works, with or without USBSTK5515_I2C_init( ).

  • BRUTE FORCE TO THE RESCUE!

    In my main DSP/BIOS task, I added code to count out enough iterations of my processing loop for 2 seconds to pass, then I re-execute configuration of the AIC3204 codec (via I2C).

    Voila!  When I plug in the 'C5515 ezDSP, I hear

    • 1.0 second of silence (board power-up + some of my initialization code), then a
    • 1.8 second burst of scratching and hiss that fades away (probably in response to the first time I configure the codec), followed by
    • 0.6 second of near silence (while my loop counter continues to run), then
    • good sound!

    It would seem that the DSP's LDO's are powering up its core and starting it up several seconds before the AIC3204 is ready to deal with instructions from it.

    Dan

     

  • I'm glad to see you're narrowing down the issue!

    D E Ungar said:
    It would seem that the DSP's LDO's are powering up its core and starting it up several seconds before the AIC3204 is ready to deal with instructions from it.

    In that case I expect an equivalent workaound would be to simply add a 2 second delay loop to the start of your program.  Does that also work?

  • Brad Griffis said:

    In that case I expect an equivalent workaound would be to simply add a 2 second delay loop to the start of your program.  Does that also work?

     

     

    It didn't work when I tried it yesterday, but I am hearing noise out of the codec 2.45 seconds after I plug in the board, so maybe a 3 second delay at the beginning would hit the spot.  I'll try it later.

    Thanks for offering your help.

    Dan

  • Dear Dan, I am again!!!!

     

    Thanks for help, you are correct about my entry point, in my case the Build Properties… -> CCS Build -> Dependencies was cslV5505 project where my vectors.asm was. I did a copy of vectors.asm to my project folder and disable the dependence with cslV5505 and the error disappears.

     

    http://e2e.ti.com/support/dsp/tms320c5000_power-efficient_dsps/f/109/p/53200/372229.aspx#372229

     

    I succeed record my big .bin file to nor_flash, thanks again but I still with problems.

     

    My application is an audio recorder where sound comes from Codec via I2S that trigger a DMA with ping/pong mode. When ping/pong interrupt occur I storage the ping or pong array (1024 bytes each) in a big array of 16384 bytes (auto-reload). When 16384 bytes are available I record these data to SD card and so on. To start and finish the last part of process (record to SD) I am using the leds and switches found at C5515 ezDSP.

     

    Similar you, I am using the example called aic3204 from Spectrum Digital to initialize and configure the Codec and I think that this part is neither working when I put the code on nor flash. According your post, a delay solves this question. I put a wait of 5 seconds according bellow but the signal still strange.

     

    void main(void)

    {

     

    InitSystem(); // configura PLL, habilita todos os

                  // clock´s e reseta periféricos

        ConfigPort(); // Configura barramento

        SYS_GlobalIntEnable(); // Habilita as interrupções

    IER0 = 0x0000; // Habilita interrupções específicas

        IER1 = 0x0000; // Habilita interrupções específicas

        Init_SAR(); // Inicializa ADC

        gpio_output_pin_test(); // Inicializa GPIO

        USBSTK5515_ULED_init(); // Inicializa Leds

         USBSTK5515_wait(5000); // Espera 5 segundos

         USBSTK5515_I2C_init(); // Inicializa I2C

         aic3204_test(); // Inicializa Codec

         config_DMA_I2S(); // Configura DMA

    mmcFileTest(); // Configura SD

    }

     

    Other thing, my ping/pong interrupt is happing because I put GPIO12 high and low on DMA interruption to watch signals with a digital oscilloscope. The signal is very similar when I run via .gel file.

     

    If ping/pong is happing, could I suppose that my DMA configuration after boot-loader is correct? It is because when I run after boot the elapsed SD writes increase more than 3 times (GPIO13 with oscilloscope) and continues to grow until it stops. I put the idle delay to DMA at vectors.asm according Rafael’s post.

    Thanks for help!!!

  • Andrea,

    I wrote a wiki page to give tips related to debugging these sorts of boot issues:

    http://processors.wiki.ti.com/index.php/Debugging_Boot_Issues

    Please use the techniques discussed there as a starting point.  Let us know what you find.  I suspect something being configured in your gel file needs to be moved into  your code.

    Brad

  • Hi Andrea,

    I am glad you are making progress.  I am currently working on other aspects of my project and on other projects, so my new DSP development skills are already getting a bit rusty.  I have been teaching myself by trial and error, so this forum is helpful for both learning and sharing what I have learned.

    Your information about Build Properties… -> CCS Build -> Dependencies  is interesting - I didn't know there was such a setting.  When I examine my own projects, it appears that the entries under this tab reflect whichever projects I have checked under Project -> Properties -> Project References.  In fact, clicking the Add.. button under Dependencies brings up the same checklist as under Project References (but in a different order).  (I don't know why they have the same setting appear in two different places.)  I have observed that if I completely rebuild a project that has another project checked under Project References - usually a library - then the referenced project also seems to get rebuilt.  I am guessing that that is the purpose of those entries - to ensure that the referenced project's build is up to date.

    The Dependencies entries do not appear to cause any files in the referenced project to be included when building (compiling and linking) the currently active project, however.  Actually including specific header files and compiled objects from other projects is controlled by the setting Properties -> C/C++ Build -> C5500 Compiler -> Include Options (direct the compiler where to search for header files) and C5500 Linker -> File Search Path (direct the linker which object and library files to include and where to search for them).

    Of course, if you are modifying a source file for your own use, it is best to copy it into your project directory, as you did.

    Dan


  • Hi Dan, unfortunatelly the configuration of projects is not trivial :(

    Please let me know, where exactly did you put the USBSTK5515_wait() function? where before the audio codec? My attempts

    are not working (last post).

    Thank you,

    Andrea

  • Hi Andrea,

    I don't actually use a USBSTK5515_WAIT( ) function.  My code is a bit complicated because I use DSP/BIOS to coordinate different parts of my code with interrupts.

    My code first calls aic3204_config() from main( ), but that by itself was not sufficient because it seems that the aic3204 is not yet ready to be configured at this time.

    After main( ) completes, DSP/BIOS performs some further initialization, then runs my background task audio_proc( )audio_proc( ) contains a repeating loop that waits for a semaphore to be set by an interrupt service routine after DMA from the aic3204 has filled half of my input ping-pong buffer.  Each time a ping-pong buffer bank has been filled (one frame of 1024 samples), this loop performs some audio processing for me.  It also counts how many times the loop has executed.  After a certain number of iterations, I call aic3204_config( ) a second time - just once.  After that, I seem to get good audio from the aic3204.  This extra delay amounts to about two seconds plus whatever time DSP/BIOS intialization takes after main( ) has finished.

    So, I am timing the delay to the second time I call aic3204_config() by counting the number of times DMA has filled half the input ping-pong buffer.  This was just done as an experiment.  Before I tryed using the loop counting approach I just described, I used USBSTK5515_waitusec( 2000000 ) before aic3204_config( ) in main( ) and it was not enough delay.  Because I was diverted to other projects, I have not had the time to try longer delays in main( ), but I suspect that lengthening that delay to 4 or 5 seconds might work.

    Good luck,

    Dan

  • To all of you who are experiencing this problem, I have also done a brute force fix that works for me. I initialize the AIC3204, wait 2 seconds, the re-initialize the AIC3204. This works! For some reason the AIC is not getting properly initialized on the first pass. I hope someone comes up with the actual problem instead of having to resort to brute force.

  • Hi Mike,


    Sorry to bring up an old thread but do you still have the source for your codec initialization? I have a similar problem where everything works in debug but will hang on a codec read when running standalone (have confirmed this with debugging when running standalone). I just wanted to take a look at exactly how you initialize your codec to see if there were any differences.

    Thanks in advance,

    James