Hello. I am trying to implement a application jump from my normal firmware located at memory 0x19000 per recommendations based on the soft device used (s112) to a different application located at memory address 0x70000. I have implemented a version of the application jump as used by the SDK, but have had no luck. The SDK had code that forced the jump to start at the end of the MBR (which I understand to be the soft device). However, I wanted to do a manual jump to a separate application, so I changed the start address to the application memory location. I also added the additional step to set the soft device vector table for later (0x70000), but the jump didn't work before this addition, nor after.
Each time I jump, I end up in the soft device (I think) and eventually hit some kind of hard fault.
My code looks like the following. Is there something obviously wrong I am not getting?
/**@brief Function that sets the stack pointer and link register, and starts executing a particular address. * * @param[in] new_msp The new value to set in the main stack pointer. * @param[in] new_lr The new value to set in the link register. * @param[in] addr The address to execute. */ #if defined ( __CC_ARM ) __ASM __STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr) { MSR MSP, R0; MOV LR, R1; BX R2; } #else __STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr) { __ASM volatile ("MSR MSP, %[arg]" : : [arg] "r" (new_msp)); __ASM volatile ("MOV LR, %[arg]" : : [arg] "r" (new_lr) : "lr"); __ASM volatile ("BX %[arg]" : : [arg] "r" (addr)); } #endif /**@brief Function for booting an app as if the chip was reset. * * @param[in] vector_table_addr The address of the app's vector table. */ __STATIC_INLINE void app_start(uint32_t vector_table_addr) { const uint32_t current_isr_num = (__get_IPSR() & IPSR_ISR_Msk); const uint32_t new_msp = *((uint32_t *)(vector_table_addr)); // The app's Stack Pointer is found as the first word of the vector table. const uint32_t reset_handler = *((uint32_t *)(vector_table_addr + sizeof(uint32_t))); // The app's Reset Handler is found as the second word of the vector table. const uint32_t new_lr = 0xFFFFFFFF; __set_CONTROL(0x00000000); // Set CONTROL to its reset value 0. __set_PRIMASK(0x00000000); // Set PRIMASK to its reset value 0. __set_BASEPRI(0x00000000); // Set BASEPRI to its reset value 0. __set_FAULTMASK(0x00000000); // Set FAULTMASK to its reset value 0. //ASSERT(current_isr_num == 0); // If this is triggered, the CPU is currently in an interrupt. // The CPU is in Thread mode (main context). jump_to_addr(new_msp, new_lr, reset_handler); // Jump directly to the App's Reset Handler. } void nrf_bootloader_app_start_final(uint32_t vector_table_addr) { // Run application app_start(vector_table_addr); } void nrf_bootloader_app_start(void) { uint32_t start_addr = 0x70000;//MBR_SIZE; // Always boot from end of MBR. If a SoftDevice is present, it will boot the app. uint32_t err_code; // Disable and clear interrupts // Notice that this disables only 'external' interrupts (positive IRQn). NVIC->ICER[0]=0xFFFFFFFF; NVIC->ICPR[0]=0xFFFFFFFF; #if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2 NVIC->ICER[1]=0xFFFFFFFF; NVIC->ICPR[1]=0xFFFFFFFF; #endif uint32_t ret_val = NRF_ERROR_INVALID_PARAM; uint32_t address = MBR_SIZE; #if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD) sd_mbr_command_t command = { .command = SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, .params.irq_forward_address_set.address = address, }; ret_val = sd_mbr_command(&command); #endif if (ret_val == NRF_ERROR_INVALID_PARAM) { // Manually set the forward address if this MBR doesn't have the command. *(uint32_t *)(0x20000000) = address; ret_val = NRF_SUCCESS; } err_code = sd_softdevice_vector_table_base_set(0x70000); if (err_code != NRF_SUCCESS) { return false; } nrf_bootloader_app_start_final(start_addr); }