nrf52832 OTA over ESB based on SDK17.1.0

Hi everyone:    I developed an application based on ESB wireless communication protocol ofr the nRF52832, and I would like to perform an OTA DFU with it.    Do you know any example of some over the air FW upgrade of nRF52832 chip via ESB protocol.

    SDK is 17.1.0.

Best regards,

Lurn.

Parents
  • I only found examples of ble and uart in the dfu/secure_bootloader folder, Which one should I use or how should I modify it to adapt my program.

  • Hello,

    It is correct that you will only find BLE and UART in our samples, but I know that several customers have ported this to SPI, so if you need it over ESB, then that should also be possible. The transport layers in the bootloader for the nRF5 SDK are on purpose quite separated from the rest of the libraries, to make it easier to change the transport layer, or to add your own transport layer.

    But you do need to implement it yourself. Also note that we do not have the "DFU Master" as an official part of our SDK. We have tools like nrfutil (open source) or nRF Connect for Desktop (not open source), and applications for mobile phones that are open source (but mobile phones doesn't have ESB). However, there is an unofficial implementation (not properly tested. You can use it, but on your own "risk"), which you can find here. I have not tested these myself, but you can give it a go. I suggest you test out the UART master, in combination with the uart bootloader, and then you can port both to ESB once you are up and running.

    Best regards,

    Edvin

  • Lurn_Z said:
    I just modify the UART TX/RX pin number, the rx default config is nrf_gpio_cfg_input(p_config->pselrxd, NRF_GPIO_PIN_NOPULL).

    What did you change them to, and what are they connected to?

    Lurn_Z said:
    Is our DFU mode standard DFU? I mean I can see its name like ...DFU... on any device?

    The log that you posted now indicates that your bootloader is running, and that you are in DFU mode! 

    No, you will not. This is a UART bootloader. Where exactly did you want to see it? 

  • Or, let me rephrase the last question:

    How do you want to update the device? From where do you want to send your new application to the nRF?

  • What did you change them to, and what are they connected to?

    No, I didn't change it, I mixed the other ticket answer.

    How do you want to update the device? From where do you want to send your new application to the nRF?

    I want to update the device by UART, and I will send it to nrf through the UART of other board.

    Do I need to do anything on other boards? For example on PC I need to use nrfjprog to update.

  • I program the mbr and bootloader, after enter dfu I use this command to update

    nrfutil sfu serial -pkg dfu_img.zip -p COM3 -fc 0 -b 115200

    It don't work, logs are here.

    when change 115200 to 9600, I only get one line  >>  app:Received an error: 0x0000004!

    So, did I forget something? All command is here.

    nrfutil settings generate --family NRF52 --application app.hex --application-version 0 --bootloader-version 0 --bl-settings-version 2 settings.hex
    nrfutil pkg generate --application app.hex --application-version 2 --sd-req 0x00 --hw-version 52 --key-file private.key dfu_image.zip
    
    nrfjprog --eraseall -f NRF52
    nrfjprog --program mbr_nrf52_2.4.1_mbr.hex --verify -f NRF52
    nrfjprog --program bootloader.hex --verify -f NRF52
    nrfjprog --reset -f NRF52
    
    
    nrfutil dfu serial -pkg dfu_image.zip -p COM3 -fc 0 -b 115200

    Another questions:

    1.Now I can enter DFU because I didn't program my application, so when I also program application.hex and settings.hex, how should I enter the DFU mode?

    2.My application used UARTE, will it affect my use of uart in bootloader?

    BR,

    Lurn

  • Lurn_Z said:
    No, I didn't change it, I mixed the other ticket answer.

    In that case, I suggest we only focus on one ticket at the time. I suggest this one, and we can continue with the other when this one is solved.

    Lurn_Z said:
    when change 115200 to 9600, I only get one line  >>  app:Received an error: 0x0000004!

    That is because you are using the wrong baud rate. Change it back to 115200.

    I still think you would have saved yourself a lot of trouble by getting up and running on a DK before attempting to do this on a custom board, and you may still save time by doing so.

    So it fails to send the serial response. The only possible reason I can think of is that you have enabled hardware flow control (HWFC) in your bootloader project. Try to disable it by setting:

    #define NRF_DFU_SERIAL_UART_USES_HWFC 0

    in your sdk_config.h (It is set to 1 by default. Search for this define in your bootloader's sdk_config.h).

    Lurn_Z said:
    I want to update the device by UART, and I will send it to nrf through the UART of other board.

    In that case, you will not see it in your nRF Connect for Android/iOS, as you would if you were using the BLE bootloader, for obvious reasons.

    Lurn_Z said:
    Do I need to do anything on other boards? For example on PC I need to use nrfjprog to update.

    From the other board, you need to transfer the image. For how to do this, I am afraid we don't have a very good documentation. You can look into the DFU library. There are some useful links from here. Alternatively, you need to look at the implementation of nrfutil (on github)

    Lastly, we have an unofficial implementation of the DFU master, which you can find in this tutorial:

     Getting started with Nordic's Secure DFU bootloader, a step by step guide 

    (Search for DFU master code).

    Best regards,

    Edvin

Reply
  • Lurn_Z said:
    No, I didn't change it, I mixed the other ticket answer.

    In that case, I suggest we only focus on one ticket at the time. I suggest this one, and we can continue with the other when this one is solved.

    Lurn_Z said:
    when change 115200 to 9600, I only get one line  >>  app:Received an error: 0x0000004!

    That is because you are using the wrong baud rate. Change it back to 115200.

    I still think you would have saved yourself a lot of trouble by getting up and running on a DK before attempting to do this on a custom board, and you may still save time by doing so.

    So it fails to send the serial response. The only possible reason I can think of is that you have enabled hardware flow control (HWFC) in your bootloader project. Try to disable it by setting:

    #define NRF_DFU_SERIAL_UART_USES_HWFC 0

    in your sdk_config.h (It is set to 1 by default. Search for this define in your bootloader's sdk_config.h).

    Lurn_Z said:
    I want to update the device by UART, and I will send it to nrf through the UART of other board.

    In that case, you will not see it in your nRF Connect for Android/iOS, as you would if you were using the BLE bootloader, for obvious reasons.

    Lurn_Z said:
    Do I need to do anything on other boards? For example on PC I need to use nrfjprog to update.

    From the other board, you need to transfer the image. For how to do this, I am afraid we don't have a very good documentation. You can look into the DFU library. There are some useful links from here. Alternatively, you need to look at the implementation of nrfutil (on github)

    Lastly, we have an unofficial implementation of the DFU master, which you can find in this tutorial:

     Getting started with Nordic's Secure DFU bootloader, a step by step guide 

    (Search for DFU master code).

    Best regards,

    Edvin

Children
  • So it fails to send the serial response. The only possible reason I can think of is that you have enabled hardware flow control (HWFC) in your bootloader project. Try to disable it by setting:

    #define NRF_DFU_SERIAL_UART_USES_HWFC 0

    Yes, this is the wrong reason. Now I can update my device successfully.

    I have a question now.

    How should I enter the DFU mode when my device in application?

    I don't think I can use the while loop that you suggest before, because I didn't use softdevice now(I used the wrong example to test before).

    To see whether it is written.

    So to fix this, you can use something like this:

    {
        uint32_t old_gpregret = sd_power_gpregret_get();
        uint32_t new_gpregret = old_gpregret & BOOTLOADER_DFU_START; //Just to retain other things written to gpregret. Not necessarily needed.
        uint32_t temp = 0;
        
        sd_power_gpregret_set(new_gpregret);
        while ((temp & BOOTLOADER_DFU_START) != BOOTLOADER_DFU_START)
        {
            // Wait until the gpregret is written, and refresh the value of temp.
            sd_power_gpregret_get(0, &temp);
        }
        // When this is reached, the gpregret is successfully written.
        nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);
        NVIC_SystemReset();
    }

    maybe I still need to modify gpregret, but can not use the function sd_power_gpregret_set() ?

    From the other board, you need to transfer the image. For how to do this, I am afraid we don't have a very good documentation. You can look into the DFU library. There are some useful links from here. Alternatively, you need to look at the implementation of nrfutil (on github)

    I will view and study these materials

    BR,

    Lurn

  • Good good! We are getting closer. Now you only need a way to enter DFU mode. You are correct that we can still use the GPREGRET, and we can do so without using the softdevice. By default, the api to interact with the GPREGRET is nrf_power_gpregret_set() and nrf_power_gpregret_get(), like it is used in the bootloader example. However, if the softdevice is enabled, the gpregret is restricted, so you need to access the gpregret via the softdevice API (sd_power_gpregret_set/get()). When the softdevice is not enabled, you are free to use the "normal" nrf_power_gpregret_set()/nrf_power_gpregret_get(). These are declared in SDK\modules\nrfx\hal\nrf_power.h.

    So the snippet in your last reply will still work. Just replace all "sd_..." with "nrf_...", and make all the variables uint8_t instead of unt32_t (because the GPREGRET is just an 8 bit value, and the non-softdevice actually expects and returns uint8_t instead of uint32_t) and you are good. 

    Do you know where you want to call this function? We have not discussed this, but perhaps you already have a plan. In a BLE bootloader, it is typical to use a special BLE service to put the device in DFU mode (the buttonless_dfu service). Other methods are:

    1: Always enter DFU mode on power on, and make it time out after X time, and then enter the application.

    2: Hold a button/gpio on reset to enter DFU mode.

    3: Use the gpregret from your application. You are free to decide when you write this register. If you have a UART device connected, you can e.g. use a special UART message to trigger this.

    Best regards,

    Edvin

  • OK, I will try enter DFU mode on power on for first test, and if it worked I can use my own way, like you said UART etc...

    BR

    Lurn

  • So the snippet in your last reply will still work. Just replace all "sd_..." with "nrf_...", and make all the variables uint8_t instead of unt32_t (because the GPREGRET is just an 8 bit value, and the non-softdevice actually expects and returns uint8_t instead of uint32_t) and you are good. 

    1.I can't enter the DFU mode in use the while loop, so I print the old_gpregret and new_gpregret, and the value is 0. so I change nrf_power_gpregret_set(new_gpregret); to nrf_power_gpregret_set(0XB1); 

    It also can't enter DFU, but the code break from while loop, when I use nrfjprog --reset to reset system, the device enter the DFU mode, so I think the reset code doesn't work.

    2.When the device in DFU mode, it can't enter the application after time out, the device is always in DFU mode.

    the NRF_BL_DFU_CONTINUATION_TIMEOUT_MS is 10000

    and the NRF_BL_DFU_INACTIVITY_TIMEOUT_MS is 120000.

    the RTT log is here.

    # SEGGER J-Link RTT Viewer V7.00a Terminal Log File
    # Compiled: 15:35:52 on Apr 16 2021
    # Logging started @ 22 Feb 2023 18:14:19
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <debug> app: timer_fire (<info> app: Inside main
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <<info> app: Inside main
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> nrf_dfu_settings: Using settings page.
    00> 
    00> <debug> nrf_dfu_settings: Copying forbidden parts from backup page.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0x7E000.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <debug> app: Enter nrf_bootloader_fw_activate
    00> 
    00> <info> app: No firmware to activate.
    00> 
    00> <debug> app: App is valid
    00> 
    00> <debug> app: DFU mode requested via GPREGRET.
    00> 
    00> <info> nrf_bootloader_wdt: WDT is not enabled
    00> 
    00> <debug> app: in weak nrf_dfu_init_user
    00> 
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <debug> app: timer_activate (0x20000020)
    00> 
    00> <info> app: Entering DFU mode.
    00> 
    00> <debug> app: Initializing transports (found: 1)
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init()
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init() completed
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> app: Enter main loop
    00> 
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <info> app: Inside main
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_f<debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> nrf_dfu_settings: Using settings page.
    00> 
    00> <debug> nrf_dfu_settings: Copying forbidden parts from backup page.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0x7E000.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <debug> app: Enter nrf_bootloader_fw_activate
    00> 
    00> <info> app: No firmware to activate.
    00> 
    00> <debug> app: App is valid
    00> 
    00> <debug> app: DFU mode requested via GPREGRET.
    00> 
    00> <info> nrf_bootloader_wdt: WDT is not enabled
    00> 
    00> <debug> app: in weak nrf_dfu_init_user
    00> 
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <debug> app: timer_activate (0x20000020)
    00> 
    00> <info> app: Entering DFU mode.
    00> 
    00> <debug> app: Initializing transports (found: 1)
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init()
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init() completed
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> app: Enter main loop
    00> 
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <debug> app: timer_fire (0x200000<info> app: Inside main
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> nrf_dfu_settings: Using settings page.
    00> 
    00> <debug> nrf_dfu_settings: Copying forbidden parts from backup page.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0x7E000.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <debug> app: Enter nrf_bootloader_fw_activate
    00> 
    00> <info> app: No firmware to activate.
    00> 
    00> <debug> app: App is valid
    00> 
    00> <debug> app: DFU mode requested via GPREGRET.
    00> 
    00> <info> nrf_bootloader_wdt: WDT is not enabled
    00> 
    00> <debug> app: in weak nrf_dfu_init_user
    00> 
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <debug> app: timer_activate (0x20000020)
    00> 
    00> <info> app: Entering DFU mode.
    00> 
    00> <debug> app: Initializing transports (found: 1)
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init()
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init() completed
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> app: Enter main loop
    00> 
    00> <debug> app: timer_stop (0x2<info> app: Inside main
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> nrf_dfu_settings<info> app: Inside main
    00> 
    00> <debug> app: In nrf_bootloader_init
    00> 
    00> <debug> nrf_dfu_settings: Calling nrf_dfu_settings_init()...
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> nrf_dfu_settings: Using settings page.
    00> 
    00> <debug> nrf_dfu_settings: Copying forbidden parts from backup page.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <info> nrf_dfu_settings: Backing up settings page to address 0x7E000.
    00> 
    00> <debug> nrf_dfu_settings: Destination settings are identical to source, write not needed. Skipping.
    00> 
    00> <debug> app: Enter nrf_bootloader_fw_activate
    00> 
    00> <info> app: No firmware to activate.
    00> 
    00> <debug> app: App is valid
    00> 
    00> <debug> app: DFU mode requested via GPREGRET.
    00> 
    00> <info> nrf_bootloader_wdt: WDT is not enabled
    00> 
    00> <debug> app: in weak nrf_dfu_init_user
    00> 
    00> <debug> app: timer_stop (0x20000020)
    00> 
    00> <debug> app: timer_activate (0x20000020)
    00> 
    00> <info> app: Entering DFU mode.
    00> 
    00> <debug> app: Initializing transports (found: 1)
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init()
    00> 
    00> <debug> nrf_dfu_serial_uart: serial_dfu_transport_init() completed
    00> 
    00> <debug> nrf_dfu_flash: Initializing nrf_fstorage_nvmc backend.
    00> 
    00> <debug> app: Enter main loop
    00> 
    
    # Logging stopped @ 22 Feb 2023 18:21:49
    

    but when use nrfjprog --reset, the device enter the application.

    So, for the two problem what's wrong with it?

    BR,

    Lurn

  • Are you resetting manually in this log (using nrfjprog --reset) or is it the timer that times out? 

    It looks like it is entering DFU mode because "DFU mode requested via GPREGRET". So if you want to exit this, you need to clear the register from your bootloader. 

    I am not sure what you mean by the while loop anymore. Perhaps you can rephrase the question.

    BR,
    Edvin

Related