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: Interrupt vector and branching to new program in flash

Part Number: TM4C123GH6PM
Other Parts Discussed in Thread: EK-TM4C1294XL

Hi Folks,

I'm continuing to work on doing a over the air update. I have the logic in place that I can load a new .bin file to a location in flash (ie 0x20000),  and  the running program can successfully call the ENTRY POINT SYMBOL: "_c_int00_noargs"  address: 0001c701  with no problem.

Note, for testing I'm just using LM Flash Programmer (Build 1613) to write the bootloader to 0x0000 and the second program to 0x00020000)

The 2nd program starts as expected, but anything beyond simple GPIO (toggling pins on and off) doesn't seem to work.  My current theory is anything that needs the interrupt vector is failing.

Note if I set the APP_BASE value to 0x0000 everything works fine. (Running stand alone without the simple bootloader.)

Here is my .cmd file for the 2nd program:

/******************************************************************************
 *
 * Default Linker Command file for the Texas Instruments TM4C123GH6PM
 *
 * This is derived from revision 15071 of the TivaWare Library.
 *
 *****************************************************************************/

--retain=g_pfnVectors


/* The starting address of the application.  Normally the interrupt vectors  */
/* must be located at the beginning of the application.                      */

#define APP_BASE 0x00010000

#define RAM_BASE 0x20000000

/* System memory map */

MEMORY
{
    /* Application stored in and executes from internal flash */
    FLASH (RX) : origin = APP_BASE, length = 0x00020000
    /* Application uses internal RAM for data */
    SRAM (RWX) : origin = 0x20000000, length = 0x00020000
}

/* Section allocation in memory */

SECTIONS
{
    .intvecs:   > APP_BASE
    .text   :   > FLASH
    .const  :   > FLASH
    .cinit  :   > FLASH
    .pinit  :   > FLASH
    .init_array : > FLASH

    .vtable :   > RAM_BASE
    .data   :   > SRAM
    .bss    :   > SRAM
    .sysmem :   > SRAM
    .stack  :   > SRAM

#ifdef  __TI_COMPILER_VERSION__
#if     __TI_COMPILER_VERSION__ >= 15009000
    .TI.ramfunc : {} load=FLASH, run=SRAM, table(BINIT)
#endif
#endif
}

__STACK_TOP = __stack + 512;

And it creates the expected .map file when compiled (everything looks like it is in the right memory location)

******************************************************************************
                  TI ARM Linker PC v18.12.2                    
******************************************************************************
>> Linked Sat Nov  5 16:28:55 2022

OUTPUT FILE NAME:   <TIVA_PK_M1_Dec24.out>
ENTRY POINT SYMBOL: "_c_int00_noargs"  address: 0001c701


MEMORY CONFIGURATION

         name            origin    length      used     unused   attr    fill
----------------------  --------  ---------  --------  --------  ----  --------
  FLASH                 00010000   00020000  0000d3fe  00012c02  R  X
  SRAM                  20000000   00020000  00006d58  000192a8  RW X


SEGMENT ALLOCATION MAP

run origin  load origin   length   init length attrs members
----------  ----------- ---------- ----------- ----- -------
00010000    00010000    0000d400   0000d400    r-x
  00010000    00010000    0000026c   0000026c    r-- .intvecs
  0001026c    0001026c    0000c6fa   0000c6fa    r-x .text
  0001c968    0001c968    00000988   00000988    r-- .const
  0001d2f0    0001d2f0    00000110   00000110    r-- .cinit
20000000    20000000    00006d5c   00000000    rw-
  20000000    20000000    00004b54   00000000    rw- .bss
  20004b58    20004b58    00002000   00000000    rw- .stack
  20006b58    20006b58    00000204   00000000    rw- .data


SECTION ALLOCATION MAP

 output                                  attributes/
section   page    origin      length       input sections
--------  ----  ----------  ----------   ----------------
.intvecs   0    00010000    0000026c     
                  00010000    0000026c     tm4c123gh6pm_startup_ccs.obj (.intvecs)

... (cut of rest of file, I can post if needed.)

I have a simple bootloader that just calls the entry point:

void main()
{
    HWREG(NVIC_DIS0) = 0xffffffff;
    HWREG(NVIC_DIS1) = 0xffffffff;


    typedef void (*boot_loader_entry_t)(void);
    boot_loader_entry_t boot_loader_entry_ptr = (boot_loader_entry_t) 0x0001c701;
    boot_loader_entry_ptr();


    while(1)
    {
    }
}

