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.

TM4C123GH6PM: Invoke ROM_UpdateUART programmatically

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: ENERGIA, EK-TM4C123GXL

I have an app that can invoke the ROM_UpdateUART() programmatically in order to do firmware updates.  We can load new firmware using LMFlash, sflash, and our own PC-side loader code, except that after loading the new firmware, we must do a manual reset to get it started properly.  So for example, if we run LMFlash with the -reset parameter, the app seems to hang and I am trying to figure out why the hard reset is required.

Following the recommendations in TivaWare Bootloader spmu301e, we use UART0 (15200, 8-N-1) in our app, and we have tried multiple ways to disable processor interrupts, but still the hard reset is necessary. 

1.  Is there a recommended code example to prepare the app for a call to ROM_UpdateUart()?  

2.  I am wondering if the issue is that the app's bin file is built with Energia?   (The app loads and starts as expected in Energia, but it is loading via the ICDI).

  • Hi,

      There is an example at C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl\boot_demo_uart_rom. Please take a look. 

      Although I'm not familiar with Energia, I don't think the problem is due to Energia. If you have doubt, why don't you build your project in CCS and try again. Please note that we don't support Energia per FAQ #4 https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/695568/faq-faqs-for-tm4c-arm-cortex-m4f-microcontrollers.

  • Thank you for your reply.   Working with the boot_demo_uart_rom project on a EK-TM4C123GXL LaunchPad, with UART0 lines from the debug uC cut, and using FTDI USB-serial bridge tied to UART0.

    1.  WIth our firmware running, I send a command to programmatically invoke the ROM bootloader, and I can successfully use sflash to load boot_demo_uart_rom.CCS.bin (my renaming).  However boot_demo_uart_rom does not blink until I hit the reset button, and then it functions as expected.

    2.  Now with boot_demo_uart_rom firmware running, I hit SW1 and flashing stops as expected, presumably configured and running ROM_UpdateUART().

    3.   Attempt to load boot_demo_uart_rom.CCS.bin again using sflash:

    sflash boot_demo_uart_rom.CCS.bin -r 0x00000000 -s 60 -d -b 115200 -c 9

    which is successful, and LED is flashing green as expected.

    4.   Attempt to load our simple LED flashing app, after hitting SW1 to launch ROM_UpdateUART().  The load is successful, but the LED is stuck on, and only after hitting the reset button does the LED start flashing as expected.

    So I am still puzzled as to why we need to hit reset after a successful load in order for the firmware to start up correctly?

  • Also, I can appreciate and respect that you cannot support Energia, but just saying that this is and Energia project imported into CCS.

  • Hi John,

    2.  Now with boot_demo_uart_rom firmware running, I hit SW1 and flashing stops as expected, presumably configured and running ROM_UpdateUART().

    3.   Attempt to load boot_demo_uart_rom.CCS.bin again using sflash:

    sflash boot_demo_uart_rom.CCS.bin -r 0x00000000 -s 60 -d -b 115200 -c 9

      I just tried exactly the same using sflash.exe and I can repeatedly load the boot_demo_uart_rom  firmware after hitting SW1 after which ROM_UpdateUART() is jumped to. Once programmed, the LED will blink without the need of a hard reset.

    4.   Attempt to load our simple LED flashing app, after hitting SW1 to launch ROM_UpdateUART().  The load is successful, but the LED is stuck on, and only after hitting the reset button does the LED start flashing as expected.

    Was the LED first turned off after you hit SW1 like the example? I want to know if the LED was stuck on after you hit SW1 or the firmware was programmed again and executed but somehow the LED got stuck. I don't think it is likely the second case but please check. The second case means the program was run but the LED was not stuck for a different reason. 

      Can you compare your code with the example boot_demo_uart_rom? Perhaps replicate your own firmware piece by piece to mimic the example one at time to see what portion of the code makes a difference. 

  • Thanks for your reply.    Here are the test results, where in Test 2 I need to hit reset after load in order for my app:

    Test 1:  Start by loading boot_demo_uart_rom in CCS.   Hit SW1.  Load same boot_demo_uart_rom using sflash loads successfully and starts normally after load (green LED is flashing).

    Test 2:  Start by loading boot_demo_uart_rom in CCS.   Hit SW1.  Load my Energia LED flash app using sflash loads successfully but does not start normally after load as there is no *red* LED flashing, it is steady ON.    Hit Reset on the LaunchPad and red LED starts flashing which is my app executing normally.

    Test 3:  Start by loading my Energia LED flash app in CCS.  Starts normally with red LED flashing.  Enter the ROM bootloader programmatically by sending command over UART0.   Load boot_demo_uart_rom using sflash loads successfully and starts normally after load (green LED is flashing).  

    I will take your suggestion of modifying my Energia LED flash app to mimic boot_demo_uart_rom,    Here are some differences between the two:

    1.  My app uses UART0 to send commands/data and it is configured by Energia for 115200, 8-N-1 and it is not reconfigured before calling ROM_UpdateUART().

    2.  My app is Energia app imported into CCS and uses Energia-supplied startup code and linker control file.   

    3.  My app uses different code to disable interrupts before entering the ROM bootloader:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    ROM_IntMasterDisable();
    long i;
    while(ROM_UARTCharsAvail(UART0_BASE)) // flush serial before entering bootloader
    i = ROM_UARTCharGetNonBlocking(UART0_BASE);
    ROM_IntDisable(INT_GPIOA);
    ROM_IntDisable(INT_GPIOB);
    ROM_IntDisable(INT_GPIOC);
    ROM_IntDisable(INT_GPIOD);
    ROM_IntDisable(INT_GPIOE);
    ROM_IntDisable(INT_GPIOF);
    ROM_IntDisable(INT_UART0);
    ROM_IntDisable(INT_UART1);
    ROM_IntDisable(INT_TIMER0A);
    ROM_IntDisable(INT_TIMER0B);
    ROM_IntDisable(INT_TIMER1A);
    ROM_IntDisable(INT_TIMER1B);
    ROM_IntDisable(INT_TIMER2A);
    ROM_IntDisable(INT_TIMER2B);
    ROM_IntDisable(INT_TIMER3A);
    ROM_IntDisable(INT_TIMER3B);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  • First change to my LED blink code is to un-configure UART0 used in my app, then call ConfigureUART() from boot_demo_uart_rom before invoking the bootloader.    Test:  Start by loading boot_demo_uart_rom in CCS.   Hit SW1.  Load my Energia LED flash app using sflash loads successfully but does not start normally after load as there is no *red* LED flashing, it is steady OFF.    Back in CCS see that debug is stopped at abort():

      Hit Reset on the LaunchPad and red LED starts flashing which is my app executing normally.

    So I am using sflash to communicate and load with ROM bootloader, e.g.:

    sflash BlinkSerial.CCS.bin -r 0x00000000 -s 60 -d -b 115200 -c 6

    I am a bit unclear about the -r 0x00000000 parameter which sflash help explains is the "execution address"  and in the bootloader protocol sends a run command with this value.  Is it true that this should be the start of the vector table?   I think the ROM bootloader examines this location to see if it contains a valid stack pointer value and ResetISR vector, correct?   Then jumps to ResetISR vector?  In my code this is the vector table:

  • Hi John,

      Can you show your Energia main() function? The abort() in your call log capture could be the results of two things I can think of:

      1. The function main() runs out of things to do.  It then goes off to exit(). Try to add a while(1) at the end of your main() function so that the processor always has code to execute. 

      2. If it is not the reason of above then you may have a memory issue. Try to increase the heap size and stack size to some larger values (e.g. 4096 for heap and 1024 for stack) and see if that makes a difference. Once working, you can adjust the heap and stack to the needed value. 

      

  • The flow in the Energia app is that ResetISR does some init and then calls main() which is an infinite loop. 

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(void)
    {
    setup();
    for (;;) {
    loop();
    if (serialEventRun) serialEventRun();
    }
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    It's not so clear about the stack and heap.   There's no obvious directive in the project settings, linker invocation, or linker command file to explicitly set the stack and heap sizes.    The GCC linker control file apparently locates the stack and heap following the .bss section and uses all unallocated RAM: 

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    *
    * lm4fcpp.ld - Linker configuration file for Energia c++ programs.
    *
    */
    MEMORY
    {
    flash (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
    }
    /* STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : 0x800 ; */
    REGION_ALIAS("REGION_TEXT", flash);
    REGION_ALIAS("REGION_RAM", ram);
    SECTIONS
    {
    .text :
    {
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    and the map file apparently shows that space to be from 0x200000460 to 0x20008000.   (Sorry for my GCC ignorance)

    .bss.__malloc_sbrk_start
    0x2000044c 0x4 c:/users/jwygonski/appdata/local/energia15/packages/energia/tools/arm-none-eabi-gcc/8.3.1-20190703/bin/../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-nano-mallocr.o)
    0x2000044c __malloc_sbrk_start
    *(COMMON)
    COMMON 0x20000450 0x4 c:/users/jwygonski/appdata/local/energia15/packages/energia/tools/arm-none-eabi-gcc/8.3.1-20190703/bin/../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-reent.o)
    0x20000450 errno
    COMMON 0x20000454 0x9 c:/users/jwygonski/appdata/local/energia15/packages/energia/tools/arm-none-eabi-gcc/8.3.1-20190703/bin/../lib/gcc/arm-none-eabi/8.3.1/../../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard\libc_nano.a(lib_a-lock.o)
    0x20000454 __lock___atexit_recursive_mutex
    0x20000455 __lock___arc4random_mutex
    0x20000456 __lock___env_recursive_mutex
    0x20000457 __lock___sinit_recursive_mutex
    0x20000458 __lock___malloc_recursive_mutex
    0x20000459 __lock___at_quick_exit_mutex
    0x2000045a __lock___dd_hash_mutex
    0x2000045b __lock___tz_mutex
    0x2000045c __lock___sfp_recursive_mutex
    0x20000460 . = ALIGN (0x4)
    *fill* 0x2000045d 0x3
    0x20000460 _ebss = .
    0x20000460 . = ALIGN (0x8)
    [!provide] PROVIDE (__exidx_start = .)

    .ARM.exidx
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    [!provide] PROVIDE (__exidx_end = .)
    0x20000460 . = ALIGN (0x4)
    0x20000460 _end = .
    0x20000460 PROVIDE (end = _end)
    0x20008000 PROVIDE (_estack = (ORIGIN (ram) + LENGTH (ram)))

    (Sorry tried to paste the above as formatted code but got an error:)

  • Hi,

      Sorry, I'm not familiar with and can't support Energia as I mentioned in the beginning.  I thought you imported Energia app into CCS and rebuild the project. If that is the case,  you can change the stack and heap in CCS. This will only work if your problem is related to heap and stack. I do have some doubt that it will make a difference. The reason is that you said if you do a hardware reset then the app will work. If there is a memory issue, I will suppose you can run into the issue after a hardware reset. Please also consult with https://forum.43oh.com/forum/119-energia/ on how to change the heap and stack in Energia. 

      

     Is there a strong reason that you cannot develop your application in CCS directly? 

  • Thanks for your reply and I totally understand TI's position on Energia.  I did import the Energia project into CCS v9.3 (and needed to apply a fix in settings having to do with floating point)  When I looked in the usual spot for setting stack size in the project properties, it is not there:

    Noting also that the project is using the GCC toolset, different from your screenshot.  I did reach out the other day to the forum you referenced, but sadly, but not unexpectedly, no reply yet. 

    So to your question--the client chose (against my strong recommendations to use CCS) to use Energia.  I have struggled with Energia-based projects for some time also with MSP430, so the many reasons *not* to use it include direct experience.   Sadly, these are the cards dealt, but I will try not to ask you about  my imported Energia project.  I will take your sound advice to slowly migrate my Energia project toward boot_demo_uart_rom.

    But as I have tried to debug this, can I get some clarification on what the ROM bootloader does with the run packet from sflash if the command line argument is "-r 0x00000000"?  This is clearly not the entry point of the program.  And what is the purpose of the -p option?   Thought this might be germane since my app does not start properly but is loaded successfully. 

  • But as I have tried to debug this, can I get some clarification on what the ROM bootloader does with the run packet from sflash if the command line argument is "-r 0x00000000"?  This is clearly not the entry point of the program.  And what is the purpose of the -p option?   Thought this might be germane since my app does not start properly but is loaded successfully. 

    Hi John,

      The -r specifies the address at which to start processor execution. The 0x0 address is the stack pointer and the 0x4 is the reset vector. Maybe you want to try to remove the -r so that the processor is reset after the firmware is downloaded. 

      The -p specifies the address at which to program your firmware. If you don't specify -p then it is default to 0x0 meaning the firmware is programmed to flash starting at address 0x0. 

    Why don't you try to load your firmware using JTAG instead of the ROM bootloader. Do you see the problem (e.g. LED got stuck) you are seeing?

  • I can load and run my imported project fine in CCS.  After loading it in CCS, it is pointing to ResetISR (I disabled the Run to main() option) ResetISR does initialization and then lastly calls main().  Ran my code many time this way and it always executed properly.   Only when same program is loaded by sflash while the LaunchPad is in the ROM bootloader (activated by SW1 press in boot_demo_uart_rom) does it fail to start properly, requiring a reset.   I have been invoking sflash with:

    sflash BlinkSerial.CCS.bin -r 0x00000000 -s 60 -d -b 115200 -c 6

    and I also tried 

    sflash BlinkSerial.CCS.bin -r 0x00000308 -s 60 -d -b 115200 -c 6

    where 0x00000308 is the address of ResetISR.

    Here is sample output:

    sflash BlinkSerial.CCS.bin -r 0x00000308 -s 60 -d -b 115200 -c 6

    Application : BlinkSerial.CCS.bin
    Program Address: 0x0
    COM Port: \\.\COM6
    Baud Rate: 115200
    Erasing Flash:
    Remaining Bytes: 00000000
    Running from address 00000308
    Successfully downloaded to device.

    And the red LED comes on but unexpectedly does not blink.  Press reset button and program restarts and red LED is blinking. 

    Tried your suggestion of leaving out the -r command line argument which worked!   sflash output:

    sflash BlinkSerial.CCS.bin -s 60 -d -b 115200 -c 6

    Application : BlinkSerial.CCS.bin
    Program Address: 0x0
    COM Port: \\.\COM6
    Baud Rate: 115200
    Erasing Flash:
    Remaining Bytes: 00000000
    Successfully downloaded to device.

    Begs the question, what does it mean "that the processor is reset after the firmware is downloaded"?  Is there a way for the ROM bootloader to programmatically cause the equivalent of a hardware reset?

    This success is with a totally stripped-down version of my app, so now I will restore the stripped code and try again.

  • Here is sample output:

    sflash BlinkSerial.CCS.bin -r 0x00000308 -s 60 -d -b 115200 -c 6

    Application : BlinkSerial.CCS.bin
    Program Address: 0x0
    COM Port: \\.\COM6
    Baud Rate: 115200
    Erasing Flash:
    Remaining Bytes: 00000000
    Running from address 00000308
    Successfully downloaded to device.

    And the red LED comes on but unexpectedly does not blink.  Press reset button and program restarts and red LED is blinking. 

    Hi John,

      Your BlinkSerial.CCS.bin project was built with the vector table starting at 0x0. Please refer back to the linker command file you presented before. You must therefore load and program your firmware at 0x0. You cannot used -r 0x00000308 as it will not run.  Normally, you will specify a non 0x0 address if you have the flash-based bootloader residing at 0x0 and your firmware will start at a flash page boundary such as 0x2800. Since you are using the ROM bootloader to load your code then you should specify -r 0x00000000. When the flash is empty, the ROM bootloader will scan for the available interfaces (e.g. among UART0, SSI0, I2C2, USB and Ethernet) to download the image. Please refer to the Bootloader user's guide for detail.  However, I still don't understand with -r 0x000000308, how can it still work after you do a hard reset. The reason is that the vector table at address 0x0 will be empty. After reset, the processor will look for the stack pointer and reset vector at 0x0 and 0x4 and will not find anything. Can you open the memory window and look at 0x0 and 0x4 and what is there?  

    Tried your suggestion of leaving out the -r command line argument which worked!   sflash output:

    sflash BlinkSerial.CCS.bin -s 60 -d -b 115200 -c 6

    Application : BlinkSerial.CCS.bin
    Program Address: 0x0
    COM Port: \\.\COM6
    Baud Rate: 115200
    Erasing Flash:
    Remaining Bytes: 00000000
    Successfully downloaded to device.

    Glad that it is working. Without -r specified, it will program the code starting at 0x0 by default and after programming it will reset the processor.  This is the correct way to load your firmware when the flash is empty and you are using the ROM bootloader to load your code. 

    Begs the question, what does it mean "that the processor is reset after the firmware is downloaded"?  Is there a way for the ROM bootloader to programmatically cause the equivalent of a hardware reset?

    I think the ROM bootloader generates a software system reset by calling the SysCtlReset(). Look at the SYSRESREQ bit in the APINT register in the datasheet for detail.  The TivaWare SDK provides the API SysCtlReset() to cause a system reset. I'm not sure how to do that in Energia if you want to generate software system reset for your application in the future. Without the API, you can still write to the SYSRESREQ bit in APINT register.  The APINT register is at address 0xE000ED0C.

  • Hi Charles,

    After loading in CCS, my Energia program has the stack pointer value at 0x00000000 followed by the address of ResetISR.  When I run the loaded program in CCS, ResetISR is first to be executed.     Now the sflash help says "-r [execution address] if address is not specified then no run command will be sent", so it made perfect sense to me that I should specify "-r [address of ResetISR]" as command-line argument.   So thanks for clearing this up and getting me on the right track.  

    But it's still a question why the "-r [address of ResetISR]" resulted in my code not starting properly?   Perhaps it's because some interrupt is still pending when the ROM bootloader is invoked and then fires when my just-loaded code enables interrupts?  And SysCtlReset() will reset the core and peripherals so that's why it works with my app.  Anyway it's a moot point now as I will not specify the run argument.  

    As far as where the code is located when loaded by sflash, is it not the case that it is the "-p" arg that specifies this?   I did not specify "-p", so per the sflash help "if address is not specified it is assumed to be 0x00000000".

    With this info, I will go back and modify my C# loader program (based on sflash code) that interacts with the ROM bootloader to send a COMMAND_RESET packet instead of a COMMAND_RUN packet and it should work now.   I'll let you know.

  • I have moved from working with my Energia LED blink app to our production firmware (Energia) project imported into CCS.  Code to invoke the ROM bootloader is invoked, and it is ending up in FaultISR() after executing code to disable interrupts:

    Fullscreen
    1
    2
    HWREG(NVIC_DIS0_R) = 0xFFFFFFFF;
    HWREG(NVIC_DIS1_R) = 0xFFFFFFFF;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    This indicates a Hard Fault, but I am not sure why it occurred or how to debug.

    Do you have any guidance as to how to proceed?

  • Thought I would close out this post to document how it got resolved.   As suggested earlier, the problem was not caused by the Energia environment.   

    I discovered a useful document containing practical info on diagnosing TivaC faults:  Following the tutorial http://www.ti.com/lit/an/spma043/spma043.pdf , I found that the hard fault was triggering at disabling interrupts before calling the ROM_UpdateUART().  So I replaced the offending code:

    Fullscreen
    1
    2
    HWREG(NVIC_DIS0_R) = 0xFFFFFFFF;
    HWREG(NVIC_DIS1_R) = 0xFFFFFFFF;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    with roughly equivalent (I think):

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ROM_IntDisable(INT_GPIOA);
    ROM_IntDisable(INT_GPIOB);
    ROM_IntDisable(INT_GPIOC);
    ROM_IntDisable(INT_GPIOD);
    ROM_IntDisable(INT_GPIOE);
    ROM_IntDisable(INT_GPIOF);
    ROM_IntDisable(INT_UART0);
    ROM_IntDisable(INT_UART1);
    ROM_IntDisable(INT_TIMER0A);
    ROM_IntDisable(INT_TIMER0B);
    ROM_IntDisable(INT_TIMER1A);
    ROM_IntDisable(INT_TIMER1B);
    ROM_IntDisable(INT_TIMER2A);
    ROM_IntDisable(INT_TIMER2B);
    ROM_IntDisable(INT_TIMER3A);
    ROM_IntDisable(INT_TIMER3B);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    And this cleared up the hard fault issue, but revealed a second problem where my code ended up in the IntDefaultHandler.   So explicitly clearing and disabling the interrupt for timer 1A that I used in the app solved the problem:

    Fullscreen
    1
    2
    3
    4
    ROM_TimerIntDisable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
    ROM_TimerDisable(TIMER1_BASE, TIMER_A);
    ROM_IntPendClear(INT_TIMER1A);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    The last addition to the loader code was to disable the SysTick timer explicitly:

    Fullscreen
    1
    2
    ROM_SysTickIntDisable();
    HWREG(NVIC_INT_CTRL) |= NVIC_INT_CTRL_PENDSTCLR;
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    So now my loader is able to update my firmware and restart properly without requiring a reset/power cycle.    What is still somewhat puzzling to me is why it was not sufficient to simply disable all processor interrupts (as recommended in the TivaWare Bootloader UG (SPMU301E) section 2 on ROM Bootloader.  At first I tried

    ROM_IntMasterDisable();

    to prevent interrupts during ROM_UpdateUART().   But this was not sufficient, even though the ROM bootloader later invokes SysCtlReset() --perhaps I was mistaken in thinking that SysCtlReset() disabled and cleared all interrupts. 

    Charles, thanks for the support.  

  • Hi John,

      Really glad that your problem is solved. I will bookmark this post so that I can refer to others for the same issue in the future. Normally, there is no need to individually disable each interrupt one by one. As to why doing in parallel will cause a hard fault is still a mystery to me since the TivaWare example as it is didn't experience the issue.