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.

MSPM0L1105: Stuck in Default_Handler after jump from bootloader to application

Part Number: MSPM0L1105
Other Parts Discussed in Thread: UNIFLASH,

I have FW divided into two parts – bootloader and application. Bootloader is very simple, it jumps into application that is located at different flash address. When I debug the application I see that it is in infinite loop of Default_Handler. When I restart the debug session and stop the run, it's still in Default_Handler. Application do not pause on `__BKPT()` or hardware breakpoint.

Code

 
// bootloader_main.c

#define APP_START_ADDR 0x00001800

typedef void (*pFunction)(void);

int main(void)
{
    uint32_t appStack;
    uint32_t appResetHandler;
    
    pFunction appEntry;
    
    __disable_irq();

    SysTick->CTRL = 0;

    for (int i = 0; i < 3; i++)
    {
        NVIC->ICER[i] = 0xFFFFFFFF;
        NVIC->ICPR[i] = 0xFFFFFFFF;
    }

    SCB->ICSR |= SCB_ICSR_PENDSTCLR_Msk;

    appStack = *((volatile uint32_t*) APP_START_ADDR);
    appResetHandler = *((volatile uint32_t*) (APP_START_ADDR + 4));
    SCB->VTOR = APP_START_ADDR;
    __set_MSP(appStack);
    appEntry = (pFunction) appResetHandler;
    appEntry();

    while (1)
    {
    }
}
 
// bootloader_linker.cmd

-uinterruptVectors
--stack_size=256

MEMORY
{
    FLASH (RX) : origin = 0x00000000, length = 0x00001800
    SRAM (RWX) : origin = 0x20000000, length = 0x00001000
    BCR_CONFIG (R) : origin = 0x41C00000, length = 0x000000FF
    BSL_CONFIG (R) : origin = 0x41C00100, length = 0x00000080
}

SECTIONS
{
    .intvecs: > 0x00000000
    .text : palign(8) {} > FLASH
    .const : palign(8) {} > FLASH
    .cinit : palign(8) {} > FLASH
    .pinit : palign(8) {} > FLASH
    .rodata : palign(8) {} > FLASH
    .ARM.exidx : palign(8) {} > FLASH
    .init_array : palign(8) {} > FLASH
    .binit : palign(8) {} > FLASH
    .TI.ramfunc : load = FLASH, palign(8), run=SRAM, table(BINIT)

    .vtable : > SRAM
    .args : > SRAM
    .data : > SRAM
    .bss : > SRAM
    .sysmem : > SRAM
    .stack : > SRAM (HIGH)

    .BCRConfig : {} > BCR_CONFIG
    .BSLConfig : {} > BSL_CONFIG
}
 
// application_main.c

#include "misc/ticks.hpp"
#include "misc/rt_timer.hpp"

static void tim_reg_64_hz_irq()
{
    static uint8_t counter = 0;
    counter++;

    if (counter >= 64)
    {
        DL_GPIO_togglePins(GPIOA_PORT, GPIOA_LR_PIN);
        counter = 0;
    }
}

misc::RtTimer tim_reg_irq_64_hz(misc::ticks_sec(1) / 64, true, true, tim_reg_64_hz_irq);

int main(void)
{
    __BKPT();
    // hw breakpoint on line below
    __disable_irq();

    int index = 0;

    SYSCFG_DL_init();

    misc_ticks_init();

    __enable_irq();

    tim_reg_irq_64_hz.start();

    while(1);

    misc_ticks_t last = 0;
    while (1) {
        misc_ticks_t now = misc_ticks_now();

        if (now - last > misc::ticks_sec(1))
        {
            DL_GPIO_togglePins(GPIOA_PORT, GPIOA_LR_PIN);
            last = now;
        }
    }
}


// misc_custom.h

#define MISC_TICKS_ENABLE                       (1)

#define MISC_TICKS_PER_SECOND                   (8192)

#define MISC_ASSERT(cond)   do{if(!(cond)) misc_abort();}while(0)

#define MISC_MAX_DEPTH_OF_RECURSIVE_LOCKS       (1000)

#define MISC_TICK_TIMER                         TIMG0
#define MISC_TICK_TIMER_IRQn                    TIMG0_INT_IRQn
#define MISC_TICK_TIMER_IRQHandler              TIMG0_IRQHandler

// -------------------------------------------------------------

// ticks.cpp

namespace misc {

static uint32_t time_overflow = 0; ///< overflow time register

void ticks_update_cmp(uint16_t cmp)
{
    MISC_TICK_TIMER->COUNTERREGS.CC_01[0] = cmp;
}

} /* namespace misc */

