I'm in the process of jumping from bootloader to application code for MKL15Z128VFT4.
Bootloader Address map:
m_interrupts start 0x00
m_flash_config start 0x400
m_interrupts_ram start 0x1FFFF000
m_text start 0x410
m_data start 0x1FFFF200
m_comm start 0x20002FFD
Application Address map:
m_interrupts start 0x7200
m_flash_config start 0x7400
m_interrupts_ram start 0x1FFFF000
m_text start 0x7410
m_data start 0x1FFFF200
m_comm start 0x20002FFD
I'm able to jump to startup_MKL15Z4.s successfully and debug through SystemInit and init_data_bss where the vector table is copied from application flash to ram and the vector table offset register is set as the RAM address of the interrupt vector table after the application vector table is copied to RAM. This is all good, though I'm not able to make the jump from _start to finding the main function of my application code. Anyone have any suggestions? I've been troubleshooting this for a while now.
Bootloader Code:
//Location of Initial Program Counter for application code
#define APPBOOT_VECTOR 0x7200
void (*bootAddress)(void);
volatile unsigned int * safeBootVector;
volatile unsigned int * appBootVector;
void jumpToAppCode()
{
//converting value appBootVector points to, to a function pointer that takes a void arg and returns void
bootAddress = (void(*)(void))(*appBootVector);
uint32_t appStack = (uint32_t)(APPBOOT_VECTOR);
//disable interrupts just in case
__disable_irq();
//set the vector table offset register to beginning of application vector table
SCB->VTOR = appStack;
__enable_irq();
//set the stack pointer to beginning of application vector table
//__set_MSP(appStack);
//start the application
bootAddress();
}
/*lint -save -e970 Disable MISRA rule (6.3) checking. */
int main(void)
/*lint -restore Enable MISRA rule (6.3) checking. */
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
Flash_Manager fm;
appBootVector = (unsigned int *)(APPBOOT_VECTOR + 4);
//Location of Communication_start shared between application and boot code
int fwUpdateFlagPointer = 0x20002FFD;
//value should equal the value stored at fwUpdateFlagPointer address
//a common address in RAM shared between Application and Bootloader
char value = *((char*)fwUpdateFlagPointer);
// Read FW_UPDATE_FLAG from External SPI flash
unsigned char fwUpdateFlag = fm.readFirmwareUpdateFlag();
//fwUpdateFlag == 7 means booloader portion of FW update from spi flash to uC flash not complete
//value == 2 means application FW update to SPI flash complete
//if FW update to SPI flash hasn't been done and FW update from SPI flash not in progress, jumpt to app
if(value != 2 && fwUpdateFlag != 7)
jumpToAppCode(); //jump to application portion of flash
}
Application portion of Code:
.syntax unified
.arch armv6-m
.section .isr_vector, "a"
.align 2
.globl __isr_vector
__isr_vector:
.long __StackTop /* Top of Stack */
.long Boot_Reset_Handler /* Reset Handler */
.long NMI_Handler /* NMI Handler*/
.long HardFault_Handler /* Hard Fault Handler*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long SVC_Handler /* SVCall Handler*/
.long 0 /* Reserved*/
.long 0 /* Reserved*/
.long PendSV_Handler /* PendSV Handler*/
.long SysTick_Handler /* SysTick Handler*/
/* External Interrupts*/
.long DMA0_IRQHandler /* DMA channel 0 transfer complete*/
.long DMA1_IRQHandler /* DMA channel 1 transfer complete*/
.long DMA2_IRQHandler /* DMA channel 2 transfer complete*/
.long DMA3_IRQHandler /* DMA channel 3 transfer complete*/
.long Reserved20_IRQHandler /* Reserved interrupt*/
.long FTFA_IRQHandler /* Command complete and read collision*/
.long LVD_LVW_IRQHandler /* Low-voltage detect, low-voltage warning*/
.long LLWU_IRQHandler /* Low leakage wakeup Unit*/
.long I2C0_IRQHandler /* I2C0 interrupt*/
.long I2C1_IRQHandler /* I2C1 interrupt*/
.long SPI0_IRQHandler /* SPI0 single interrupt vector for all sources*/
.long SPI1_IRQHandler /* SPI1 single interrupt vector for all sources*/
.long UART0_IRQHandler /* UART0 status and error*/
.long UART1_IRQHandler /* UART1 status and error*/
.long UART2_IRQHandler /* UART2 status and error*/
.long ADC0_IRQHandler /* ADC0 interrupt*/
.long CMP0_IRQHandler /* CMP0 interrupt*/
.long TPM0_IRQHandler /* TPM0 single interrupt vector for all sources*/
.long TPM1_IRQHandler /* TPM1 single interrupt vector for all sources*/
.long TPM2_IRQHandler /* TPM2 single interrupt vector for all sources*/
.long RTC_IRQHandler /* RTC alarm*/
.long RTC_Seconds_IRQHandler /* RTC seconds*/
.long PIT_IRQHandler /* PIT interrupt*/
.long Reserved39_IRQHandler /* Reserved interrupt*/
.long Reserved40_IRQHandler /* Reserved interrupt*/
.long DAC0_IRQHandler /* DAC0 interrupt*/
.long TSI0_IRQHandler /* TSI0 interrupt*/
.long MCG_IRQHandler /* MCG interrupt*/
.long LPTMR0_IRQHandler /* LPTMR0 interrupt*/
.long Reserved45_IRQHandler /* Reserved interrupt*/
.long PORTA_IRQHandler /* PORTA Pin detect*/
.long PORTD_IRQHandler /* PORTD Pin detect*/
.size __isr_vector, . - __isr_vector
/* Flash Configuration */
.section .FlashConfig, "a"
.long 0xFFFFFFFF
.long 0xFFFFFFFF
.long 0xFFFFFFFF
.long 0xFFFFFFFE
.text
.thumb
/* Reset Handler */
.thumb_func
.align 2
.globl Boot_Reset_Handler
.weak Boot_Reset_Handler
.type Boot_Reset_Handler, %function
Boot_Reset_Handler:
cpsid i /* Mask interrupts */
#ifndef __NO_SYSTEM_INIT
bl SystemInit
#endif
bl init_data_bss
cpsie i /* Unmask interrupts */
#ifndef __START
#define __START _start
#endif
#ifndef __ATOLLIC__
bl __START
#else
bl __libc_init_array
bl main
#endif
After _start it jumps to the exception loop....
Sorry, meant to type SysTick->CTRL = 0U
Hello jonathan.guinta@qsc.com ,
- Why enable the interrupt here :
could you try enable the interrupt after jump.
- Do you use KDS IDE ? If yes, there is a code about jump, i think you can refer to :
// relocate vector table
SCB_VTOR = RELOCATED_VECTORS;
JumpToUserApplication(*((unsigned long*)RELOCATED_VECTORS), *((unsigned long*)(RELOCATED_VECTORS+4)));
- There is a bootloader about KL26, i thin you can refer to the jumper code , it is the same as i mentioned above.
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Have a great day,
Alice Yang
Hi Alice,
I tried the code you have suggested and I'm experiencing the exact same behavior. I arrive at the breakpoints I set for the startup_MKL15Z4.s file, I execute the init_data_bss and SystemInit, and then when I step to the __START call, the program jumps to the DefaultISR loop for an exception. If I comment out the SystemInit call, the program will jump from __START to main of my application, but I have to manually step through the code otherwise the exception will be triggered again. I'm not sure what's going on, I'm new to this. Is there an issue restarting the clocks and watchdog in the default code for the SystemInit function? The init_data_bss function appears to be ok transferring the application vector table from flash to RAM and the data rom from flash to RAM.
Regards,
Jon
Update:
So I narrowed it down to here:
void OSA_TimeInit(void)
{
uint64_t divider;
/* Disable timer and interrupt */
SysTick->CTRL = 0U;
/* A write of any value to current value register clears the field to 0, and also clears the SYST_CSR COUNTFLAG bit to 0. */
SysTick->VAL = 0U;
#if FSL_FEATURE_SYSTICK_HAS_EXT_REF
/* Set the clock source back to core freq */
CLOCK_SYS_SetSystickSrc(kClockSystickSrcCore);
#endif
/* Get SysTick counter input frequency and compute divider value */
divider = ((((uint64_t)CLOCK_SYS_GetSystickFreq() * OSA1_TIMER_PERIOD_US)) / 1000000U);
assert(divider != 0U);
/* Set divide input clock of systick timer */
SysTick->LOAD = (uint32_t)(divider - 1U);
/* Set interrupt priority and enable interrupt */
NVIC_SetPriority(SysTick_IRQn, 1U);
/* Run timer and enable interrupt */
SysTick->CTRL = (SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);
}
If I enable the bare metal OSA Timer (System Tick interrupt) and interrupt in the bootloader code, then I can't successfully make the jump from __start to main in the application portion of the code.
I figured it out, it was the OSA_Timer interrupt, it needed to be turned off: SysTick->VTOR = 0U. Once this was disabled, then the jump to main in the application code worked.