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.

TM4C123GH6PGE: How to setup the bootloader and comms the right way?

Part Number: TM4C123GH6PGE
Other Parts Discussed in Thread: EK-TM4C123GXL

I like to go to bootloader mode and do a firmware update.
So far I failed when doing the sync (send 0x55,0x55)


I wrote a small python script, that tries to connect and do the dfu.

2021-09-24 10:51:14.657 DEBUG:	open uart /dev/ttyUSB0
2021-09-24 10:51:14.658 DEBUG:	try to sync 0/100
...
2021-09-24 10:51:14.734 DEBUG:	try to sync 3/100
2021-09-24 10:51:14.742 DEBUG:	got response but value was 0x00
2021-09-24 10:51:14.742 DEBUG:	try to sync 4/100
2021-09-24 10:51:14.742 DEBUG:	got response but value was 0x33
...

At my firmware I am setting the uart to 115200, 8, N
after some time I am going to bootloader mode via

void tiva_bl_activateUART(void) {
	// stop systick
	sys_clock_disable();
	// disable all intr
	irq_lock();

	// start bootloader
	ROM_UpdateUART();
}

this code runs on zephyr and using the zephyr kernel api to disable the systick and the interrupts.
My config with I am compiling against the tiva hal (2.2.0295) is

#define PART_TM4C123GH6PGE
#define TARGET_IS_TM4C123_RB1

