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.

boot_usb problem on custom board, CCSv5.4, XDS100v2

Other Parts Discussed in Thread: TM4C1236H6PM

Hi all,

I've got a TM4C1236H6PM on a custom board and I'm at the stage where I want USB DFU capability. I'm using CCS 5.4 and debugging with an XDS100v2. I've imported the boot_usb example and changed the part definition, when I debug it starts at the point in bl_startup.css.s:

.thumbfunc _c_int00
.global _c_int00
_c_int00: .asmfunc
b ResetISR

But doesn't branch to ResetISR and appears to step to the next assembly instruction which varies depending on optimization settings. The assembly with optimization off around that part looks like this:

   626 b ResetISR
_c_int00:
20000afa: F00101FF    AND.W R1, R1, #255
   483 {
20000afe:  F000F92B   BL          0x20000D58
20000b02: 9002            STR       R0, [SP, #0x8]
20000b04: 9802            LDR       R0, [SP, #0x8]
20000b06: F1B03FFF  CMP.W  R0, #4294967295
20000b0a: D102           BNE       0x20000B12
20000b0c: F000FEB6  BL          0x2000187C
20000b10: E01C           B            0x20000B4C

Shouldn't that AND.W instruction be a branch one? The branch instruction at 0x20000afe branches from USBConfigurePins to HandleSetAddress. The assembly doesn't seem to match what the code is asking, is there something wrong with the compiler settings? Should the code be in 0x2000XXXX space from the start of debug?

  • Kieran,

    Sorry for the slow response.  I just got around to looking at your post this AM and, unfortunately, the answer is ridiculously complicated and there's a few IDE bugs at play (as far as I can tell) just to keep it interesting.

    The easiest way to explain it is to start with a "typical" application that runs from flash and build up through scenarios where code is relocated to SRAM all the while keeping tabs on what the debugger (incorrectly) thinks it needs to do.

    First, you need to have an understanding of how Cortex comes out of reset.  By convention the CPU loads the SP from 0x0 and the address of the reset vector at 0x4.  These two values go straight into SP and PC respectively.  Once the PC has its new value, you've branched and you're on your way.

    Second, a bit of convention from TivaWare.  The reset exception handler is always called ResetISR.  So if you look at 0x4 of flash it will always point to the address of ResetISR.  You should take a few minutes to flash a few non-boot-loader apps, look at the map file, look at a memory dump of flash, and correlate that with the debugger's idea of ResetISR and the behavior of the core immediately after a system reset.  (Note the little drop-down arrow next to the 8 pin DIP icon in the debugger tool-bar?  Click that and note that you have a "core reset" and a "system reset" option.  I always recommend the use of System Reset).  Another thing to keep in mind about TivaWare is that we strive to maintain feature parity across toolchains.  So if toolchain XYZ has some whiz-bang feature we won't take advantage of it unless every toolchain can do it.

    Next, the entry point for TI's C runtime initialization is a function called _c_int00.  I think this stems from other architectures where int00 (interrupt 0) is the reset vector.  A bit of a misnomer on a Cortex but... whatever. Application developers typically consider main() to be the entry point of their code but there is usually some bit of code that runs before main() is called.  This code is responsible for zeroing out pieces of RAM that are supposed to be zero and copying/uncompressing a chunk of data to fill non-zero data.  For example:


    uint32_t g_ui32Foo = 0;  // This is part of the
                             // zero-init section aka BSS section

    uint32_t g_ui32Bar;      // This is ZI too because ANSI C says
                             // uninitialized defaults to 0.  This is .BSS

    float g_fPi = 3.14f;     // This is .DATA

    Not only do data sections get initialized there are also scenarios in which code is loaded in one place and copied to another before it runs.  The TI C runtime would normally take responsibility for this relocation.  If you look at your bl_link_usb.cmd you can see the 'load' and 'run' directives at play.

    Ok.  Enough background.  Lets get to it.

    Scenario 1:  Execute from flash, data in SRAM (the "typical" thing to do)
    0x0 gets your initial SP
    0x4 points to address of ResetISR.  ResetISR() branches to _c_int00().
    _c_int00() initializes data sections and branches to main().
    Debugger writes program to Flash, sets PC to _c_int00() because that's where the entry point is.

    Scenario 2:Execute most of application from Flash except one function (call it foo()) which runs from SRAM (perhaps for performance reasons).   In this case we use a #pragma to put the desired function into a different section.  Then we tweak the linker script so that the section is load(FLASH) and run(SRAM).  This also clues the C runtime into the fact that it has to copy a code chunk at init time.
    Similar to scenario 1 except _c_int00() also copies foo() from FLASH to SRAM.  Note that the compiler and linker generated all branches to the SRAM version of foo().
    The debugger writes the program to Flash, sets the PC to _c_int00() because that's where the entry point is.

    Scenario 3: A boot loader -- you can't execute from flash while reprogramming it.  Note that the entire .TEXT section is set to SRAM -- no code (.TEXT section) is left running from FLASH.  But it should be apparent by now that a piece of code must run from FLASH to initialize SRAM before branching there.  

    Check out bl_startup_ccs.s.   Look at the vector table and notice that 0x2000.0000 is subtracted from ResetISR and a few other vectors.  So, per the map file, ResetISR is in SRAM but the vector table is correct (The address of ResetISR is hacked to be in Flash by subtracting 0x2000.0000).  Prove this to yourself with a memory dump.  ResetISR, in this case, does NOT call _c_int00().  We take care of the init "ourselves" (we == "TivaWare" as opposed to relying on the C runtime).  So we're executing from FLASH ('cuz we hacked the vector table), running ResetISR, encounter the branch to ProcessorInit() which we get away with because it's resolved locally (same assembly file) and a PC-relative jump is generated.  Prove this to yourself as well by looking at the disassembly.  After the copy we OR in 0x2000.0000 to the Link Register so we branch to SRAM when we return from the copy loop and <hand-waving/> it all works great, right?

    No?  The problem is with the debugger.  

    The debugger assumes _c_int00() is the entry point.  And lo' there's a _c_int00() in bl_startup_ccs.s which is there to make the linker happy.  But we told the linker to place all of .TEXT in SRAM.  So what's the address of _c_int00()?  Mine is at 0x2000.0532 which isn't initialized yet.  So single-stepping from _c_int00() is not going to work.  If you do a core or system reset you should see the PC is set at 0x4e0 (should be 0x4e1 but the debugger can't seem to display a '1' in bit 0).

    Ok, so we'll just set a breakpoint on the 'bl CheckForceUpdate' instruction in SRAM, right (around 0x2000.04F4)?   BUT the debugger is insisting on setting a software breakpoint in SRAM which will be over-written in the copy loop.  So we have to set a BP at the instruction where we OR in 0x2000.0000 to LR (in ProcessorInit).  Then we single step through the 'bx  lr' .  NOW that we're executing from SRAM all the symbols and debug information are correct so you can start using the debugger normally now (including the use of software breakpoints).

    Does that help?

    --Miles

  • Hi Miles,

    Very detailed response! I understand the debugging process of the bl much better. So I should ignore the 'Restart' button at the start, as this will take me to _c_int00 which isn't actually there?

    Using system reset takes me to 0xaac which appears to make sense as ResetISR is listed as 0x20000aad in the .map file. It says there is no source for the assembly there, presumably because it thinks all the source is in the SRAM space? If left to run, the code gets stuck at 0xae4 which is listed as 'undefined', which I think is just before the flash space for Delay (0x20000ae9 in map) and _c_int00 (0x20000aef in map). 

    I presume this has something to do with the FaultISR as the 'Forced Hard Fault' bit is set at this point and the Configurable Fault Status register has 'Instruction Access Violation' set. So an attempt has been made to execute from a region it shouldn't have, but all Flash and SRAM space is set as executable, would it have tried to execute from another address? Perhaps there is something wrong with my port from the DK example, I'll take another look at the bl_config and other parts.

    Kieran

  • ENABLE_BL_UPDATE wasn't set! I've now successfully loaded application firmware via LM Flash Programmer. Thanks for the help Miles.

    Kieran