This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Jump from bootloader to application, SDK 15.3, no SoftDevice

SDK 15.3
NRF52840

Hi, I'm trying to write a very basic bootloader for my application and the memory map is more or less as follows.
0x0000-0x10000 Bootloader
0x10000-0x70000 Bank0
0x70000-0xD0000 Bank1
0xFF000-0xFFFFF Proprietary Flash area

In the bootloader code, it only initializes Flash Settings so that it can read the "Proprietary Flash area", and from there it reads a 32-bit value to find if it should copy application from Bank1 to Bank0 or not.

I don't need SoftDevice, and so I'm thinking to not use MBR and keep it as simple as possible.
I used the USB Serial Bootloader as the base and removes anything I don't need. But, when I jump to application it goes to hard fault.

We had a similar simple bootloader like this in the past, but it was from an older SDK and from 51422 so we couldn't port it as easily.

My question is:
1) Is this design feasible, or do I need to use MBR?
2) Do i need to do anything to forward interrupt to application?

3) I don't see interrupts_disable in SDK 15.3. Do I need to copy this from the old code?

This was the code that worked for us.

#define IRQ_ENABLED             0x01           /**< Field identifying if an interrupt is enabled. */
#define MAX_NUMBER_INTERRUPTS   32

void interrupts_disable(void)
{
    uint32_t interrupt_setting_mask;
    uint8_t  irq;

    // We start the loop from first interrupt, i.e. interrupt 0.
    irq                    = 0;
    // Fetch the current interrupt settings.
    interrupt_setting_mask = NVIC->ISER[0];
    
    for (; irq < MAX_NUMBER_INTERRUPTS; irq++)
    {
        if (interrupt_setting_mask & (IRQ_ENABLED << irq))
        {
            // The interrupt was enabled, and hence disable it.
            NVIC_DisableIRQ((IRQn_Type) irq);
        }
    }        
}

4) The new jump_to_addr is slightly different from the older StartApplication. But they should mean the same right?

//SDK 15.3
//new_msp is the same with "start_addr" in the older code
//addr == new_msp + 0x4
//new_lr == 0xFFFFFFFF
__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));
}

//Older code
__asm void StartApplication(uint32_t start_addr)
{
    LDR   R2, [R0]               ; Get App MSP.
    MSR   MSP, R2                ; Set the main stack pointer to the applications MSP.
    LDR   R3, [R0, #0x00000004]  ; Get application reset vector address.
    BX    R3                     ; No return - stack code is now activated only through SVC and plain interrupts.
    ALIGN
}

Thanks,
Cecylia

  • Hi,

    1) Is this design feasible, or do I need to use MBR?

    Yes, it is feasible. The reason for having an MBR is that it allows the update of the bootloader itself. Since you don't use the SoftDevice and as long as you don't need a way to (safely) update the bootloader, then there is no need for an MBR.

    2) Do i need to do anything to forward interrupt to application?

    Yes. Since you don't use MBR or SoftDevice, the most straightforward would be to simply use the VTOR.

    3) I don't see interrupts_disable in SDK 15.3. Do I need to copy this from the old code?

    The interrupt forwarding in the bootloader example in the SDK depends on the MBR. You can see how it is done there in the implementation of nrf_dfu_mbr_irq_forward_address_set() in <SDK15.3>\components\libraries\bootloader\dfu\nrf_dfu_mbr.c, but this is not relevant if you don't use the MBR.

    4) The new jump_to_addr is slightly different from the older StartApplication. But they should mean the same right?

     Yes.

  • Hi Einar,

    I really appreciate your prompt and very helpful feedback!
    I found more info online based on the keyword "VTOR", since I wasn't sure how to change the VTOR. 

    I just realized that these 2 lines in nrf_bootloader_app_start actually disable all the interrupts:
    NVIC->ICER[0]=0xFFFFFFFF;
    NVIC->ICPR[0]=0xFFFFFFFF;

    I simply added this line right after:
    SCB->VTOR = (uint32_t) start_addr;

    And continued with nrf_bootloader_app_start_final which eventually calls app_start that takes care of setting the new_msp and new reset_handler.

    It works :) No more hard fault.

    Thanks!!
    Cecylia

Related