Custom bootloader stuck in nrf_dfu_mbr_init_sd()

Device: nRF52840
Softdevice: 140
SDK: 17.1.0

I'm trying to develop a custom bootloader that will determine which of two images (A or B) to jump to. The memory map that I'm aiming for is:

Flash Memory Map (256 pages of 4096 bytes = 1MByte):
MBR            0x00000000 - 0x00000FFF (0x1000)
Softdevice     0x00001000 - 0x00026FFF (0x26000)
Bootloader     0x00027000 - 0x00033FFF (0xD000)
Image A        0x00034000 - 0x00097FFF (0x64000)
Image B        0x00098000 - 0x000FBFFF (0x64000)
MBR store      0x000FD000 - 0x000FDFFF (0x1000)
Image A Config 0x000FE000 - 0x000FEFFF (0x1000)
Image B Config 0x000FF000 - 0x000FFFFF (0x1000)

I've been following the information from these similar posts:

https://devzone.nordicsemi.com/f/nordic-q-a/84917/porting-project-from-sdk12-3-to-sdk17-and-sd132-to-sd140-unable-to-start-custom-application-from-custom-bootloader-no-dfu-starting-after-sd-in-flash-storage/353891

https://devzone.nordicsemi.com/f/nordic-q-a/33610/can-t-jump-to-a-custom-app-location-using-nrf_bootloader_app_start-with-sdk-v15

Here is the custom bootloader code:

#include <stdint.h>
#include "boards.h"
#include "nrf_mbr.h"
#include "app_error.h"
#include "app_error_weak.h"
#include "nrf_dfu_mbr.h"
#include "nrf_delay.h"
#include "nrf_sdm.h"


void jump_to_addr2(uint32_t new_msp, uint32_t addr)
{
    __set_MSP(new_msp);
    ((void (*)(void))addr)();
}


void app_start2(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.

    __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_addr2(new_msp, reset_handler); // Jump directly to the App's Reset Handler.
}

void nrf_bootloader_app_start_old(uint32_t start_addr)
{
    printf("Running nrf_bootloader_app_start with address: 0x%08lx\r\n", start_addr);

    uint32_t err_code;

    //NRF_LOG_INFO("Initializing SD in mbr\r\n");
    err_code = nrf_dfu_mbr_init_sd();
    if(err_code != NRF_SUCCESS)
    {
        printf("Failed running nrf_dfu_mbr_init_sd\r\n");
        return;
    }

    // Disable interrupts
    printf("Disabling interrupts\r\n");

    NVIC->ICER[0]=0xFFFFFFFF;
#if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2
    NVIC->ICER[1]=0xFFFFFFFF;
#endif

    // Set the sd softdevice vector table base address
    printf("Setting SD vector table base: 0x%08lx\r\n", start_addr);
    err_code = sd_softdevice_vector_table_base_set(start_addr);
    if(err_code != NRF_SUCCESS)
    {
        printf("Failed running sd_softdevice_vector_table_base_set\r\n");
        return;
    }

    // Run application
    //nrf_bootloader_app_start_impl(start_addr);
	app_start2(start_addr);
}

int main(void)
{
	/* APP start flash address: 0x34000 */
	nrf_bootloader_app_start_old(0x34000);
}

The bootloader linker script has:

MEMORY
{
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0xd000
RAM (rwx) : ORIGIN = 0x20002BF0, LENGTH = 0x3D410
}

I'm setting the custom location for the MBR storage using these changes in nrf_mbr.h:
#define MBR_BOOTLOADER_ADDR (0xFDFF8) // MBR store: 0x000FD000 - 0x000FDFFF (0x1000)
#define MBR_PARAM_PAGE_ADDR (0xFDFFC) // MBR store: 0x000FD000 - 0x000FDFFF (0x1000)

When I run the bootloader it hangs in the call to nrf_dfu_mbr_init_sd(). I presume I'm missing something important in my bootloader code. Can someone explain what I've done wrong here?

Thanks.

Parents Reply Children
  • Hi Vidar,

    I have come across another problem. I'm now trying to initialise the softdevice in the custom bootloader; this is because I need the bootloader to be able to read and write to the Image A/B config areas of flash, so I want to be able to use these functions in the bootloader:

    sd_flash_write()

    sd_flash_page_erase()

    and process the sys_evt_dispatch() callbacks. However when I try to initialise the softdevice in the bootloader, it hangs at the call to:

    nrf_sdh_enable_request()

    I'm assuming that this is because the softdevice vector table base is pointing to the image not the bootloader. What is the correct way to deal with this? Should the bootloader adjust the softdevice vector table base back to itself at the start like this:

    sd_softdevice_vector_table_base_set(bootloader_start_addr)
    
    ...
    
    // Call flash read/write functions
    
    sd_softdevice_vector_table_base_set(application_start_addr)
    
    // Jump to application

    Or would it be better to try and access the read/write/erase flash operations without using the softdevice (if that's possible)?

  • Hi,

    You need to call nrf_dfu_mbr_init_sd(); followed by sd_softdevice_vector_table_base_set(<bootloader start address>); before you can make any Softdevice API calls. The SVC interrupt will not be forwarded to the Softdevice otherwise.

    nordic_pdaj said:
    Or would it be better to try and access the read/write/erase flash operations without using the softdevice (if that's possible)?

    Yes, there is slightly less overhead if you can access the NVMC directly. The "flashwrite" example in /examples/peripheral/flashwrite/ demonstrates how you can use the nrf_nvmc driver.

  • Thanks Vidar, I used the NVMC flash writing based on the 'flashwrite' example and it is working fine now. 

Related