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?

Parents Reply Children
  • I just attempted this method, but unfortunately it did not successfully modify the bootloader region. I tested the code below and got a return code of 4, which I believe corresponds to NRF_ERR_NO_MEM. I'm using a very small 6-byte array and testing this in a sandbox environment, so I suspect I'm either going about this method incorrectly or I may need to initialize something else before calling the sd_mbr_command?

    /* Enable SoftDevice */
    
    ret_code_t err_code;
    err_code = nrf_sdh_enable_request();
    APP_ERROR_CHECK(err_code);
    
    uint32_t ram_start = 0;
    err_code = nrf_sdh_ble_app_ram_start_get(&ram_start);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrf_sdh_ble_enable(&ram_start);
    APP_ERROR_CHECK(err_code);
    
    /* MBR->SD method */
    
    uint8_t bootloader_bin[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
    uint32_t bootloader_bin_len = 6;
    uint32_t len_words = bootloader_bin_len / sizeof(uint32_t);
    
    sd_mbr_command_t command =
    {
        .command = SD_MBR_COMMAND_COPY_BL,
        .params.copy_bl.bl_src = bootloader_bin,
        .params.copy_bl.bl_len = len_words
    };
    uint32_t ret_val = sd_mbr_command(&command);
    NRF_LOG_INFO("ret: %d", ret_val);

    I also tried the methods below, making one build for each and commenting out the other methods. They all return NRF_SUCCESS, but the bootloader is still present and functional after POR and the memory region is unchanged based on the device memory layouts from the nRF Connect Programmer.

    /* SoftDevice library method */
    err_code = sd_flash_page_erase(240);
    APP_ERROR_CHECK(err_code);
    
    /* DFU library method */
    err_code = nrf_dfu_flash_init(true);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_dfu_flash_erase(0xF0000, 1, NULL);
    APP_ERROR_CHECK(err_code);
    	
    	
    /* Flash storage library method */
    nrf_fstorage_api_t * p_fs_api = &nrf_fstorage_sd;
    err_code = nrf_fstorage_init(&bl_flash, &nrf_fstorage_sd, NULL);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_fstorage_erase(&bl_flash, 0xF0000, 1, NULL);
    APP_ERROR_CHECK(err_code);

  • Hi!

    rbmarcus said:
    I tested the code below and got a return code of 4, which I believe corresponds to NRF_ERR_NO_MEM. I'm using a very small 6-byte array and testing this in a sandbox environment, so I suspect I'm either going about this method incorrectly or I may need to initialize something else before calling the sd_mbr_command?

    Sounds like you might not have the mbr params page in flash present.

  • 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