Any ideas what I missed?

  • Hi,

      Did you have a chance to run TivaWare bootloader examples?

    The bootloader can be found at: C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl\boot_serial

    The application example that calls the ROM_UpdateUART to jump back to the bootloader can be found at:  C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl\boot_demo_uart_rom

  • hey ho
    @chance to run bootloader example:
    I used the "TivaWare_C_Series-2.2.0.295/examples/boards/ek-tm4c123gxl/boot_demo_uart_rom" as my template.
    Since my UART is already initialized I don't run the configure code. My code - so far - not using the "MAP_" prefix for the functions.

    @general:
    I am compiling my code with the zephyr arm toolchain. Which is a gcc based. The makefile is generated by Zephyr. So taking your example code means porting for me. I like to avoid that.

    Lets first check if I rightfully setup the tiva driverlib.
    Can you pls clarify where do I need to setup the right defines (at header file or for the compiler). So I am using the TM4C123GH6PGE. Where and what do I need to define, so that the driver lib is build rightfully against my MCU.

    currently I solved it without any compiler defines(only via preprocessor):

    #ifndef SRC_DRV_CFG_TIVA_H_
    #define SRC_DRV_CFG_TIVA_H_
    
    #define PART_TM4C123GH6PGE
    #define TARGET_IS_TM4C123_RB1
    
    #include <tm4c123gh6pge.h>
    
    #include <hw_memmap.h>
    #include <pin_map.h>
    #include <gpio.h>
    #include <sysctl.h>
    #include <uart.h>
    #include <i2c.h>
    #include <can.h>
    #include <timer.h>
    #include <adc.h>
    #include <pwm.h>
    #include <rom.h>
    
    #endif /* SRC_DRV_CFG_TIVA_H_ */
    

  • Hi,

      I don't see a problem with your #include header files. 

  • thx for confirming.

    I double checked the UART setup. My is the same. As said before if I am sending (0x55, 0x55) every 100msec I am getting after 6 sends  (0x00, 0x33) read back. Changing the baudrate on my laptop generates different patterns.

    Lets try to rule out side effects. Before calling the UART bootloader (via ROM_UpdateUART) I have setup my system (pll, gpios, i2c, can, timer, adc, uart). All the peripherals are enabled when I am starting the bootloader.
    As shown at the example - before starting the bootloader I am disabling all intr (and the systick). Maybe I am missing something out - Do I need to disable all peripherals, etc.?

    Please advice me how I am starting the ROM bootloader from a running firmware?

  • I done some testing.

    The the disabling of the peripherals does not have a effect.

    I also executed the bootloader start just directly from the start. Same 0x5555 -> 0x0033 pattern

    I read the ROM version via ROM_VERSION = 0x26E(622) can you confirm that I am working on the right API?

  • Lets try to rule out side effects. Before calling the UART bootloader (via ROM_UpdateUART) I have setup my system (pll, gpios, i2c, can, timer, adc, uart). All the peripherals are enabled when I am starting the bootloader.

    You don't need to disable these peripherals. However, you must disable interrupts associated with them. Refer to the TivaWare examples as to disable all interrupts to NVIC. If you have already disable interrupts like below then you are fine. No need to disable peripherals. 

    //*****************************************************************************
    //
    // Passes control to the boot loader and initiates a remote software update.
    //
    // This function passes control to the boot loader and initiates an update of
    // the main application firmware image via UART0
    //
    // \return Never returns.
    //
    //*****************************************************************************
    void
    JumpToBootLoader(void)
    {
        //
        // Disable all processor interrupts.  Instead of disabling them
        // one at a time, a direct write to NVIC is done to disable all
        // peripheral interrupts.
        //
        HWREG(NVIC_DIS0) = 0xffffffff;
        HWREG(NVIC_DIS1) = 0xffffffff;
    
        //
        // Call the ROM UART boot loader.
        //
        ROM_UpdateUART();
    }

    Which tool did you use to download the code? I guess you are not using LM flash programmer. Is that correct? Can you try the sflash.exe in C:\ti\TivaWare_C_Series-2.2.0.295\tools\bin\sflash.exe? This is a command line tool to download firmware through UART. 

    My understanding is that you are not using the stock boot_serial example. Is that correct? You make some modification. What changes did you do? Can you please run the example if possible just to make sure it works on your side.

  • at the code I added:

    	HWREG(NVIC_DIS0) = 0xffffffff;
    	HWREG(NVIC_DIS1) = 0xffffffff;
    	HWREG(NVIC_DIS2) = 0xffffffff;
    	HWREG(NVIC_DIS3) = 0xffffffff;
    	HWREG(NVIC_DIS4) = 0xffffffff;
    

    I am using JLink swd directly or via openOCD

    I can x compile sflash on my Ubuntu. What logs do you like to see?

    I am want to use the ROM bootloader. My blueprint is "/boards/ek-tm4c123gxl/boot_demo_uart_rom"

    and its not working.

    I can confirm that my uart is working at my firmware. Although the pcb is a pre production pcb so there is might some error(unlikly)

  • Hi,

      I ran the stock TivaWare example boot_demo_uart_rom multiple times and it always works for me. The boot_demo_uart_rom example is very short. Can you not run as is? Just load the .out or .bin file to flash and see if it works first. 

    I

  • I also use sflash.exe to download the code and it is passing. 

  • Note in the boot_demo_uart_rom example, you must press the SW1 switch on the LaunchPad so it will jump to the ROM bootloader. Look at the switches I use in the sflash.exe command line as to disable autobaud. 

  • tried to compile sflash on my Ubuntu but failed with

    stefan@stefan-ThinkPad-L13-Gen-2:~/Downloads/TivaWare_C_Series-2.2.0.295/tools/sflash$ make -j
      CC    packet_handler.c
      CC    sflash.c
      CC    uart_handler.c
    gcc: error: unrecognized command-line option ‘-mno-cygwin’; did you mean ‘-mno-clwb’?
    gcc: error: unrecognized command-line option ‘-mno-cygwin’; did you mean ‘-mno-clwb’?
    gcc: error: unrecognized command-line option ‘-mno-cygwin’; did you mean ‘-mno-clwb’?
    make: *** [../toolsdefs:99: sflash.o] Error 1
    make: *** Waiting for unfinished jobs....
    make: *** [../toolsdefs:99: packet_handler.o] Error 1
    

    I will quickly try to execute the boot_demo_uart_rom code(ConfigureUART + JumpToBootLoader) inside that project.

    Are there external signals that control the rom bootloader code?

  • HI,

    Are there external signals that control the rom bootloader code?

      The main() of boot_demo_uart_rom is quite simple. It toggles a LED and waiting for user to press SW1 (PF4 pin) on the LaunchPad before calling ROM UART bootloader. Other than that, there is no other signals controlling boot_demo_uart_rom program flow. 

    //*****************************************************************************
    //
    // A simple application demonstrating the use of the ROM UART boot loader.
    //
    //*****************************************************************************
    int
    main(void)
    {
        //
        // Enable lazy stacking for interrupt handlers.  This allows floating-point
        // instructions to be used within interrupt handlers, but at the expense of
        // extra stack usage.
        //
        MAP_FPULazyStackingEnable();
    
        //
        // Set the system clock to run at 50MHz from the PLL.
        //
        MAP_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ |
                           SYSCTL_OSC_MAIN);
    
        //
        // Initialize the peripherals for the serial UART boot loader.
        //
        ConfigureUART();
    
        //
        // Initialize the buttons driver.
        //
        ButtonsInit();
    
        //
        // Enable the GPIO port that is used for the on-board LED.
        //
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    
        //
        // Enable the GPIO pin for the LED (PF3) as an output.
        //
        MAP_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_3);
    
        //
        // If the Switch SW1 is not pressed then blink the LED.  Press
        // and hold the SW1 for the debouncer to recognize the pin pressed.
        // On switch SW1 press detection, exit the blinking program and jump
        // to the ROM boot loader.
        //
        while ((ButtonsPoll(0, 0) & LEFT_BUTTON) == 0)
        {
            MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, GPIO_PIN_3);
            MAP_SysCtlDelay(SysCtlClockGet() / 50);
            MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);
            MAP_SysCtlDelay(SysCtlClockGet() / 50);
        }
    
        //
        // Before passing control make sure that the LED is turned OFF.
        //
        MAP_GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_3, 0x00);
    
        //
        // Pass control to whichever flavor of boot loader the board is configured
        // with.
        //
        JumpToBootLoader();
    
        //
        // The boot loader should not return.  In the off chance that it does,
        // enter a dead loop.
        //
        while(1)
        {
        }
    }
    

  • I mean the >>ROM<< bootloader not the code of the demo app ;) I am seeing at the debugger that after calling "ROM_UpdateUART" the instruction pointer goes to a addr somewhere over 0x1000000

  • ROM memory is mapped to 0x01000000. So the jump to ROM is happening. 

  • I think at this point we can rule out, that the bootloader is not started. I also checked the bootloader against different baudrates. The sync never worked. Like with my 115200-8-N config  (laptop to MCU (tx) 0x5555 -> MCU to laptop (rx) 0x0033)

    As said before, I like to check what has impact on the ROM bootloader. Can you advice me or point me to a document, that describes the ROM bootloader?

  • Notice in the screenshot I showed, I have autobaud rate detection disabled. Why don't you try to disable the autobaud and try the same setting as I did and see if that makes a difference. Otherwise, I really don't know why yours is not working while it works perfectly on my side. 

    Below is the sflash usage guide. 

  • Looks that my question was not well written.

    I was asking for the bootloader stored at the ROM of the tm4c123gh6pe
    not for the "sflash" cli tool

  • Ok, ROM user's guide is the only thing we have. 

    https://www.ti.com/lit/pdf/spmu367

  • look what I have found

    When an application calls back to the ROM-based boot loader to start an update over the UART
    port, the auto-baud feature is bypassed, along with UART configuration and pin configuration.

    Means the autobaud sync I try by sending 0x5555 is wrong. So I should ping the bootloader directly with out sync(autobaud) before.

    Is there a way to reset the uart peripheral back to its resets default?

  • Quick update

    If I am pining the bootloader now with (032020) the response is 00CC. I am sure that CC is the type 1 response (ACK) because if I mess up the ping message I will get NACK(in that case I am rxing 0033)

    So what now stays is: Why I am seeing a 00 every time before the type 1 response?
    My protocol source is document SPMA074A

  • Hi,

      As I mentioned, I disable the autobaud rate and it works for me using either LM flash programmer or sflash.exe. I'm not sure if autobaud rate will work. I need to do some research from past forum archives.

  • heureka
    I discard the first rx byte I am receiving from the bootloader and now I can do a firmware dfu.
    Next week I will do some scoping and let you know, who is generating the zero byte a the rx.

  • Glad you have made good progress. 

  • hey

    I put some spectrum analyser on the uart rx/tx. You can clearly see that the bootloader adds a 0x00 before an tx.

    ping request with 0x00 before ACK

    it happens everytime when the bootloader sends some bytes
    any idea what is the root cause?

    An other picture showing the ack of a send_data message
    send_data ack with leading 0x00

  • You can clearly see that the bootloader adds a 0x00 before an tx

    Please refer to the source file bl_main.c. You can see that when a COMMAND_PING received by the bootloader it will reply with a AckPacket(). See below snippet.

            //
            // The first byte of the data buffer has the command and determines
            // the format of the rest of the bytes.
            //
            switch(g_pui8DataBuffer[0])
            {
                //
                // This was a simple ping command.
                //
                case COMMAND_PING:
                {
                    //
                    // This command always sets the status to COMMAND_RET_SUCCESS.
                    //
                    g_ui8Status = COMMAND_RET_SUCCESS;
    
                    //
                    // Just acknowledge that the command was received.
                    //
                    AckPacket();
    
                    //
                    // Go back and wait for a new command.
                    //
                    break;
                }
    

    Now look at bl_packet.c file on how AckPacket() is coded. 

    //*****************************************************************************
    //
    //! Sends an Acknowledge packet.
    //!
    //! This function is called to acknowledge that a packet has been received by
    //! the microcontroller.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    AckPacket(void)
    {
        //
        // ACK/NAK packets are the only ones with no size.
        //
        SendData(g_pui8ACK, 2);
    }

    As you can see AckPacket() will call SendData() to send two bytes of data. What is sent by the bootloader is in g_pui8ACK. Now look at how g_pui8ACK[2] is defined. 

    //*****************************************************************************
    //
    // The packet that is sent to acknowledge a received packet.
    //
    //*****************************************************************************
    static const uint8_t g_pui8ACK[2] = { 0, COMMAND_ACK };

    As you can see the two bytes consists of a 0x0 followed by COMMAND_ACK. COMMAND_ACK is 0xCC and COMMAND_NAK is 0x33 defined in bl_commands.h file. 

    //*****************************************************************************
    //
    // This is the value that is sent to acknowledge a packet.
    //
    //*****************************************************************************
    #define COMMAND_ACK             0xcc
    
    //*****************************************************************************
    //
    // This is the value that is sent to not-acknowledge a packet.
    //
    //*****************************************************************************
    #define COMMAND_NAK             0x33

    I hope this is clear now why a 0x0 comes before 0xCC. 

  • perfect
    fyi if you check document SPMA074A page 7 (chapter 2.3.3 Response Packet Structure) you will see that there is no 0x00 mentioned.

    This answer solved my problem. Thx

  • Hi Stefan,

      I agree that SPMA074A  is a bit misleading to say ACK is only one byte. It is a two-bytes packet with 0x0 as the starting byte followed by the ACK byte (0x33) per the bootloader source code implementation.