I'd appreciate any suggestions.  Note I looked at the boot_loader example multiple times, it seems bl_startup.gcc.S file is written in assembly and does some manipulation with the vector table that I'm missing in my simple bootloader.

Boot_demo1 and boot_demo2, startup.css.c  are similar to what I have:  

//*****************************************************************************
//
// Startup code for use with TI's Code Composer Studio.
//
// Copyright (c) 2011-2014 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Software License Agreement
//
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
//
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
//
//*****************************************************************************

#include <stdint.h>
#include "inc/hw_nvic.h"
#include "inc/hw_types.h"

#include "tiva_uart_new.h"
#include "PK_MISC.h"

//*****************************************************************************
//
// Forward declaration of the default fault handlers.
//
//*****************************************************************************
void ResetISR(void);
static void NmiSR(void);
static void FaultISR(void);
static void IntDefaultHandler(void);

//*****************************************************************************
//
// External declaration for the reset handler that is to be called when the
// processor is started
//
//*****************************************************************************
extern void _c_int00(void);

//*****************************************************************************
//
// Linker variable that marks the top of the stack.
//
//*****************************************************************************
extern uint32_t __STACK_TOP;

//*****************************************************************************
//
// External declarations for the interrupt handlers used by the application.
//
//*****************************************************************************
// To be added by user

