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.

EK-TM4C1294XL: Eth bootloader update vector fails

Guru 54027 points
Part Number: EK-TM4C1294XL
Other Parts Discussed in Thread: TM4C1294NCPDT, TM4C1294KCPDT, LM3S8971

Hello group,

Attempted various ways to get Serial bootloader (BL) to vector jump address (0x2c). Or even 0x04 (ResetISR()) as to assert UpdateHandler() or EnterBootLoader() via Thumb code explicitly via BL table offset 0x2C.

The application launches 0x4000 without issues. Yet calling the jump 0x2c via application as do both Tiva examples seems to cause watchdog resets when dogs are disable prior to jump. The BL  code flow used to work fairly well via Stellaris MCU via the TFTP server client. Seemingly TM4C jump to 0x2c is not vectoring to where the BL vector table calls SRAM 0x2000.0000. BL is not hard faulting at this point only resets after a while.

I placed several LED toggles in the bl_emac.c code path but LED D1-D4 only turn on and never off as instructed below, until BL unexpected reset event. The PDF text misstates update via BootP without EMAC re-configuration is left over form Stellaris MCU and should be appended. Any ideas why the jump address 0x2C might not execute from BL vector table defined entries ENET_ENABLE_UPDATE as bl_config.h has un-commented? I don't see why MOSC should need to be reconfigured after jumping 0x2c if BL is not immediately resetting MCU. The 25mHz MOSC seems to be running as Ethernet client is active prior jumping 0x2c. 

Text: Additionally, the application can call the boot loader in order to perform an application-directed update. In this case, the boot loader assumes that the application has already configured the peripheral that it will use for the update. This allows the boot loader to use the peripheral as is to perform the update. The boot loader also assumes that the interrupt to the core has been left enabled as well, which means that that application should not call IntMasterDisable() before calling the boot loader. Once the application calls the boot loader, the boot loader copies itself to SRAM, branches to the SRAM copy of the boot loader, and starts the update by calling Updater() (for UART0, SSI0, and I2C0), UpdateBOOTP() (for Ethernet), AppUpdaterCAN() (for CAN) or AppUpdaterUSB() (for USB). The SVCall entry of the vector table contains the location of the application-directed update entry point. 

BootP via (TFTP) server requires BL calling UpdateBootP() where setup of UIP asserts via EnetReconfig() and resetting EMAC0 inside BL. So it can not use the fast updater() as described above without doing a full EMAC reconfiguration. What might be going on here? Where is Updater() in the BL Thumb code, it does not seem to exist?

The application jump and 2nd snip configureEnet() does toggle 4 LEDS On, then MCU resets. Skipping over configureEnet() and Thumb vector table calling BootP() the same reset occurs as if the jump address 0x2c is off by 4 byes in the vector table hard offset addresses.  

  

