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": [ ... ]}

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.