using namespace misc;

void misc_ticks_init()
{
    MISC_TICK_TIMER->GPRCM.STAT = 0;
    // reset (key protected)
    MISC_TICK_TIMER->GPRCM.RSTCTL = GPTIMER_RSTCTL_KEY_UNLOCK_W |
        GPTIMER_RSTCTL_RESETASSERT_ASSERT | GPTIMER_RSTCTL_RESETSTKYCLR_CLR;

    wait_for_bit_set(MISC_TICK_TIMER->GPRCM.STAT, GPTIMER_STAT_RESETSTKY_MASK);

    // enable power (key protected)
    MISC_TICK_TIMER->GPRCM.PWREN = GPTIMER_PWREN_KEY_UNLOCK_W | GPTIMER_PWREN_ENABLE_ENABLE;
    delay_cycles(POWER_STARTUP_DELAY);

    // clear pending irq
    NVIC_ClearPendingIRQ(MISC_TICK_TIMER_IRQn);

    // clear irq
    MISC_TICK_TIMER->CPU_INT.ICLR = MISC_TICK_TIMER->CPU_INT.RIS;

    // enable irqs
    NVIC_EnableIRQ(MISC_TICK_TIMER_IRQn);
    set_bit(
        MISC_TICK_TIMER->CPU_INT.IMASK,
        GPTIMER_CPU_INT_IMASK_CCU0_MASK | GPTIMER_CPU_INT_IMASK_L_MASK
    );

    // clock source as busclk
    set_bit(MISC_TICK_TIMER->CLKSEL, GPTIMER_CLKSEL_BUSCLK_SEL_ENABLE);
    // divide 8
    MISC_TICK_TIMER->CLKDIV = 7;
    // prescaler 128
    MISC_TICK_TIMER->COMMONREGS.CPS = 127;
    // clock enable
    set_bit(MISC_TICK_TIMER->COMMONREGS.CCLKCTL, GPTIMER_CCLKCTL_CLKEN_ENABLED);
    // full range counter
    MISC_TICK_TIMER->COUNTERREGS.LOAD = 0xFFFF;

    // enable auto reload
    modify_reg(
        MISC_TICK_TIMER->COUNTERREGS.CTRCTL,
        GPTIMER_CTRCTL_REPEAT_MASK,
        GPTIMER_CTRCTL_REPEAT_REPEAT_1
    );

    // up counting
    modify_reg(
        MISC_TICK_TIMER->COUNTERREGS.CTRCTL,
        GPTIMER_CTRCTL_CM_MASK,
        GPTIMER_CTRCTL_CM_UP
    );

    // counter = 0 on start
    modify_reg(
        MISC_TICK_TIMER->COUNTERREGS.CTRCTL,
        GPTIMER_CTRCTL_CVAE_MASK | GPTIMER_CTRCTL_CZC_MASK |
        GPTIMER_CTRCTL_CAC_MASK | GPTIMER_CTRCTL_CLC_MASK,
        GPTIMER_CTRCTL_CVAE_ZEROVAL | GPTIMER_CTRCTL_CZC_CCCTL0_ZCOND |
        GPTIMER_CTRCTL_CAC_CCCTL0_ACOND | GPTIMER_CTRCTL_CLC_CCCTL0_LCOND
    );

    // compare value
    MISC_TICK_TIMER->COUNTERREGS.CC_01[0] = 0x8000;

    // start timer
    set_bit(MISC_TICK_TIMER->COUNTERREGS.CTRCTL, GPTIMER_CTRCTL_EN_ENABLED);
}

misc_ticks_t misc_ticks_now()
{
    uint32_t cnt;
    uint32_t overflow;
    uint32_t isr1, isr2;

/*1*/    __disable_irq();
/*2*/    overflow = time_overflow;
/*3*/    isr1 = MISC_TICK_TIMER->CPU_INT.MIS;
/*4*/    cnt = misc_ticks16_now();
/*5*/    isr2 = MISC_TICK_TIMER->CPU_INT.MIS;
/*6*/    __enable_irq();

    // check overflow
    isr1 &= GPTIMER_CPU_INT_MIS_L_MASK;
    isr2 &= GPTIMER_CPU_INT_MIS_L_MASK;

    if (!isr1 && !isr2)    //No overflow happened (most common)
    {
        return (Ticks(overflow) << 16) | cnt;
    }
    else if (isr1 && isr2)     //Overflow happened between *1* and *3*, but variable is not updated
    {
        return (Ticks(overflow + 1) << 16) | cnt;     //Add 1 overflow
    }
    else    // overflow happened somewhere between *3* and *5*
    {
        // cnt is assumed to be 0 if overflow happened
        return Ticks(overflow + 1) << 16;     //Add 1 overflow
    }
}

