Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

fds_init() returns FDS_ERR_NO_PAGES when using bootloader

I have an application that is using FDS to save settings to flash. The application works great as a standalone application, but when I try to use a custom bootloader (same as the secure bootloader for buttonless dfu), I get a FDS_ERR_NO_PAGES when calling fds_init(). This is one of the first calls in the main as listed below. The only difference is the use of the bootloader. I have erased all before loading the bootloader, and Segger is setup to load the additional hex files. Note that I have buttonless DFU working on a separate application that does not use the DFU, and it works as expected. The flash_placement.xml is also attached.

Snippet from main for initialization

int main(void)
{
    ret_code_t err_code;

    // Initialize.
    log_init();
    timers_init();
    leds_init();
    power_management_init();

    // Start execution.
    NRF_LOG_DEBUG("Beacon example started.");

    err_code = nrf_mem_init();
    APP_ERROR_CHECK(err_code);

    err_code = nrf_crypto_init();
    APP_ERROR_CHECK(err_code);

    fds_app_init();

    ble_stack_init();

    gap_params_init();

...
}

fds_app_init() definition:

void fds_app_init(void) {
    NRF_LOG_INFO("Initializing fds...");

    ret_code_t rc;

    /* Register first to receive an event when initialization is complete. */
    (void) fds_register(fds_evt_handler);

    rc = fds_init();    //  <---- The line that fails -----
    APP_ERROR_CHECK(rc);

    /* Wait for fds to initialize. */
    wait_for_fds_ready();

}


Segger additional load files.

debug_additional_load_file="lib/nRF5-sdk/components/softdevice/s132/hex/s132_nrf52_6.0.0_softdevice.hex"
debug_additional_load_file1="$(ProjectDir)/secure_bootloader/pca10040_ble/ses/Output/Release/Exe/secure_bootloader_ble_s132_pca10040.hex"
debug_additional_load_file2="$(ProjectDir)/$(OutDir)/settings.hex"

Linker section macros and placement

linker_section_placement_macros="FLASH_PH_START=0x0;FLASH_PH_SIZE=0x80000;RAM_PH_START=0x20000000;RAM_PH_SIZE=0x10000;FLASH_START=0x26000;FLASH_SIZE=0x5a000;RAM_START=0x20002220;RAM_SIZE=0xDDE0;UICR_PH_START=0x10001000;UICR_PH_SIZE=0x0100;UICR_START=0x10001080"
linker_section_placements_segments="FLASH RX 0x0 0x80000;RAM RWX 0x20000000 0x10000;uicr_bootloader_start_address RX 0x10001014 0x4;UICR RX 0x10001000 0x0100"

