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

Related