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

nRF5 SDK custom bootloader, attempting flash write operation returns NRF_LOG_INTERNAL and NRF_ERROR_INVALID_ADDR

I'm writing a custom bootloader for an nRF52840 using the nRF5 SDK v15.0.0. This bootloader uses the SoftDevice to receive BLE packets containing binary data for the DFU. Write operations don't work and I can't trace back the source of the error, what could be going wrong with my code?

NRF_FSTORAGE_DEF(nrf_fstorage_t dfu_flash) =
    {
        .evt_handler = dfu_flash_callback,
        .start_addr = 0x000070000,
        .end_addr = 0x0000E0000,
};

void dfu_flash_callback(nrf_fstorage_evt_t *evt) {
    NRF_LOG_INFO("evt: %d result: %d", evt->id, evt->result);
}

void flash_manager_init(uint32_t fw_size, uint32_t fw_crc) {
    p_fs_api = &nrf_fstorage_sd;
    ret_code_t err_code = nrf_fstorage_init(&dfu_flash, p_fs_api, dfu_flash_callback);
    if (err_code == NRF_SUCCESS) {
        size_received = 77388; // temporary hardcoded value
        crc_received = fw_crc;
        uint32_t num_pages = MIN(CEIL_DIV(size_received, PAGE_SIZE), MAX_NUM_PAGES);
        err_code = nrf_fstorage_erase(&dfu_flash, dfu_flash.start_addr, num_pages, dfu_flash_callback);
        NRF_LOG_INFO("erase err: %d, pages: %d, bytes: 0x%X", err_code, num_pages, size_received);
    }
    is_dfu_started = (err_code == NRF_SUCCESS);
}

void flash_manager_write(uint8_t *data, uint32_t cur_idx, uint32_t len) {
    if (!is_dfu_started)
        return;

    payload_loc = dfu_flash.start_addr + cur_idx;

    static uint8_t binary_chunk[200];
    memcpy(binary_chunk, data, len);
    uint32_t err_code = nrf_fstorage_write(&dfu_flash, payload_loc, binary_chunk, len, dfu_flash_callback);
    NRF_LOG_INFO("idx: %d, payload loc: %p, length: %d, err: %d", cur_idx, payload_loc, len, err_code);
}

Direct calls fstorage functions all return NRF_SUCCESS, and the callback for flash erase works, but any flash write callbacks provide an error NRF_LOG_INTERNAL. I managed to trace the problem to this function in nrf_fstorage_sd.c:

static uint32_t write_execute(nrf_fstorage_sd_op_t const * p_op)
{
    uint32_t chunk_len;

    chunk_len = MIN(p_op->write.len - p_op->write.offset, NRF_FSTORAGE_SD_MAX_WRITE_SIZE);
    chunk_len = MAX(1, chunk_len / m_flash_info.program_unit);

    /* Cast to p_src to uint32_t to perform arithmetic. */
    uint32_t       * p_dest = (uint32_t*)(p_op->write.dest + p_op->write.offset);
    uint32_t const * p_src  = (uint32_t*)((uint32_t)p_op->write.p_src + p_op->write.offset);

    return sd_flash_write(p_dest, p_src, chunk_len);
}

Here, sd_flash_write returns NRF_ERROR_INVALID_ADDR, which seems to be the source of the problem. I couldn't narrow down the problem beyond this, because the only definition I found for sd_flash_write is in ser_app_hal_nrf5x.c, and the function from this library is not called (checked with print statements and modifying return values). I found some relevant macros in the SDK config file, but none of these seem like they could be causing the issue:

#ifndef NRF_FSTORAGE_ENABLED
#define NRF_FSTORAGE_ENABLED 1
#endif

#ifndef NRF_FSTORAGE_PARAM_CHECK_DISABLED
#define NRF_FSTORAGE_PARAM_CHECK_DISABLED 1
#endif

#ifndef NRF_FSTORAGE_SD_QUEUE_SIZE
#define NRF_FSTORAGE_SD_QUEUE_SIZE 16
#endif

#ifndef NRF_FSTORAGE_SD_MAX_RETRIES
#define NRF_FSTORAGE_SD_MAX_RETRIES 8
#endif

#ifndef NRF_FSTORAGE_SD_MAX_WRITE_SIZE
#define NRF_FSTORAGE_SD_MAX_WRITE_SIZE 4096
#endif

Parents Reply
  • Hi,

    Which address did you attempt to write to when you got NRF_ERROR_INVALID_ADDR? Are you able to log it or check with a debugger? You can get this error in a few different cases:

    • If the source or destination adsdress is not word aligned
    • If the destination address is outside of the physical address space of the device

    For reference, if you try to write over the SoftDevice itself, you will get a different error: NRF_ERROR_FORBIDDEN.

Children
  • If there were a word alignment issue, wouldn't this be rejected on the initial call to nrf_fstorage_write rather the error code being passed into the callback handler? I attempt to write a 200-byte chunk into address 0x70000, and the source address comes from static uint8_t binary_chunk[200]. This process originally worked when it was used in the main app, but began reporting errors after I shifted the logic into the bootloader. The flash and RAM regions from the bootloader are taken from the secure bootloader sample in 15.0.0:

    MEMORY
    {
      FLASH (rx) : ORIGIN = 0xf1000, LENGTH = 0xd000
      RAM (rwx) :  ORIGIN = 0x200057b8, LENGTH = 0x3a848
      uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
      mbr_params_page (r) : ORIGIN = 0x000FE000, LENGTH = 0x1000
      bootloader_settings_page (r) : ORIGIN = 0x000FF000, LENGTH = 0x1000
      uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
    }

  • Hi,

    I agree with your resoning, fstorage also checks for word alignment and boundaries. However, I do not see any other reason for getting NRF_ERROR_INVALID_ADDR returned from a call to sd_flash_write() when looking at the SoftDevice implementation. Can you log the parameters you pass to each call to sd_flash_write() so that we can see which exact parameters you call it with when you get the unexpected NRF_ERROR_INVALID_ADDR returned?

Related