//*****************************************************************************
//
// The vector table.  Note that the proper constructs must be placed on this to
// ensure that it ends up at physical address 0x0000.0000 or at the start of
// the program if located at a start address other than 0.
//
//*****************************************************************************
#pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =
{
    (void (*)(void))((uint32_t)&__STACK_TOP),
                                            // The initial stack pointer
    ResetISR,                               // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    IntDefaultHandler,                      // The SysTick handler
    IntDefaultHandler,                      // GPIO Port A
    IntDefaultHandler,                      // GPIO Port B
    IntDefaultHandler,                      // GPIO Port C
    IntDefaultHandler,                      // GPIO Port D
    IntDefaultHandler,                      // GPIO Port E
    UARTStdioIntHandler0,                      // UART0 Rx and Tx
    IntDefaultHandler,                      // UART1 Rx and Tx
    IntDefaultHandler,                      // SSI0 Rx and Tx
    IntDefaultHandler,                      // I2C0 Master and Slave
    IntDefaultHandler,                      // PWM Fault
    IntDefaultHandler,                      // PWM Generator 0
    IntDefaultHandler,                      // PWM Generator 1
    IntDefaultHandler,                      // PWM Generator 2
    IntDefaultHandler,                      // Quadrature Encoder 0
    IntDefaultHandler,                      // ADC Sequence 0
    IntDefaultHandler,                      // ADC Sequence 1
    IntDefaultHandler,                      // ADC Sequence 2
    IntDefaultHandler,                      // ADC Sequence 3
    WatchdogIntHandler,                     // Watchdog timer
    IntDefaultHandler,                      // Timer 0 subtimer A
    IntDefaultHandler,                      // Timer 0 subtimer B
    IntDefaultHandler,                      // Timer 1 subtimer A
    IntDefaultHandler,                      // Timer 1 subtimer B
    IntDefaultHandler,                      // Timer 2 subtimer A
    IntDefaultHandler,                      // Timer 2 subtimer B
    IntDefaultHandler,                      // Analog Comparator 0
    IntDefaultHandler,                      // Analog Comparator 1
    IntDefaultHandler,                      // Analog Comparator 2
    IntDefaultHandler,                      // System Control (PLL, OSC, BO)
    IntDefaultHandler,                      // FLASH Control
    IntDefaultHandler,                      // GPIO Port F
    IntDefaultHandler,                      // GPIO Port G
    IntDefaultHandler,                      // GPIO Port H
    IntDefaultHandler,                      // UART2 Rx and Tx
    IntDefaultHandler,                      // SSI1 Rx and Tx
    IntDefaultHandler,                      // Timer 3 subtimer A
    IntDefaultHandler,                      // Timer 3 subtimer B
    IntDefaultHandler,                      // I2C1 Master and Slave
    IntDefaultHandler,                      // Quadrature Encoder 1
    IntDefaultHandler,                      // CAN0
    IntDefaultHandler,                      // CAN1
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // Hibernate
    IntDefaultHandler,                      // USB0
    IntDefaultHandler,                      // PWM Generator 3
    IntDefaultHandler,                      // uDMA Software Transfer
    IntDefaultHandler,                      // uDMA Error
    IntDefaultHandler,                      // ADC1 Sequence 0
    IntDefaultHandler,                      // ADC1 Sequence 1
    IntDefaultHandler,                      // ADC1 Sequence 2
    IntDefaultHandler,                      // ADC1 Sequence 3
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // GPIO Port J
    IntDefaultHandler,                      // GPIO Port K
    IntDefaultHandler,                      // GPIO Port L
    IntDefaultHandler,                      // SSI2 Rx and Tx
    IntDefaultHandler,                      // SSI3 Rx and Tx
    IntDefaultHandler,                      // UART3 Rx and Tx
    IntDefaultHandler,                      // UART4 Rx and Tx
    IntDefaultHandler,                      // UART5 Rx and Tx
    IntDefaultHandler,                      // UART6 Rx and Tx
    IntDefaultHandler,                      // UART7 Rx and Tx
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // I2C2 Master and Slave
    IntDefaultHandler,                      // I2C3 Master and Slave
    IntDefaultHandler,                      // Timer 4 subtimer A
    IntDefaultHandler,                      // Timer 4 subtimer B
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // Timer 5 subtimer A
    IntDefaultHandler,                      // Timer 5 subtimer B
    IntDefaultHandler,                      // Wide Timer 0 subtimer A
    IntDefaultHandler,                      // Wide Timer 0 subtimer B
    IntDefaultHandler,                      // Wide Timer 1 subtimer A
    IntDefaultHandler,                      // Wide Timer 1 subtimer B
    IntDefaultHandler,                      // Wide Timer 2 subtimer A
    IntDefaultHandler,                      // Wide Timer 2 subtimer B
    IntDefaultHandler,                      // Wide Timer 3 subtimer A
    IntDefaultHandler,                      // Wide Timer 3 subtimer B
    IntDefaultHandler,                      // Wide Timer 4 subtimer A
    IntDefaultHandler,                      // Wide Timer 4 subtimer B
    IntDefaultHandler,                      // Wide Timer 5 subtimer A
    IntDefaultHandler,                      // Wide Timer 5 subtimer B
    IntDefaultHandler,                      // FPU
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // I2C4 Master and Slave
    IntDefaultHandler,                      // I2C5 Master and Slave
    IntDefaultHandler,                      // GPIO Port M
    IntDefaultHandler,                      // GPIO Port N
    IntDefaultHandler,                      // Quadrature Encoder 2
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // GPIO Port P (Summary or P0)
    IntDefaultHandler,                      // GPIO Port P1
    IntDefaultHandler,                      // GPIO Port P2
    IntDefaultHandler,                      // GPIO Port P3
    IntDefaultHandler,                      // GPIO Port P4
    IntDefaultHandler,                      // GPIO Port P5
    IntDefaultHandler,                      // GPIO Port P6
    IntDefaultHandler,                      // GPIO Port P7
    IntDefaultHandler,                      // GPIO Port Q (Summary or Q0)
    IntDefaultHandler,                      // GPIO Port Q1
    IntDefaultHandler,                      // GPIO Port Q2
    IntDefaultHandler,                      // GPIO Port Q3
    IntDefaultHandler,                      // GPIO Port Q4
    IntDefaultHandler,                      // GPIO Port Q5
    IntDefaultHandler,                      // GPIO Port Q6
    IntDefaultHandler,                      // GPIO Port Q7
    IntDefaultHandler,                      // GPIO Port R
    IntDefaultHandler,                      // GPIO Port S
    IntDefaultHandler,                      // PWM 1 Generator 0
    IntDefaultHandler,                      // PWM 1 Generator 1
    IntDefaultHandler,                      // PWM 1 Generator 2
    IntDefaultHandler,                      // PWM 1 Generator 3
    IntDefaultHandler                       // PWM 1 Fault
};

//*****************************************************************************
//
// This is the code that gets called when the processor first starts execution
// following a reset event.  Only the absolutely necessary set is performed,
// after which the application supplied entry() routine is called.  Any fancy
// actions (such as making decisions based on the reset cause register, and
// resetting the bits in that register) are left solely in the hands of the
// application.
//
//*****************************************************************************
void
ResetISR(void)
{
    //
    // Jump to the CCS C initialization routine.  This will enable the
    // floating-point unit as well, so that does not need to be done here.
    //
    __asm("    .global _c_int00\n"
          "    b.w     _c_int00");
}

