I used the nRF52840 SDK 15.3.0 dfu secure_bootloader uart example to develop a custom bootloader. I have checked that my application file is correct by trying it without the bootloader. I have also validated that the soft device and application files match what they are expected after a successful DFU.
After the bootloader determines that the app is valid, it proceeds through nrf_bootloader_app_start.c and nrf_bootloader_app_start_final.c but after
jump_to_addr(new_msp, new_lr, reset_handler); // Jump directly to the App's Reset Handler.
the firmware doesn't start the application.
Any ideas why the firmware breakpoint stops at the address in MBR 0xA60 4B01 ldr r3 after the jump and doesn't start the application?

watch1.txt attached is the watch of s_dfu_settings and vector_table_addr immediately before the jump.
Here's nrf_bootloader_app_start:
void nrf_bootloader_app_start(void)
{
uint32_t start_addr = MBR_SIZE; // Always boot from end of MBR. If a SoftDevice is present, it will boot the app.
NRF_LOG_DEBUG("Running nrf_bootloader_app_start with address: 0x%08x", start_addr);
uint32_t err_code;
// Disable and clear interrupts
// Notice that this disables only 'external' interrupts (positive IRQn).
NRF_LOG_DEBUG("Disabling interrupts. NVIC->ICER[0]: 0x%x", NVIC->ICER[0]);
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
//err_code = nrf_dfu_mbr_irq_forward_address_set();
//if (err_code != NRF_SUCCESS)
//{
// NRF_LOG_ERROR("Failed running nrf_dfu_mbr_irq_forward_address_set()");
//}
NRF_LOG_FLUSH();
nrf_bootloader_app_start_final(start_addr);
}
Here's nrf_bootloader_app_start_final:
void nrf_bootloader_app_start_final(uint32_t vector_table_addr)
{
ret_code_t ret_val;
// Protect MBR & bootloader code and params pages.
if (NRF_BOOTLOADER_READ_PROTECT)
{
ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, NRF_BOOTLOADER_READ_PROTECT);
}
// Size of the flash area to protect.
uint32_t area_size;
//area_size = BOOTLOADER_SIZE + NRF_MBR_PARAMS_PAGE_SIZE;
area_size = BOOTLOADER_SIZE;
uint32_t blStartAddr = BOOTLOADER_START_ADDR;
ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR,
area_size,
NRF_BOOTLOADER_READ_PROTECT);
if (!NRF_BOOTLOADER_READ_PROTECT && (ret_val != NRF_SUCCESS))
{
//NRF_LOG_ERROR("Could not protect bootloader and settings pages, 0x%x.", ret_val);
NRF_LOG_ERROR("Could not protect bootloader pages, 0x%x.", ret_val);
}
//ret_val = nrf_bootloader_flash_protect(0,
// //nrf_dfu_bank0_start_addr() + s_dfu_settings.bank_0.image_size,
// nrf_dfu_bank1_start_addr() + s_dfu_settings.bank_1.image_size,
// false);
//if (!NRF_BOOTLOADER_READ_PROTECT && (ret_val != NRF_SUCCESS))
//{
// //NRF_LOG_ERROR("Could not protect SoftDevice and application, 0x%x.", ret_val);
// NRF_LOG_ERROR("Could not protect application, 0x%x.", ret_val);
//}
uint32_t bank0_addr = nrf_dfu_bank0_start_addr();
ret_val = nrf_bootloader_flash_protect(0,ALIGN_TO_PAGE(bank0_addr + s_dfu_settings.bank_0.image_size),false);
if (!NRF_BOOTLOADER_READ_PROTECT && (ret_val != NRF_SUCCESS))
{
NRF_LOG_ERROR("Could not protect bootloader and application, 0x%x.", ret_val);
}
NRF_LOG_INFO("Entering app_start(vector_table_addr).");
// Run application
app_start(vector_table_addr);
}
Here's app_start:
/**@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)
{
NRF_LOG_INFO("In 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 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.
if (current_isr_num == 0)
{
// 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.
}
else
{
// The CPU is in Handler mode (interrupt context).
const uint32_t exception_stack[EXCEPTION_STACK_WORD_COUNT] = // To be copied onto the stack.
{
0x00000000, // New value of R0. Cleared by setting to 0.
0x00000000, // New value of R1. Cleared by setting to 0.
0x00000000, // New value of R2. Cleared by setting to 0.
0x00000000, // New value of R3. Cleared by setting to 0.
0x00000000, // New value of R12. Cleared by setting to 0.
0xFFFFFFFF, // New value of LR. Cleared by setting to all 1s.
reset_handler, // New value of PC. The CPU will continue by executing the App's Reset Handler.
xPSR_T_Msk, // New value of xPSR (Thumb mode set).
};
const uint32_t exception_sp = new_msp - sizeof(exception_stack);
memcpy((uint32_t *)exception_sp, exception_stack, sizeof(exception_stack)); // 'Push' exception_stack onto the App's stack.
jump_to_addr(exception_sp, new_lr, HANDLER_MODE_EXIT); // 'Jump' to the special value to exit handler mode. new_lr is superfluous here.
// exception_stack will be popped from the stack, so the resulting SP will be the new_msp.
// Execution will continue from the App's Reset Handler.
}
}