//*****************************************************************************
//
//! Configures the Ethernet controller at bootloaders initinalizaition.
//!
//! This function configures the Ethernet controller, preparing it for use by
//! the boot loader. COnfigure the GPIO LED Port Pins
//!
//! \return None. Called via bl_startup_ccs.s
//
//*****************************************************************************
void
ConfigureEnet(void)
{
    //
    // Make sure the main oscillator is enabled because this is required by
    // the PHY.  The system must have a 25MHz crystal attached to the OSC
    // pins.  The SYSCTL_MOSC_HIGHFREQ parameter is used when the crystal
    // frequency is 10MHz or higher.
    //
    //HWREG(SYSCTL_MOSCCTL) = SYSCTL_MOSC_HIGHFREQ;

    //
    // Delay while the main oscillator starts up.
    //
    //Delay(5242880);

	 /* MPU uses MOSC driven PLL 480mHz/4 produce 120 MHz SYSCLK:
	    Y1 = 25mHz XTAL HIGHFREQ. */
    //while(g_ui32SysClock != 120000000)
    {
		//g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
												  // SYSCTL_OSC_MAIN |
													//SYSCTL_USE_PLL |
													//SYSCTL_CFG_VCO_480), 120000000);
    }

	//
	//! Configure SysTick with 24ms periodic interrupt for the user functions.
	//! EthernetSendRealTimeData() tick rate via TM02
	//ROM_SysTickPeriodSet(120000000 / SYSTICKHZ);
	//ROM_SysTickEnable();
	//ROM_SysTickIntEnable();


#ifdef ENET_ENABLE_LEDS
    //
    // PF0/PF1 are used for Ethernet LEDs.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    /* Link LED-0 */
    ROM_GPIOPinConfigure(GPIO_PF0_EN0LED0); //EKXL_LED0:PF0, CPCB:PK4
    /* Activity LED-1 */
    ROM_GPIOPinConfigure(GPIO_PF4_EN0LED1); //EKXL_LED1:PF4, CPCB:PK5, PF1:EN0LED2

    //Configure PHY LEDS for Link, Activity at 2ma.
    GPIOPinTypeEthernetLED(GPIO_PORTF_AHB_BASE, GPIO_PIN_0 | GPIO_PIN_4);

    // Set the LED pad(s) for standard push-pull operation.
    MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);//CPCB:PK4
    MAP_GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); //CPCB:PK5

    /* Enable GPIO-N peripheral */
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

    /* Run LED N1 */
    ROM_GPIOPinTypeGPIOOutput(PIN_LEDRUN_PORT, PIN_LEDRUN_PIN);
    MAP_GPIOPadConfigSet(GPIO_PORTN_BASE, GPIO_PIN_0,
                             GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);//CPCB:A2

    /* Fault LED N0 */
    ROM_GPIOPinTypeGPIOOutput(PIN_LEDFAULT_PORT, PIN_LEDFAULT_PIN);
    MAP_GPIOPadConfigSet(GPIO_PORTN_BASE, GPIO_PIN_1,
                                 GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);//CPCB:A3

    // Turn Run LED On, fault LED On
    ROM_GPIOPinWrite(PIN_LEDRUN_PORT, PIN_LEDRUN_PIN, PIN_LEDRUN_PIN);
    ROM_GPIOPinWrite(PIN_LEDFAULT_PORT, PIN_LEDFAULT_PIN, PIN_LEDFAULT_PIN);

   SysCtlDelay(120000000 * 4);

    // Turn Run LED On, fault LED Off
    ROM_GPIOPinWrite(PIN_LEDRUN_PORT, PIN_LEDRUN_PIN, 0x0);
    ROM_GPIOPinWrite(PIN_LEDFAULT_PORT, PIN_LEDFAULT_PIN, 0x2);

    SysCtlDelay(120000000 * 4);

	// Turn Run LED On, fault LED Off
	ROM_GPIOPinWrite(PIN_LEDRUN_PORT, PIN_LEDRUN_PIN, 0x1);
	ROM_GPIOPinWrite(PIN_LEDFAULT_PORT, PIN_LEDFAULT_PIN, 0x0);

#endif
//
//
    //
    // Enable and reset the Ethernet modules.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
    ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
    ROM_SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);

    while(!ROM_SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
    {
    }

}
/* System memory map */

MEMORY
{
    FLASH (RX) : origin = 0x00000000, length = 0x00080000
    SRAM (RWX) : origin = 0x20000000, length = 0x00040000
}

/* Section allocation in memory */