<!DOCTYPE Linker_Placement_File>
<Root name="Flash Section Placement">
  <MemorySegment name="FLASH" start="$(FLASH_PH_START)" size="$(FLASH_PH_SIZE)">
    <ProgramSection load="no" name=".reserved_flash" start="$(FLASH_PH_START)" size="$(FLASH_START)-$(FLASH_PH_START)" />
    <ProgramSection alignment="0x100" load="Yes" name=".vectors" start="$(FLASH_START)" />
    <ProgramSection alignment="4" load="Yes" name=".init" />
    <ProgramSection alignment="4" load="Yes" name=".init_rodata" />
    <ProgramSection alignment="4" load="Yes" name=".text" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_soc_observers" inputsections="*(SORT(.sdh_soc_observers*))" address_symbol="__start_sdh_soc_observers" end_symbol="__stop_sdh_soc_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".pwr_mgmt_data" inputsections="*(SORT(.pwr_mgmt_data*))" address_symbol="__start_pwr_mgmt_data" end_symbol="__stop_pwr_mgmt_data" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_ble_observers" inputsections="*(SORT(.sdh_ble_observers*))" address_symbol="__start_sdh_ble_observers" end_symbol="__stop_sdh_ble_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(SORT(.log_const_data*))" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_balloc" inputsections="*(.nrf_balloc*)" address_symbol="__start_nrf_balloc" end_symbol="__stop_nrf_balloc" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_state_observers" inputsections="*(SORT(.sdh_state_observers*))" address_symbol="__start_sdh_state_observers" end_symbol="__stop_sdh_state_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_stack_observers" inputsections="*(SORT(.sdh_stack_observers*))" address_symbol="__start_sdh_stack_observers" end_symbol="__stop_sdh_stack_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_req_observers" inputsections="*(SORT(.sdh_req_observers*))" address_symbol="__start_sdh_req_observers" end_symbol="__stop_sdh_req_observers" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_queue" inputsections="*(.nrf_queue*)" address_symbol="__start_nrf_queue" end_symbol="__stop_nrf_queue" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_command" inputsections="*(.cli_command*)" address_symbol="__start_cli_command" end_symbol="__stop_cli_command" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".crypto_data" inputsections="*(SORT(.crypto_data*))" address_symbol="__start_crypto_data" end_symbol="__stop_crypto_data" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections" address_symbol="__start_nrf_sections" />
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data"  inputsections="*(SORT(.log_dynamic_data*))" runin=".log_dynamic_data_run"/>
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data"  inputsections="*(.fs_data*)" runin=".fs_data_run"/>
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".cli_sorted_cmd_ptrs"  inputsections="*(.cli_sorted_cmd_ptrs*)" runin=".cli_sorted_cmd_ptrs_run"/>
    <ProgramSection alignment="4" load="Yes" name=".dtors" />
    <ProgramSection alignment="4" load="Yes" name=".ctors" />
    <ProgramSection alignment="4" load="Yes" name=".rodata" />
    <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" />
    <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" />
    <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" />
    <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" />
  </MemorySegment>
  <MemorySegment name="RAM" start="$(RAM_PH_START)" size="$(RAM_PH_SIZE)">
    <ProgramSection load="no" name=".reserved_ram" start="$(RAM_PH_START)" size="$(RAM_START)-$(RAM_PH_START)" />
    <ProgramSection alignment="0x100" load="No" name=".vectors_ram" start="$(RAM_START)" address_symbol="__app_ram_start__"/>
    <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run" address_symbol="__start_nrf_sections_run" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".log_dynamic_data_run" address_symbol="__start_log_dynamic_data" end_symbol="__stop_log_dynamic_data" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".cli_sorted_cmd_ptrs_run" address_symbol="__start_cli_sorted_cmd_ptrs" end_symbol="__stop_cli_sorted_cmd_ptrs" />
    <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run_end" address_symbol="__end_nrf_sections_run" />
    <ProgramSection alignment="4" load="No" name=".fast_run" />
    <ProgramSection alignment="4" load="No" name=".data_run" />
    <ProgramSection alignment="4" load="No" name=".tdata_run" />
    <ProgramSection alignment="4" load="No" name=".bss" />
    <ProgramSection alignment="4" load="No" name=".tbss" />
    <ProgramSection alignment="4" load="No" name=".non_init" />
    <ProgramSection alignment="4" size="__HEAPSIZE__" load="No" name=".heap" />
    <ProgramSection alignment="8" size="__STACKSIZE__" load="No" place_from_segment_end="Yes" name=".stack"  address_symbol="__StackLimit" end_symbol="__StackTop"/>
    <ProgramSection alignment="8" size="__STACKSIZE_PROCESS__" load="No" name=".stack_process" />
  </MemorySegment>
  <MemorySegment name="uicr_bootloader_start_address" start="0x10001014" size="0x4">
    <ProgramSection alignment="4" keep="Yes" load="Yes" name=".uicr_bootloader_start_address" address_symbol="__start_uicr_bootloader_start_address" end_symbol="__stop_uicr_bootloader_start_address" start = "0x10001014" size="0x4" />
  </MemorySegment>
  <MemorySegment name="UICR" start="$(UICR_PH_START)" size="$(UICR_PH_SIZE)">
    <ProgramSection load="no" name=".reserved_uicr" start="$(UICR_PH_START)" size="$(UICR_START)-$(UICR_PH_START)"/>
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress00" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress01" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress02" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress03" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress04" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress05" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress06" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress07" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress08" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress09" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress10" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress11" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress12" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress13" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress14" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress15" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress16" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress17" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress18" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress19" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress20" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress21" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress22" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress23" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress24" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress25" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress26" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress27" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress28" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress29" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress30" />
    <ProgramSection alignment="4" load="Yes" keep="Yes" name=".uicrCustomerAddress31" />
  </MemorySegment>
