This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Files for OTA firmware update stored in flash

Hello,

We are using nRF52840 with SDK 15.2.0, a bootloader, the bootloader settings and the SoftDevice. Our product has a cellular modem to be able to perform OTA firmware updates without BLE. We are currently able to receive and store the new firmware in flash memory, so the next step is to reboot on the bootloader to swap the new application code at the address of the old.

We have tried to store firstly all the .zip DFU file in flash, but according to this answer on an other thread we can't do that. The .zip file contains 3 files : a .bin, a .dat and a .json. The answer said "The bootloader will activate the new image if both init data and FW data are stored correctly."

Can you explain which files must be used and where in the flash memory ? We think FW data is the .bin file but is the init data the .dat ? And is the right location at the first page after the end of the current application ?

Thanks!

Parents
  • Hi,

    We have tried to store firstly all the .zip DFU file in flash, but according to this answer on an other thread we can't do that.

    You should not store the . zip on the nRF (then you would have to have flash to unzip it etc).

    Can you explain which files must be used and where in the flash memory ?

    You should transfer and store the raw binary image (.bin) file as well as the init packet (.dat file). You do not actually have to think about how this is stored. Instead, you can make a transport for your cellular modem similar to the UART transport as described here. Then the DFU library will temporarily store the data for you (somewhere between the application end address and the reserved application data pages).

    I recomend you refer to the project Vidar posted in the thread you linked to as an example of how this can be done. Note that it uses some support that was introduced in SDK 15.3, which is the first SDK with proper support for DFU in the application. If you start playing with that, which is a working example, then you can adapt that to your cellular transport starting off with a known good base. Once that works, you can port it to your application.

  • Thanks for your help.

    In fact we can't use the DFU transport because the new firmware come from an external FTP server, downloaded in several parts and with some extra data we need to filter. We can't modify this behavior. It's the reason why we have created our own storage method in flash memory.

    So we must just know how we can inform the bootloader about the addresses of the .bin and .dat data in the flash to be able to perform the swap.

Reply
  • Thanks for your help.

    In fact we can't use the DFU transport because the new firmware come from an external FTP server, downloaded in several parts and with some extra data we need to filter. We can't modify this behavior. It's the reason why we have created our own storage method in flash memory.

    So we must just know how we can inform the bootloader about the addresses of the .bin and .dat data in the flash to be able to perform the swap.

Children
  • Hi,

    The image (.dat) should be located in bank 1, which is calculated by nrf_dfu_bank1_start_addr(). The init command should be stored in the bootloader settings page (nrf_dfu_settings_t::init_command). Note that this approach described by Vidar describes how you can use the "normal" SDK bootloader to do DFU from the application. This makes a lot of sense in many cases, for instance, if you also want BLE transport in the bootloader, or you need a well-tested solution.

    (If you only intend to do DFU via your modem, then another approach could be to use a thin bootloader such as the IoT backround DFU library (this uses many of the same concepts). However, there is no complete example for the IoT DFU solution, and it is experimental.)

  • Currently the application code starts in memory at address 0x26000 and finishes at 0x58DD1. So the new firmware data (.bin) is stored in the following page at 0x59000.

    The bootloader settings are stored on the last page, at 0xFF000. We have written the init command (.dat) in the nrf_dfu_settings_t structure and calculated the CRCs. Then the modified settings are rewritten in flash.

    Finally, we have tried to reboot on DFU mode with the following code:

    err_code = sd_power_gpregret_clr(0, 0xFFFFFFFF);
    APP_ERROR_CHECK(err_code);
    err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
    APP_ERROR_CHECK(err_code);
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);

    Is it the good way to do what we want? This is not working, the bootloader seems doing nothing during 2 minutes then it reboots on the original application and the settings are reinitialized in flash.

  • Hi Pierre,

    I am sorry, I did not mention that you need to populate bank_1 in the bootloader settings. The bank_code field must be NRF_DFU_BANK_VALID_APP. The bootloader checks this during startup (nrf_bootloader_init() calls nrf_bootloader_fw_activate()), and will continue with activation if the code is NRF_DFU_BANK_VALID_APP.

    Br,

    Einar

  • OK, thanks!

    We have checked what the bootloader do in nrf_bootloader_init() and nrf_bootloader_fw_activate(). It seems ok compared to our settings, but perhaps the problem appears above, in nrf_dfu_settings_init().

    Here is our full nrf_dfu_settings_t structure values after adding the init command:

    • crc = computed value of the settings, like the documentation explains
    • settings_version, app_version and bootloader_version = no modification
    • bank_layout and bank_current = no modification
    • bank_0:
      • image_size and image_crc = no modification
      • bank_code = NRF_DFU_BANK_INVALID
    • bank_1:
      • image_size = size of the new firmware
      • image_crc = computed value of the new firmware
      • bank_code = NRF_DFU_BANK_VALID_APP
    • write_offset and sd_size = no modification
    • progress:
      • command_size = size of the init command
      • command_offset = no modification
      • command_crc = computed value of the init command
      • data_object_size = no modification
      • update_start_address = bank 1 address
    • enter_buttonless_dfu = 1
    • init_command = init command data

    Is it correct? About the CRC of the settings, we must include all the size of the init_command table (256 bytes with several 0xFF at the end) or only the size of the written data?

  • Concerning our last question in the previous post, we have found a difference between the online documentation and the bootloader code about the CRC.

    In the description of the settings structure, we can read "uint32_t nrf_dfu_settings_t::crc CRC for the stored DFU settings, not including the CRC itself."

    But in the comments of the bootloader code, for the settings_crc_get() function, it is written "The crc is calculated from the s_dfu_settings struct, except the crc itself and the init command"

    So we have removed the init command from the CRC calculation but the behavior stays the same.

Related