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

How to use external app firmware update

Hi,

I would like to use external app firmware to update over BLE a secondary microncontroler behind a NRF52832. I read that it's an experimental feature but it's very intersting because this avoids to implement an other mecanism in mobile application to update the other MCU.

I already developped the DFU over BLE for application, bootloader and soft device. I now try to make work the external app update.

SDK 17.0.2, SoftDevice s112

The process I imagine :

  • Run the NRF52 in DFU mode
  • Upload the external firmware (in Bank 1 to preserve app in Bank 0)
  • Once done, run boot the secondary MCU by driving GPIO (nReset/Boot)
  • Send the firmware over UART
  • Restart in normal mode

I already created a zip package using nrfutil : nrfutil pkg generate --hw-version 52 --application-version-string 1.0.0 --application XYZ_Project.hex --external-app --key-file private.key XYZ_Project.zip

where XYZ_Project.hex is a STM32 hex file.

I succeed in downloading the zip file in the NRF52 and I check the internal memory of the MCU. Everythong looks good in Bank 1 ;)

Now, I want to push the Bank 1 data to the other MCU. Searhing the code, I saw I have to implement this method :

nrf_dfu_result_t nrf_dfu_validation_post_external_app_execute(dfu_init_command_t const * p_init, bool is_trusted)

However, it's never called; I ran the code in debbuger mode and saw this code section in postvalidate function nrf_dfu_validation.c but don't really understand how it works :

#if NRF_DFU_SUPPORTS_EXTERNAL_APP
        else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
        {
            if (!is_trusted)
            {
                // This function must be implemented externally
                ret_val = nrf_dfu_validation_post_external_app_execute(p_init, is_trusted);
            }
            else
            {
                s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_EXT_APP;
            }
        }
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP

The method nrf_dfu_validation_post_external_app_execute is never executed (in debugger mode, I put a breakpoint on the function).

Help is welcome Smiley

  • Hi Einar,

    Thanks a lot, this is clearer now.

    When or where I have to execute nrf_dfu_validation_valid_external_app() and update the external MCU ? I don't really understand how to catch the end of the upload and launch the update.

    I believed it's in nrf_dfu_validation_post_external_app_execute() I had to do this.

    Thanks a lot.

  • Hi,

    No, you don't need nrf_dfu_validation_post_external_app_execute(). That was my bad. To be honest the last time I looked at this was a few years ago, as it is not a commonly used feature. 

    Essentially once the app is in bank 1 it is up to you. If you want to do this in the nRF bootloader, then you could modify <SDK_17.02>/components/libraries/bootloader/dfu/nrf_dfu_validation.c around line 1010-1020 so that you call your implementation for updating the other MCU from there. Alternatively you could let the bootloader reset and start your application, and do the rest from your application. The app would know that a image is ready by seeing that the bank 1 code is NRF_DFU_BANK_VALID_EXT_APP. (Once the external MCU is successfully updated  you probably want to invalidate that in this case so that you don not attempt to update again).

  • Hi Einar!

    Thanks a lot for your previous help, this is now working like a charm ;) the external MCU can be updated from my app.

    I now try to manage external app versionning and I'm exploring the NRF_DFU_EXTERNAL_APP_VERSIONING option in my sdk_config.h on the BL project.

    I searched the libraries and I saw that there are some checks if this option is activated (extract from nrf_dfu_ver_validation.c / fw_version_ok :

    #if NRF_DFU_EXTERNAL_APP_VERSIONING
        else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
        {
            return (p_init->fw_version >= s_dfu_settings.app_version);
        }
    #else
        else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
        {
            return true;
        }
    #endif // NRF_DFU_EXTERNAL_APP_VERSIONING
    #endif // NRF_DFU_SUPPORTS_EXTERNAL_APP

    What I understand is that p_init is linked to the new package sent by BLE and dfu_settings contains the information of the previous one.

    However, I don't understand how the bootloader can differantiate app_version for application and app_version for external application... 

    When I dumped the flash content and ran nrfutil settings display, I only saw app_version but nothing about external_app_version.

    Maybe it is not already managed as external app is not often used ?

  • Hi Thib,

    As you know you use the external-app flag when you generate the DFU package, and this will become part of the init packet. You cannot have both an external app and normal/local app in the same DFU operation, so here the specified app version will apply to the external app. There is no need to differentiate between external and normal app, as the updates never occur at the same time. See example from generating external app update, and display of the generated package (which is essentially what is in the init packet, which is pointed to by p_init in your code snippet from the bootloader.

    C:\Users\eith\SDK\nRF5_SDK_17.0.2_d674dde\examples\dfu>nrfutil pkg generate --application secure_dfu_test_images\ble\nrf52832\hrs_application_s132.hex --application-version 123 --hw-version 5 --sd-req 0 --external-app --key-file c:\vault\priv.pem update_external.zip
    Zip created at update_external.zip
    
    C:\Users\eith\SDK\nRF5_SDK_17.0.2_d674dde\examples\dfu>nrfutil pkg display update_external.zip 
    
    DFU Package: <update_external.zip>:
    |
    |- Image count: 1
    |
    |- Image #0:
       |- Type: application
       |- Image file: hrs_application_s132.bin
       |- Init packet file: hrs_application_s132.dat
          |
          |- op_code: INIT
          |- signature_type: ECDSA_P256_SHA256
          |- signature (little-endian): b'025356933b17ff646eb2d7d536f82ee6ace8f62284521e6cccb53a8730e878599cb13d885e88438b6816c1eb74f6b4282111c9e0337f3f7eec3fb0da591dd0e1'
          |
          |- fw_version: 0x0000007B (123)
          |- hw_version 0x00000005 (5)
          |- sd_req: 0x00
          |- type: EXTERNAL_APPLICATION
          |- sd_size: 0
          |- bl_size: 0
          |- app_size: 85500
          |
          |- hash_type: SHA256
          |- hash (little-endian): b'e61a6b2fe616bfb0e3da756774a781e49db4dc8cab5732adf216723613bbe677'
          |
          |- boot_validation_type: ['VALIDATE_GENERATED_CRC']
          |- boot_validation_signature (little-endian): [b'']
          |
          |- is_debug: False
    

    Einar

  • Hi,

    I understand well the content of the p_init pointer.

    What I don't understand is the content of the BL settings. The externall app version is not mentionned in the BL settings so I don't know how the version comparison can work :

    p_init->fw_version >= s_dfu_settings.app_version

    Maybe the BL setting store alternatively the app version or the external app version (make no sense?)

    Moreover, once the external app is updated in flash and the application boot, the p_init pointer is lost and I can only trust the BL settings loaded in nrf_dfu_settings.

    sorry if I'm not clear Smiley

Related