misc_ticks16_t misc_ticks16_now()
{
    return (misc_ticks16_t)MISC_TICK_TIMER->COUNTERREGS.CTR;
}

// irq handler
extern "C" void MISC_TICK_TIMER_IRQHandler(void)
{
    using namespace misc;

    uint32_t mis = MISC_TICK_TIMER->CPU_INT.MIS;
    // clear interrupts
    MISC_TICK_TIMER->CPU_INT.ICLR = mis;

    // overflow interrupt
    if (mis & GPTIMER_CPU_INT_MIS_L_MASK)
    {
        // add one overflow to time
        time_overflow++;
    }

    // compare match interrupt
    if (mis & GPTIMER_CPU_INT_MIS_CCU0_MASK)
    {
        // TIM has just incremented, so no overflow will happen again in near future
        // thus we can obtain 'now' more cheaply than by calling misc_ticks_now()
        RtTimerBase::timer_isr((Ticks(time_overflow) << 16) | MISC_TICK_TIMER->COUNTERREGS.CTR);
    }
}
// application_linker.cmd

-uinterruptVectors
--stack_size=256


MEMORY
{
    FLASH           (RX)  : origin = 0x00001800, length = 0x00004800
    SRAM            (RWX) : origin = 0x20000000, length = 0x00001000
    BCR_CONFIG      (R)   : origin = 0x41C00000, length = 0x000000FF
    BSL_CONFIG      (R)   : origin = 0x41C00100, length = 0x00000080
}

SECTIONS
{
    .intvecs:   > 0x00001800
    .text   : palign(8) {} > FLASH
    .const  : palign(8) {} > FLASH
    .cinit  : palign(8) {} > FLASH
    .pinit  : palign(8) {} > FLASH
    .rodata : palign(8) {} > FLASH
    .ARM.exidx    : palign(8) {} > FLASH
    .init_array   : palign(8) {} > FLASH
    .binit        : palign(8) {} > FLASH
    .TI.ramfunc   : load = FLASH, palign(8), run=SRAM, table(BINIT)

    .vtable :   > SRAM
    .args   :   > SRAM
    .data   :   > SRAM
    .bss    :   > SRAM
    .sysmem :   > SRAM
    .stack  :   > SRAM (HIGH)

    .BCRConfig  : {} > BCR_CONFIG
    .BSLConfig  : {} > BSL_CONFIG
}

 

I assume that this is enough for understanding what it should do.

Debug setup

HW: TI XDS110
IDE: CCS 20.4.1
Flasher: uniFlash 9.4.1

Configuration:

{
    "name": "application",
    "type": "ccs-debug",
    "request": "launch",
    "projectInfo": {
        "name": "application",
        "resourceId": "/application",
        "loadSymbolsOnly": true
    },
    "connections": [
        ...
    ]
}

Pasted image 20260225144706.png

Testing process

- connecting to running application

1) Application from flash 0x0 without bootloader
    - code works, led is repeatedly blinking
2) Bootloader + dummy_app
    - dummy_app blinks 3 times as in code below

    void SysTick_Delay(uint32_t ticks)
    {
        SysTick->LOAD = ticks - 1;
        SysTick->VAL = 0;
        SysTick->CTRL = 5;  // enable with CPU clock
    
        while((SysTick->CTRL & (1 << 16)) == 0);
    
        SysTick->CTRL = 0;
    }
    
    int main(void)
    {
        
        SYSCFG_DL_init();
    
        for (int i = 0; i < 3; i++)
        {
            DL_GPIO_setPins(PA_PORT, PA_LEDR_PIN);
            SysTick_Delay(16000000);
            DL_GPIO_clearPins(PA_PORT, PA_LEDR_PIN);
            SysTick_Delay(16000000);
        }
    
        while (1) {
        }
    }

    - debug works as intended, after reset I can go through main step by step
3) Bootloader + Application
    - application is stuck in Default_Handler
    - VTOR is correctly set
    - in flash at 0x1800 is correctly interrupt vector table

Does MSPM0L1105 need to have set / reset something more than I have already done? I tried everything I could think of but I cannot make the application run.

  • I have registered other handlers. It ended up in HardFault_Handler. I have also discovered the culprit. When using optimalization -O0 for bootloader, for some reason it doesn't work, but for whatever reason it works with -O2.