SECTIONS
{
        GROUP
    {
	    .intvecs:
	    .text
	    .const
	    .cinit  :   > FLASH
	    .pinit  :   > FLASH
	    .data
	    .init_array : > FLASH //added

    } load = FLASH, run = SRAM, LOAD_START(init_load), RUN_START(init_run), SIZE(init_size)

    GROUP
    {
        .vtable:   > 0x20000000 //added
	    .bss
	    .sysmem
	    .stack

    } run = SRAM, RUN_START(bss_run), RUN_END(bss_end), SIZE(bss_size), RUN_END(__STACK_TOP)


}

  • Here is the BL Thumb UpdateHandler() code where PDF states to also call Updater():

    ;;*****************************************************************************
    ;;
    ;; The update handler, which gets called when the application would like to
    ;; start an update.
    ;;
    ;;*****************************************************************************
        .thumbfunc UpdateHandler
    UpdateHandler: .asmfunc
        ;;
        ;; Initialize the processor.
        ;;
        bl      ProcessorInit
    
        ;;
        ;; Load the stack pointer from the vector table.
        ;;
        movs    r0, #0x0000
        ldr     sp, [r0]
    
        ;;
        ;; Call the user-supplied low level hardware initialization function
        ;; if provided.
        ;;
     ;;.if $$defined(BL_HW_INIT_FN_HOOK)
       ;; bl      BL_HW_INIT_FN_HOOK
     ;;.endif
    
        ;;
        ;; Call the user-supplied re-initialization function if provided.
        ;;
     ;;.if $$defined(BL_REINIT_FN_HOOK)
       ;; .ref    BL_REINIT_FN_HOOK
       ;; bl      BL_REINIT_FN_HOOK
     ;;.endif
    
        ;;
        ;; Branch to the update handler.
        ;; added EnterBootLoader
     .if $$defined(ENET_ENABLE_UPDATE)
     ;;  b	ConfigureEnet
        b		EnterBootLoader
        b       UpdateBOOTP
     .elseif $$defined(CAN_ENABLE_UPDATE)
        .ref    AppUpdaterCAN
        b       AppUpdaterCAN
     .elseif $$defined(USB_ENABLE_UPDATE)
        .ref    AppUpdaterUSB
        b       AppUpdaterUSB
     .else
        b       Updater
     .endif
        .endasmfunc
    

  • I think the problem is that once the application enables the watchdog, you cannot disable it except through a reset:

    If the application must use the watchdog I think you have two options:

    1) add watchdog support to the bootloader

    2) define your own function to check if the bootloader runs the application or stays in the bootloader. This function can check the reset source. If the reset source is the watchdog, then the function returns a non-zero and stays in the bootloader. Then you can actually force a watchdog reset to re-enter the bootloader instead of the SVC call at 0x2C.

    An example from line 1462 of bl_config.h

    //*****************************************************************************
    //
    // Allows an application to force a new firmware download.  If hooked, this
    // function will be called during boot loader initialization to determine
    // whether a firmware update should be performed regardless of whether a valid
    // main code image is already present.  If the function returns 0, the existing
    // main code image is booted (if present), otherwise the boot loader will wait
    // for a new firmware image to be downloaded.
    //
    unsigned int MyCheckUpdateFunc(void);
    //
    // This value takes precedence over ENABLE_UPDATE_CHECK} if both are defined.
    // If you wish to perform a GPIO check in addition to any other update check
    // processing required, the GPIO code must be included within the hook function
    // itself.
    //
    //*****************************************************************************
    #define BL_CHECK_UPDATE_FN_HOOK MyCheckUpdateFunc
    
    

  • Hi Bob,

    You might noticed below code disabled both watchdog resets, should keep dogs from asserting during BL code execution. It must be the MCU is resetting from catastrophic code failure entering BootP section.

    I'v tracked down part of the issue being UART0 GPIO PA0/PA1 when added to BootP() code execution toggle LEDS D1/D2 On then watch dogs reset MCU. Noticed several other make objects are being built that are not selected via bl_config.h see ssi, i2c, USB, UART, etc...

    void
    BootLoader(void)
    {
    
             /* bool (g_bStartBootLoader) = (0)-false do NOT invoke Boot Loader.
             While bool (g_bStartBootLoader) = (1)-true, Invoke Boot Loader.
             Loop Forever, the real work is done in interrupt handlers.*/
    
    	         UARTprintf("<< Boot Loader >> \n\n");
    
                    while(1)
                    {
    					 //
    					 // Put the processor to sleep.
    					 //
    					 //MAP_SysCtlSleep();
    
                  
    						/* Unlock the watchdogs Eallow */
    						MAP_WatchdogUnlock(WATCHDOG0_BASE | WATCHDOG1_BASE);
                            /* Disable the watchdog timers */
                            MAP_WatchdogResetDisable(WATCHDOG0_BASE);
                            MAP_WatchdogResetDisable(WATCHDOG1_BASE);
                			/* Disable Watchdog interrupts */
                			HWREG(WATCHDOG0_BASE + WDT_O_CTL) &= ~(WDT_CTL_INTEN);
                			HWREG(WATCHDOG1_BASE + WDT_O_CTL) &= ~(WDT_CTL_INTEN);
    
                            //
                            // Turn off all the on-board LEDs.
                            //
                            UIRunLEDBlink(0, 0);
                            UIFaultLEDBlink(0, 0);
    
                            MAP_SysCtlDelay(g_ui32SysClock / 400);
    
                            //
                            // We must make sure we turn off SysTick and its interrupt before entering
                            // the boot loader!
                            //
                            ROM_SysTickIntDisable();
                            ROM_SysTickDisable();
    
                            //
                            // 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;
                            HWREG(NVIC_DIS2) = 0xffffffff;
                            HWREG(NVIC_DIS3) = 0xffffffff;
    
                            //
                            // Clear any active interrupts.  If the boot loader uses
                            // any interrupts, they will therefore respond as expected.
                            //
                            //HWREG(NVIC_APINT) = (NVIC_APINT_VECTKEY |
                                                //NVIC_APINT_VECT_CLR_ACT);
    
                            // Return control to the boot loader.  This is a call to the SVC
                            // handler in the boot loader.
                            //
                            (*((void (*)(void))(*(uint32_t *)0x2c)))(); //ISRreset 0x04
    
                            //
                            // Control should never return here, but just in case it does.
                            //
                            while(1)
                            {
                            }
    
    				}
    
    }

  • Reduced BL build to 6k after patching (bl_startup_ccs.c) to have Thumb checks for force update enable (bl_config.h). After callApplication would not launch application.

    Oddly UART0 must be configured and call UARTStdioConfig() into (bl_emac.c) or the Application will not launch, no LED blink activity. The application has both UART0, UART3 configured and debug messages virtual COM (UART0) via launch pads XDS110 USB0.

    Having to call UARTStdioConfig() in bl_emac.c is baffling. UART0 does not have UART_BUFFER defined, no interrupt handler required in vector table..

  • The serial bootloaders UpdateHandler() is being executed after MCU soft/hard reset and falling through to BootP() via bl_emac.c. It seems possible some Thumb instructions are not working as intended via bl_startup_ccs.s. The UpdateHandler() thumb code is executed without being asserted to do so by the application. That us how UARTStdioConfig() is being executed in bl_emac.c and allowing application to launch from flash address 0x4000. 

    Further I removed UpdateHander -0x2000000 from BL vector table address 0x2c and still executes BootP(), EnterBootLoader() placed under UpdateHandler() in bl_startup_ccs.s. It would seem the serial Bootloader was modified and left in state of partial functionality. 

    Point being the BL peripheral functions should not be executing until asserted by the application or GPIO pin forced update mode on MCU reset. The BL code runs via PIOSC internal oscillator until the Application configures MOSC for what ever XTAL frequency exists on the PCB.

  • Launching the demo projects with the serial bootloader on my Lauchpad does not cause Watchdog resets. You seem to be focusing on the bootloader. I suggest you set a breakpoint in the application on the call back to the bootloader and verify that the watchdog really was disabled. 

  • Hi Bob,

    I finally got BL to work after loading newer version and adding above patches with one change below. Part of the issue was ORing the watchdog unlock is not allowed and mixing ROM with MAP calls in BL made it behave badly, MAP even breaks it on some EMAC0 function calls Tivaware v2.1.1.7.1. Are all ROM calls in the latter v2.1.2.111 and the later compilers LTS suffix seem to break BootP calls, v5.2.8 compiler builds ok. Had changed several calls to MAP after reading a post you made comment of how MAP trumps ROM, in this case it made things worse. Oddly I compiled BL v2.1.2.111 via v2.1.1.7.1 driverlib since build had errors to find EMAC0 configure LED's. 

    The EnterBootLoader: function was defined for bl_startup_ccs.s builds when MCU asserts NmiSR: called if ENABLE_MOSCFAIL_HANDLER. The EBL re-configures MOSC on NMI event but was not blocked in ResetISR: seemingly can fall through reconfigure MOSC. The below patch is similar to above snip but calls NmiSR: if AppAddress not added bl_config.h. BTW the flash block size 400 needed to be 4000 or the bin file would not write to flash. Unless TM4C1294 MOSC has oscillator fail detection NmiSR may not do much good.

    All this and like to USB0 for future updates though wanted to prove the BL works. Does update via require USB license?

    ;;*****************************************************************************
    ;;
    ;; The reset handler, which gets called when the processor starts.
    ;;
    ;;*****************************************************************************
        .thumbfunc ResetISR
    ResetISR: .asmfunc
        ;;
        ;; Enable the floating-point unit.  This must be done here in case any
        ;; later C functions use floating point.  Note that some toolchains will
        ;; use the FPU registers for general workspace even if no explicit floating
        ;; point data types are in use.
        ;;
        movw    r0, #0xED88
        movt    r0, #0xE000
        ldr     r1, [r0]
        orr     r1, r1, #0x00F00000
        str     r1, [r0]
    
        ;;
        ;; Initialize the processor.
        ;;
        bl      ProcessorInit
    
        ;;
        ;; Call the user-supplied low level hardware initialization function
        ;; if provided.
        ;;
     .if $$defined(BL_HW_INIT_FN_HOOK)
        .ref    BL_HW_INIT_FN_HOOK
        bl      BL_HW_INIT_FN_HOOK
     .endif
    
        ;;
        ;; See if an update should be performed.
        ;; 6/25/21 if check bl_config.h
        ;;
     .if $$defined(ENABLE_UPDATE_CHECK)
        .ref    CheckForceUpdate
        bl      CheckForceUpdate
     .endif
       	;;
     	;; <<< Start Application >>>
     	;;
     .if $$defined(APP_START_ADDRESS)
     	bl		StartApplication
     ;; cbz     r0, CallApplication
     .else
     ;; Something went wrong so reconfigure MOSC
     	bl		NmiSR
     ;;	FaultISR
     .endif
      ;; Does not work
      ;;  cbz     r0, CallApplication
    
        ;;
        ;; Configure the microcontroller.
        ;;
        .thumbfunc EnterBootLoader
    EnterBootLoader:
     .if $$defined(ENET_ENABLE_UPDATE)
        .ref    ConfigureEnet
        bl      ConfigureEnet
     .elseif $$defined(CAN_ENABLE_UPDATE)
        .ref    ConfigureCAN
        bl      ConfigureCAN
     .elseif $$defined(USB_ENABLE_UPDATE)
        .ref    ConfigureUSB
        bl      ConfigureUSB
     .else
        .ref    ConfigureDevice
        bl      ConfigureDevice
     .endif
    
        ;;
        ;; Call the user-supplied initialization function if provided.
        ;;
     .if $$defined(BL_INIT_FN_HOOK)
        .ref    BL_INIT_FN_HOOK
        bl      BL_INIT_FN_HOOK
     .endif
    
        ;;
        ;; Branch to the update handler.
        ;;
     .if $$defined(ENET_ENABLE_UPDATE)
        .ref    UpdateBOOTP
        b       UpdateBOOTP
     .elseif $$defined(CAN_ENABLE_UPDATE)
        .ref    UpdaterCAN
        b       UpdaterCAN
     .elseif $$defined(USB_ENABLE_UPDATE)
        .ref    UpdaterUSB
        b       UpdaterUSB
     ;;.else
     ;;  .ref    Updater
     ;;   b      Updater
     .endif
        .endasmfunc
     

  • Does update via require USB license?

    Glad that you got the bootloader working. The Bootloader update by DFU does not require any license other than the standard TivaWare license.

  • Glad that you got the bootloader working.

    Oddly BL works on NCPDT but not KCPDT. Seems Tivaware 2.1.4.178 has clock issue KCPD. Below the command killing EnetReconfig()  Tivaware 2.1.1.71 without any build warnings. Change build library ~178 then BootP works (NCPDT). Any idea why MOSC fails Tivaware ~178 on KCPDT?

    The PLL is set 480mHz and recall a change was made to fix clocking PYSDIV issue seemingly should effect NCPDT in same way. At lease the fault LED came on NCPDT but nothing on KCPDT.

    //
    // Initialize the MAC and set the DMA mode.
    // 
    ROM_EMACInit(EMAC0_BASE, ui32Clock,
    EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0);

  • There was a change done in TivaWare v2.1.3 and later that sets the VCO to 240MHz instead of 480MHz to avoid an issue where the RSCLKCFG.PSYSDIV bits did not get properly written. This could result in the system clock running at 240MHz and the device would lock up. I suggest using the newest version of TivaWare. I have no explanation why the bootloader would work on the TM4C1294NCPDT, but not on the TM4C1294KCPDT unless the application being loaded exceeded the 512KB flash available on the smaller part.

  • unless the application being loaded exceeded the 512KB flash available on the smaller part.

    Application is only 102Kb and UART update has the same issue as Ethernet KCPDT update. Almost as if the start address of vector table is not being copied 0x2000000 but some other address or not at all. Debug IP ping pongs between Delay and Reset Thumb instructions.

    .thumbfunc Delay
    .global Delay
    Delay: .asmfunc
    subs r0, #1
    bne Delay
    bx lr
    .endasmfunc

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

    This could result in the system clock running at 240MHz and the device would lock up

    Yet BL sets MOSC 25Mhz toggles LED's and pulls in a relay. And BL peripheral functions are working, the copy BL to SRAM location is not.

  • If the hardware is the same and there is no code in the upper half of the flash, I have no idea why they would behave differently.

  • For one the compiler v5.2.8 upward does not understand the literal defined name SRAM and expects bl_link_ccs.cmd explicit address run=0x20000000 or BL Thumb code does not run.

    Other BL problems reside around the NVIC_VTABLE indirect memory address instruction. Thumb call to load  VTABLE_START_ADDRESS as defined bl_config.h. Now that the flash vector is somewhat correct KCPDT can access the app .data section but fails to initialize app peripherals (main.c). This really needs to be tested in TI lab, replace NCPDT for KCPDT check Bootloader actually does relocate NVIC_VTABLE vector address.

      ;;
    ;; Set the application's vector table start address. Typically this is the
    ;; application start address but in some cases an application may relocate
    ;; this so we can't assume that these two addresses are equal.
    ;;
    movw r0, #(VTABLE_START_ADDRESS & 0xffff)
    .if (VTABLE_START_ADDRESS > 0xffff)
    movt r0, #(VTABLE_START_ADDRESS >> 16)
    .endif
    movw r1, #(NVIC_VTABLE & 0xffff)
    movt r1, #(NVIC_VTABLE >> 16)
    str r0, [r1] 

  • HI Bob,

    The SBL call to load the NVIC_VTABLE offset via indirect memory addressing Thumb code is not working for  KCPDT, FLASH length=0x00080000, origin=0x00004000.

    That call gets the table at NVIC offset of the applications Flashed Vtable. Need to add text to PDF, Note to subtract the origin from the Length. Oddly that is not required for NCPDT Length=0x000100000. Nor was it required for LM3S8971 ~.cmd file and the NVIC_VTABLE offset address contents seem to be relocated with the application. It doesn't matter the compiler LTS or older, looses flash length when origin is moved upward.

    Regards,