Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Is it possible to update the bootloader from the main application using nRF5 SDK? Program crashes from flash erase calls.

I need to update a custom bootloader from the main application running on an nRF52840. The bootloader is contained in 0xF0000 to 0xF90D7 in internal flash, and the S140 SoftDevice is present from 0x1000 to 0x253C7. I attempted to run the code below but my program crashes once it attempts to erase a block.

NRF_FSTORAGE_DEF(nrf_fstorage_t bl_flash) =
{
    .evt_handler = fs_event_handler,
    .start_addr = 0x0000F0000,
    .end_addr 	= 0x000100000,
};

static void fs_event_handler(nrf_fstorage_evt_t * evt){
	if (evt->result != NRF_SUCCESS)
		NRF_LOG_ERROR("Flash error");
}

int main (void) {
	ret_code_t err_code = nrf_fstorage_init(&bl_flash, &nrf_fstorage_sd, NULL);
	err_code = nrf_fstorage_erase(&bl_flash, 0xF0000, 1, NULL);
}

I also tried nrf_dfu_flash_erase(). In both cases, the init functions work and return an error code of 0, but the app faults when I try to erase or modify the target memory region. Am I going about this the wrong way, or is it not possible to overwrite bootloader code from the main application?

  • I think that may have been the problem. I have the params page in my original bootloader's linker script with a NOLOAD directive, and the memory region is empty when reading from the Connect programmer.

    MEMORY
    {
      FLASH (rx) : ORIGIN = 0xF0000, LENGTH = 0xE000
      RAM (rwx) :  ORIGIN = 0x20000008, LENGTH = 0x3fff8
      uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
      mbr_params_page (r) : ORIGIN = 0x000FE000, LENGTH = 0x1000
      uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
      bootloader_settings_page (r) : ORIGIN = 0x000FF000, LENGTH = 0x1000
    }
    
    SECTIONS
    {
      .uicr_mbr_params_page :
      {
        PROVIDE(__start_uicr_mbr_params_page = .);
        KEEP(*(SORT(.uicr_mbr_params_page*)))
        PROVIDE(__stop_uicr_mbr_params_page = .);
      } > uicr_mbr_params_page
      .mbr_params_page(NOLOAD) :
      {
        PROVIDE(__start_mbr_params_page = .);
        KEEP(*(SORT(.mbr_params_page*)))
        PROVIDE(__stop_mbr_params_page = .);
      } > mbr_params_page
      .uicr_bootloader_start_address :
      {
        PROVIDE(__start_uicr_bootloader_start_address = .);
        KEEP(*(SORT(.uicr_bootloader_start_address*)))
        PROVIDE(__stop_uicr_bootloader_start_address = .);
      } > uicr_bootloader_start_address
      .bootloader_settings_page(NOLOAD) :
      {
        PROVIDE(__start_bootloader_settings_page = .);
        KEEP(*(SORT(.bootloader_settings_page*)))
        PROVIDE(__stop_bootloader_settings_page = .);
      } > bootloader_settings_page
    }

    Is there a way to add this to units retroactively, or any alternative method to modify the bootloader in this circumstance? This bootloader's linker script looks to be a very lightly modified version of example bootloader linker scripts in the nRF5 SDK.

  • Hi!

    I assume 0x10001018 is just empty as well? (0xFFFFFF)

    Try from the main app to write the mbr_params_page address to 0x10001018 (UICR).

    Example code on how to write to UICR here:  RE: Example code to write to UICR 

    Then try with sd_mbr_command / SD_MBR_COMMAND_COPY_BL again.

  • Thank you! I'm now using a different method for DFU, but if I revisit this method I will update the thread to confirm if the workaround to copy a params page is successful.

Related