DFU approach from cloud to ESP32 to nRF52840

Hi,

My setup include a nRF52840-DK board that has an ESP32 WiFi module connected to it via UART. The idea is to source the new firmware from a server located in the cloud.

GCC toolchain,

Running FreeRTOS,

SDK 15.2.0

I am getting really confused after reading all the information on DFU and how I should be doing it. Simon also recently posted an article on DFU using Connect SDK https://devzone.nordicsemi.com/guides/nrf-connect-sdk-guides/b/software/posts/ncs-dfu

However, we are not using NCS at the moment.

Questions that I asked myself or still confused about are:

  1. Should I be using background DFU or should I be modifying the bootloader to perform the DFU?
  2. Where do I get the bin file from? I have a .zip package from the build output. Is that the bin file to use?
  3. What is an init packet? Is that the .dat file that comes in the .zip package? How do you trigger the init packet? Via application or bootloader?
  4. What is this bootloader settings file?
  5. If I am using dual bank update, how do I specify the flash address for the second bank where the updated firmware gets written to?
  6. How to let the bootloader knows that there is a new firmware in the second bank for validation and swap over? 
  7. What transport should I be looking at? I assume serial - UART?

My initial approach is to write my own in a simplified manner.

The application will issue HTTP GET to the server and retrieve data chunks of the binary until the whole bin file is received. As it receives the chunks, it writes to a flash location.

After the whole bin file is received, the CPU reboots and the application copies the new firmware, overriding the old firmware in place.

Will that "upset" the bootloader when it reboots next time seeing that the firmware signature is different from the one being overwritten?

This is not foolproof as there is no validation and checks for data corruption. It's also not the "proper" way that Nordic perform DFU.

I hope someone can help with those questions and shed some light on the best method to approach this (given my setup, NRF52-ESP32-cloud).

What are the articles that I should focus reading up on. 

  • Thanks Hung, I will see if I can update my SDK version.

    Can you help with question 1 please?

  • Hi Jason, 

    Please have a look at the function nrf_dfu_bank1_start_addr() in nrf_dfu_utils.c . It's used in this function update_data_addr_get() 

    Basically Bank1 starts right after Bank0 . So it dynamically changes depending on the size of the application which placed at bank0. This is only applied for dual bank update.  

  • Hi,

    I am still working on the DFU, progress has been slow.

    I am trying to access the global variable s_dfu_settings, that has been loaded into memory by my bootloader app hex, in my application code (a separate hex)

    I tried to print the value in the settings e.g. app_version or bank_0.image_size and the result is always zero. I did things like

    extern "C" nrf_dfu_settings_t s_dfu_settings;
     in my app code but didn't help. I am puzzled why I can't see s_dfu_settings in my app code.

    However, when I do direct pointer access to the memory address from app, I can access the settings and values.

    The bootloader code is built with nrf_dfu_settings.c included in the makefile. Do I have to include nrf_dfu_settings.c this same file in my application build? I did the inclusion but still can't "see" the global variable s_dfu_settings.

    Also do i need to include  bootloader_settings_page (r) : ORIGIN = 0x000FF000, LENGTH = 0x1000 in my linker script for my application since it's included in the linker script for the bootloader.

    Hope I am making sense here.

  • Hi Jason, 

    The bootloader and the application are 2 separated image. So you can't use the normal "extern" to get the visibility of the variable(s) from bootloader to application. 

    There is a way to share data and function between the 2 images is to use the SVCI interface. You can have a look at the ble_app_buttonless example , where we use SVCI to either send bond information or advertising name to the bootloader via this interface. 

    But anyway, for bootloader setting, it's easier that you access flash directly from the application than trying to communicate with bootloader via SVCI on this. What you need to do is to read the bootloader setting from flash and write new value to flash after you finished receiving image. Then you reset to the bootloader. The bootloader will read the bootloader setting in flash and continue accordingly. 

    This also applied for the linker script, they are 2 different applications and not related to each other when you compiling. 

  • Thanks Hung for the detailed explaination. It helps in my understanding and goes to show there is still lots to learn!

    I think I am a step more closer to my understanding and implementation of background DFU now.

    Still trying to get my head over something.

    It's not possible for me to implement a DFU master on the cloud server to send the nrf52 application the bytes chunks while observing the serial DFU
    protocol.

    My application has to act like the DFU Master as well as the slave at the same time because the server will only do
    whatever my application request from it. So I was thinking maybe after the app receiving a chunk of data from the server, the app then put on the DFU Master
    "role" and "package" the data chunk with a serial DFU opcode and then call another local function which will decode the OP code in a serial DFU opcode switch/case block and
    eventaully pass the data to nrf_dfu_req_handler_on_req() to be written to flash?

    Will background DFU still work if I did not implement the full serial DFU opcodes processing e.g. can I skip SERIAL_DFU_OP_CODE_CREATE_OBJECT, SERIAL_DFU_OP_CODE_GET_SERIAL_MTU etc.
    and just implement SERIAL_DFU_OP_CODE_WRITE_OBJECT and probably SERIAL_DFU_OP_CODE_CALCULATE_CRC, SERIAL_DFU_OP_CODE_EXECUTE_OBJECT?

    Or I don't even need to implement this serial protocol and just call nrf_dfu_req_handler_on_req() directly each time I receive a data chunk?

    Why do we need to send the init packet first and then execute the init packet. Also after every data chunk we need to execute object?

    I am also having some build issue at the moment after pulling in the dfu modules from the bootloader for the application.

    It's saying
    undefined reference to `nrf_cc310_bl_ecdsa_verify_secp256r1'
    undefined reference to `nrf_cc310_bl_hash_sha256_init'
    undefined reference to `nrf_cc310_bl_hash_sha256_update'

    but I've already included all the source modules for crypto and the libraries as well.

Related