//*****************************************************************************
//
// This is the code that gets called when the processor receives a NMI.  This
// simply enters an infinite loop, preserving the system state for examination
// by a debugger.
//
//*****************************************************************************
static void
NmiSR(void)
{
    //
    // Enter an infinite loop.
    //
    while(1)
    {
    }
}

//*****************************************************************************
//
// This is the code that gets called when the processor receives a fault
// interrupt.  This simply enters an infinite loop, preserving the system state
// for examination by a debugger.
//
//*****************************************************************************
static void
FaultISR(void)
{
    //
    // Enter an infinite loop.
    //
    while(1)
    {
    }
}

//*****************************************************************************
//
// This is the code that gets called when the processor receives an unexpected
// interrupt.  This simply enters an infinite loop, preserving the system state
// for examination by a debugger.
//
//*****************************************************************************
static void
IntDefaultHandler(void)
{
    //
    // Go into an infinite loop.
    //
    while(1)
    {
    }
}

Thanks again for any suggestions,

Bob

  • Note, for testing I'm just using LM Flash Programmer (Build 1613) to write the bootloader to 0x0000 and the second program to 0x00020000)

    While the post said you write the second program to 0x00020000, the .cmd file for the 2nd program contains:

    /* The starting address of the application.  Normally the interrupt vectors  */
    /* must be located at the beginning of the application.                      */
    
    #define APP_BASE 0x00010000

    Where the APP_BASE value of 0x00010000 is used to set the address of the interrupt vectors and the origin of the FLASH memory region:

        .intvecs:   > APP_BASE
        
        /* Application stored in and executes from internal flash */
        FLASH (RX) : origin = APP_BASE, length = 0x00020000

    Was LM Flash Programmer really used to write the second program to 0x00020000, rather than 0x00010000, or was that a typo in the post?

  • My current theory is anything that needs the interrupt vector is failing.

    Is the 2nd program setting the Vector Table Offset (VTABLE) register?

    At reset VTABLE is to 0x0000000 which is the start of flash (where the bootloader has been programmed).

    The value of VTABLE will need to be changed if the 2nd program needs to use interrupts.

    Looking at TivaWare_C_Series-2.2.0.295/examples/boards/ek-tm4c1294xl/usb_stick_update/usb_stick_update.c there is the following CallApplication function to call the entry point of an application, which sets the vector table to the beginning of the app in flash:

    #elif defined(ccs)
    void
    CallApplication(uint_fast32_t ui32StartAddr)
    {
        //
        // Set the vector table to the beginning of the app in flash.
        //
        HWREG(NVIC_VTABLE) = ui32StartAddr;
    
        //
        // Load the stack pointer from the application's vector table.
        //
        __asm("    ldr     r1, [r0]\n"
              "    mov     sp, r1\n");
    
        //
        // Load the initial PC from the application's vector table and branch to
        // the application's entry point.
        //
        __asm("    ldr     r0, [r0, #4]\n"
              "    bx      r0\n");
    }
    #else
    

    Where CallApplication also reads the initial stack pointer and initial PC from the vector table, which would also avoids the need for the bootloader to hard-code the value of boot_loader_entry_ptr (which may change when the application changes).

    I.e. suggest in your bootloader add the CallApplication function (which uses in-line assembler in the format supported by the TI ARM compiler) and replace:

        typedef void (*boot_loader_entry_t)(void);
        boot_loader_entry_t boot_loader_entry_ptr = (boot_loader_entry_t) 0x0001c701;
        boot_loader_entry_ptr();

    With:

        CallApplication (0x10000); /* Transfer to the application with the vector table starting at address 0x10000 */

  • The flash programmer is writing to 0x10000,  APP_BASE value.  I noticed you highlighted the length length.  Is there something I need to change there?

  • 2nd program is not setting VTABLE.  Thanks for the suggestion I'll look into this Monday evening and get back with the group.

    thanks,

    Bob

  • The flash programmer is writing to 0x10000,  APP_BASE value.  I noticed you highlighted the length length.  Is there something I need to change there?

    No changes required; the LM Flash Programmer setup looks OK and matches the setting of APP_BASE.

    When I first read your original post thought the following meant the Program Address Offset in the LM Flash Programmer might have been set to 0x20000 rather than 0x10000:

    Note, for testing I'm just using LM Flash Programmer (Build 1613) to write the bootloader to 0x0000 and the second program to 0x00020000)
  • Chester,

    Thank you so much!!!!!!!!!!!!!!!!!  This resolved my issue!

    I really appreciate the help.

    Bob