</Root>

  • The problem is that your application is configured to use the entire flash region, i.e. FLASH_START(0x26000) + FLASH_SIZE(0x5a000) = 0x80000 == FLASH_PH_SIZE. You need to set the FLASH_SIZE = Bootloader Start Address(0x78000) - FLASH_START(0x26000) =  0x52000

  • That didn't work. I still get the same error. In case this matters, here are the FDS settings and bootloader flash placement.

    #define FDS_VIRTUAL_PAGES 5
    
    #define FDS_VIRTUAL_PAGE_SIZE 1024
    
    #define FDS_OP_QUEUE_SIZE 20
    


    Bootloader flash placement settings:

    linker_section_placement_macros="FLASH_PH_START=0x0;FLASH_PH_SIZE=0x80000;RAM_PH_START=0x20000000;RAM_PH_SIZE=0x10000;FLASH_START=0x72000;FLASH_SIZE=0xc000;RAM_START=0x200057b8;RAM_SIZE=0xa848"
    linker_section_placements_segments="FLASH RX 0x0 0x80000;RAM RWX 0x20000000 0x10000;uicr_mbr_params_page RX 0x10001018 0x4;mbr_params_page RX 0x0007E000 0x1000;bootloader_settings_page RX 0x0007F000 0x1000;uicr_bootloader_start_address RX 0x10001014 0x4"

    <!DOCTYPE Linker_Placement_File>
    <Root name="Flash Section Placement">
      <MemorySegment name="FLASH" start="$(FLASH_PH_START)" size="$(FLASH_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_flash" start="$(FLASH_PH_START)" size="$(FLASH_START)-$(FLASH_PH_START)" />
        <ProgramSection alignment="0x100" load="Yes" name=".vectors" start="$(FLASH_START)" />
        <ProgramSection alignment="4" load="Yes" name=".init" />
        <ProgramSection alignment="4" load="Yes" name=".init_rodata" />
        <ProgramSection alignment="4" load="Yes" name=".text" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".crypto_data" inputsections="*(SORT(.crypto_data*))" address_symbol="__start_crypto_data" end_symbol="__stop_crypto_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_queue" inputsections="*(.nrf_queue*)" address_symbol="__start_nrf_queue" end_symbol="__stop_nrf_queue" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".dfu_trans" inputsections="*(SORT(.dfu_trans*))" address_symbol="__start_dfu_trans" end_symbol="__stop_dfu_trans" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_const_data" inputsections="*(SORT(.log_const_data*))" address_symbol="__start_log_const_data" end_symbol="__stop_log_const_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".nrf_balloc" inputsections="*(.nrf_balloc*)" address_symbol="__start_nrf_balloc" end_symbol="__stop_nrf_balloc" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".svc_data" inputsections="*(.svc_data*)" address_symbol="__start_svc_data" end_symbol="__stop_svc_data" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_ble_observers" inputsections="*(SORT(.sdh_ble_observers*))" address_symbol="__start_sdh_ble_observers" end_symbol="__stop_sdh_ble_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_state_observers" inputsections="*(SORT(.sdh_state_observers*))" address_symbol="__start_sdh_state_observers" end_symbol="__stop_sdh_state_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_stack_observers" inputsections="*(SORT(.sdh_stack_observers*))" address_symbol="__start_sdh_stack_observers" end_symbol="__stop_sdh_stack_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_req_observers" inputsections="*(SORT(.sdh_req_observers*))" address_symbol="__start_sdh_req_observers" end_symbol="__stop_sdh_req_observers" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".sdh_soc_observers" inputsections="*(SORT(.sdh_soc_observers*))" address_symbol="__start_sdh_soc_observers" end_symbol="__stop_sdh_soc_observers" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections" address_symbol="__start_nrf_sections" />
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".log_dynamic_data"  inputsections="*(SORT(.log_dynamic_data*))" runin=".log_dynamic_data_run"/>
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".fs_data"  inputsections="*(.fs_data*)" runin=".fs_data_run"/>
        <ProgramSection alignment="4" load="Yes" name=".dtors" />
        <ProgramSection alignment="4" load="Yes" name=".ctors" />
        <ProgramSection alignment="4" load="Yes" name=".rodata" />
        <ProgramSection alignment="4" load="Yes" name=".ARM.exidx" address_symbol="__exidx_start" end_symbol="__exidx_end" />
        <ProgramSection alignment="4" load="Yes" runin=".fast_run" name=".fast" />
        <ProgramSection alignment="4" load="Yes" runin=".data_run" name=".data" />
        <ProgramSection alignment="4" load="Yes" runin=".tdata_run" name=".tdata" />
      </MemorySegment>
      <MemorySegment name="RAM" start="$(RAM_PH_START)" size="$(RAM_PH_SIZE)">
        <ProgramSection load="no" name=".reserved_ram" start="$(RAM_PH_START)" size="$(RAM_START)-$(RAM_PH_START)" />
        <ProgramSection alignment="0x100" load="No" name=".vectors_ram" start="$(RAM_START)" address_symbol="__app_ram_start__"/>
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run" address_symbol="__start_nrf_sections_run" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".log_dynamic_data_run" address_symbol="__start_log_dynamic_data" end_symbol="__stop_log_dynamic_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".fs_data_run" address_symbol="__start_fs_data" end_symbol="__stop_fs_data" />
        <ProgramSection alignment="4" keep="Yes" load="No" name=".nrf_sections_run_end" address_symbol="__end_nrf_sections_run" />
        <ProgramSection alignment="4" load="No" name=".fast_run" />
        <ProgramSection alignment="4" load="No" name=".data_run" />
        <ProgramSection alignment="4" load="No" name=".tdata_run" />
        <ProgramSection alignment="4" load="No" name=".bss" />
        <ProgramSection alignment="4" load="No" name=".tbss" />
        <ProgramSection alignment="4" load="No" name=".non_init" />
        <ProgramSection alignment="4" size="__HEAPSIZE__" load="No" name=".heap" />
        <ProgramSection alignment="8" size="__STACKSIZE__" load="No" place_from_segment_end="Yes" name=".stack"  address_symbol="__StackLimit" end_symbol="__StackTop"/>
        <ProgramSection alignment="8" size="__STACKSIZE_PROCESS__" load="No" name=".stack_process" />
      </MemorySegment>
      <MemorySegment name="mbr_params_page" start="0x0007E000" size="0x1000">
        <ProgramSection alignment="4" keep="Yes" load="No" name=".mbr_params_page" address_symbol="__start_mbr_params_page" end_symbol="__stop_mbr_params_page" start = "0x0007E000" size="0x1000" />
      </MemorySegment>
      <MemorySegment name="bootloader_settings_page" start="0x0007F000" size="0x1000">
        <ProgramSection alignment="4" keep="Yes" load="No" name=".bootloader_settings_page" address_symbol="__start_bootloader_settings_page" end_symbol="__stop_bootloader_settings_page" start = "0x0007F000" size="0x1000" />
      </MemorySegment>
      <MemorySegment name="uicr_mbr_params_page" start="0x10001018" size="0x4">
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".uicr_mbr_params_page" address_symbol="__start_uicr_mbr_params_page" end_symbol="__stop_uicr_mbr_params_page" start = "0x10001018" size="0x4" />
      </MemorySegment>
      <MemorySegment name="uicr_bootloader_start_address" start="0x10001014" size="0x4">
        <ProgramSection alignment="4" keep="Yes" load="Yes" name=".uicr_bootloader_start_address" address_symbol="__start_uicr_bootloader_start_address" end_symbol="__stop_uicr_bootloader_start_address" start = "0x10001014" size="0x4" />
      </MemorySegment>
    </Root>
    
  • So did you set the APPLICATION FLASH_SIZE = Bootloader Start Address(0x72000) - FLASH_START(0x26000) =  0x46000?

  • I tried that, but it did not work either. However, it put me on the right track. I switched to the Release version of the bootloader which had the following flash placements, and updated the application flash placement as you suggested. I also had an issue with the RAM placement for the DFU and GATT sdk_config parameters to allow for the DFU characteristic. Ultimately, here are the settings that worked. It would be extremely helpful if there was a page on the Nordic site to help compute these values based on the desired configuration, with/without bootloader, and target.

    Bootloader flash placement:

    linker_section_placement_macros="FLASH_PH_START=0x0;FLASH_PH_SIZE=0x80000;RAM_PH_START=0x20000000;RAM_PH_SIZE=0x10000;FLASH_START=0x78000;FLASH_SIZE=0x6000;RAM_START=0x200057b8;RAM_SIZE=0xa848"
    linker_section_placements_segments="FLASH RX 0x0 0x80000;RAM RWX 0x20000000 0x10000;uicr_mbr_params_page RX 0x10001018 0x4;mbr_params_page RX 0x0007E000 0x1000;bootloader_settings_page RX 0x0007F000 0x1000;uicr_bootloader_start_address RX 0x10001014 0x4"

    Application flash and RAM placement:

    linker_section_placement_macros="FLASH_PH_START=0x0;FLASH_PH_SIZE=0x80000;RAM_PH_START=0x20000000;RAM_PH_SIZE=0x10000;FLASH_START=0x26000;FLASH_SIZE=0x46000;RAM_START=0x20002C10;RAM_SIZE=0xD3F0;UICR_PH_START=0x10001000;UICR_PH_SIZE=0x0100;UICR_START=0x10001080"
    linker_section_placements_segments="FLASH RX 0x0 0x80000;RAM RWX 0x20000000 0x10000;uicr_bootloader_start_address RX 0x10001014 0x4;UICR RX 0x10001000 0x0100"

    Application sdk_config.h changes to support DFU (assuming GATT is being used for other characteristics as well)

    • Add 1 to NRF_BLE_QWR_MAX_ATTR
    • Add 1 to NRF_SDH_BLE_VS_UUID_COUNT
Related