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

DFU by app using MTP

Hi
my application will be based on nRF52820 and has only USB connection (no BLE).
I'm developping with nRF5_SDK_17.0.2_d674dde and a nRF52840 devkit.

The end user should be able to update the firmware without any tools.
Thus I implemented Media Transfer Protocol to copy the new image to the device.

First I used
nrfutil pkg generate ...
to create and sign the new application and I wrote a script to unzip the result and combine bootloader data and firmware image to single file which can be copied to the device using MTP.
On the device I receive the combined file and I first check the bootloader data
After I've written the firmware to bank 1 the check with   nrf_dfu_validation_prevalidate() returns  NRF_DFU_RES_CODE_SUCCESS

The I took a copy from
nRF5_SDK_17.0.2_d674dde/examples/dfu/secure_bootloader/pca10056_uart/
and removed DFU completely (I just want the activation part, but no transport at all)

Now I think I have to write valid bootloader settings and reboot.
After many days of reading examples, bootloader code and trial/error I think I miserably fail because of some conceptual misunderstanding or wrong expectation.

I try to prepare bootloader settings following the procedures I find in the examples.

settings_forbidden_parts_copy_from_backup()
detects unacceptable changes compared to the backup settings in MBR parameter page

OK - I did not do any DFU before, the backup can not contain reasonable data yet - this makes sense.

Lets "invent" reasonable bootloader settings reflecting the current app (very nasty hack) at startup and write them to the backup too.

nrfutil says about my fake...
Bootloader DFU Settings:
* File:                 fakeBootloaderSettings.hex
* Family:               NRF52840
* CRC:                  0xF36F5B3B
* Settings Version:     0x00000001 (1)
* App Version:          0x00000001 (1)
* Bootloader Version:   0x00000002 (2)
* Bank Layout:          0x00000000
* Current Bank:         0x00000000
* Application Size:     0x0007AFFC (503804 bytes)
* Application CRC:      0xEC72A580
* Bank0 Bank Code:      0x00000001

Looking at the flash memory I see my dummy settings, but the newly created settings are never written to flash.

I tried
nrf_dfu_validation_activation_prepare()
nrf_dfu_validation_post_data_execute()
and other variants

when I follow the execution in Segger Studio and it comes to reboot I have the strong feeling to get started in the app again.
I think I never hit the bootloader. So I checked the UICR 0x10001014 and 0x10001018 and I think they point to the correct location
I use
                nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_RESET);

I have 3 problems:
a) how to correctly prepare bootloader settings in the app?
b) how to shutdown/reboot the system correctly?
c) how can I know if Segger reboots into the bootloader or the app?

I'd appreciate a comment how solve problem a) because here I'm definitely stuck

best regards
Peter

  • Hi,

    Are you using an image that will fit in the flash of the device?

    The "Fake Bootloader settings" you posted shows an application size of 0x0007AFFC (503804 bytes), while the nRF52820 only have 256 kB of flash available.

    The initial bootloader settings should either be generated by the bootloader when you perform the first DFU, or be generated by nrfutil and merged with the initial flashed application.

    It sounds like what you are trying to achieve is very similar to how the Background DFU solution in previous SDKs work. Have you configured the bootloader to allow updates from the application (NRF_BL_DFU_ALLOW_UPDATE_FROM_APP)? I assume this is where you try to write the bootloader settings from?

    Best regards,
    Jørgen

  • Hi Jørgen

    yes, my image is just a proof of concept and small enough to fit (<100k)
    the 'fake bootloader settings' are calculated to eat up the first half of the available flash and to place bank 1 in the second half. Then I calculate CRC of whatever is currently in the first half (bank0).
    I'm aware of the 52820 having just a quarter of the flash and I want to make it work with the DevKit before I move to my own hardware.

    The initial bootloader settings should either be generated by the bootloader when you perform the first DFU, or be generated by nrfutil and merged with the initial flashed application.

    I do not have a "first DFU" and integrating MTP as transport into the bootloader would a nightmare and a waste of flash. Generating settings with nrfutil is both uncomfortable while developing and an (unwanted) additional step for production. IMHO it's quite simple to create these initial settings for the very first DFU on the fly.

    I like to separate my settings in app_config.h and for the bootloader it contains the following:

    #define NRF_BL_DFU_ALLOW_UPDATE_FROM_APP 1
    #define NRF_DFU_REQUIRE_SIGNED_APP_UPDATE 1
    #define NRF_DFU_APP_DOWNGRADE_PREVENTION 0
    #define NRF_DFU_EXTERNAL_APP_VERSIONING 0
    #define NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES 1
    #define NRF_DFU_SINGLE_BANK_APP_UPDATES 0
    
    #define NRF_BL_DFU_ENTER_METHOD_BUTTON 0
    #define NRF_BL_DFU_ENTER_METHOD_BUTTONLESS 0
    
    #define NRF_DFU_HW_VERSION 52
    
    
    // <i> Enable this to disable writing to areas of the settings that are protected
    // <i> by the bootlader. If this is not enabled in the app, certain settings write
    // <i> operations will cause HardFaults or will be ignored. Enabling this option
    // <i> also causes postvalidation to be disabled since this is meant to be done
    // <i> in the bootloader. NRF_BL_DFU_ALLOW_UPDATE_FROM_APP must be enabled in the bootloader.
    #define NRF_DFU_IN_APP 1
    
    
    // NRF_DFU_APP_DATA_AREA_SIZE - The size (in bytes) of the flash area reserved for application data. 
    // This area is found at the end of the application area, next to the start of
    // the bootloader. This area will not be erased by the bootloader during a
    // firmware upgrade. The size must be a multiple of the flash page size.
    #define NRF_DFU_APP_DATA_AREA_SIZE 12288
    
    
    // <i> External apps are apps that will not be activated. They can 
    // <i> e.g. be apps to be sent to a third party. External app updates 
    // <i> are verified upon reception, but will remain in bank 1, and 
    // <i> will never be booted. An external app will be overwritten if 
    // <i> a new DFU procedure is performed. Note: This functionality is 
    // <i> experimental and not yet used in any examples.
    #define NRF_DFU_SUPPORTS_EXTERNAL_APP 0
    
    
    
    #define NRF_LOG_ENABLED 0
    #define NRF_LOG_BACKEND_RTT 0
    #define NRF_LOG_DEFERRED 0
    #define NRF_LOG_DEFAULT_LEVEL 4
    
    #define NRF_LOG_BACKEND_RTT_ENABLED 1
    #define NRF_LOG_BACKEND_RTT_TEMP_BUFFER_SIZE 64
    #define SEGGER_RTT_CONFIG_BUFFER_SIZE_UP 4096
    #define SEGGER_RTT_CONFIG_MAX_NUM_UP_BUFFERS 2
    #define SEGGER_RTT_CONFIG_BUFFER_SIZE_DOWN 16
    #define SEGGER_RTT_CONFIG_MAX_NUM_DOWN_BUFFERS 2
    #define SEGGER_RTT_CONFIG_DEFAULT_MODE 0
    

    thank you very much for your support :-))

    Peter

  • Hi,

    Is it correct that you have set "#define NRF_DFU_IN_APP 1" in the bootloader? This should normally be set in the "Background DFU application" to prevent it from writing the parts that bootloader will handle. If you set this in the bootloader, it may not work properly.

    Would you be able to provide minimal examples/instructions that can be used to reproduce/debug this issue?

    Can you enable and provide logs (preferably debug level) from the bootloader?

    Best regards,
    Jørgen

  • Hi

    > Is it correct that you have set "#define NRF_DFU_IN_APP 1" in the bootloader?
    no this was wrong - thanks for the hint!

    and also wrong in my fake bootloader settings for the very first DFU - I should have added:

        // copied from boot_validation_crc(nrf_dfu_settings_t const * p_settings) in nrf_dfu_settings.c
        dummySettings.boot_validation_crc = crc32_compute((const uint8_t *)&(dummySettings.boot_validation_softdevice),
                              (3 * sizeof(boot_validation_t)), NULL);
    

    Providing debug output from the bootloader requires adding a lot of library code which leads to much bigger bootloader - it won't fit anymore to 0xF8000 - 0xFDFFF
    It isn't working yet but I feel like making progress again - I'll provide feedback - hopefully I'll tell you that it works.

    thanks a lot
    Peter

  • Hi

    after checking my DFU for days I find that everything would work - except booting. The application prepares bank1, the bootloader settings and reboots. But the CPU does definitely NOT execute the bootloader but restarts the application instead.

    On the other hand: all is in place and I step through the bootloader in Segger Studio. It perfectly recognizes the new image, copies bank1 to bank0, updates bootloader settings and MBR (settings backup), restarts the bootloader, detects there^s nothing left to do...
            case ACTIVATION_NONE:
                nrf_bootloader_app_start();
                break;
    and nrf_bootloader_app_start() ends up somewhere in Nirwana but not in the app.

    Yes, UICR settings are correct and checked (snippet from bootloader hex):
    :02 0000 04 1000  EA
    :04 1014 00 00800F00  49
    :04 1018 00 00E00F00  E5

    I have the bootloader and a valid app in place and do a power up:
    the app starts - no trace from the bootloader.

    Now I compiled the blinky example to check what pointer is set at VTOR address 0x00000000
    The hex file says in the first line
    :10 0000 00 00000420 B5020000 DD020000 DF020000 55
    does this really mean VTOR Reset vector points to 0x20040000, the very first non-existing address in RAM? I do definitely not understand what's going on here :-(
    Does this address intentionally provoke a hard fault which is then handled?
    Or is VTOR not at address 0x00000000 as I expect? What vector is used at power up?

    I need some pat on the shoulder (a hint, a pointer to docs, whatever):
    how the heck does BOOT work???

    best regards, Peter

    PS -  EDIT:
    gcc_startup_nrf52840.S reveals
    0x00000000  __StackTop
    0x00000004  Reset_Handler
    (so I was wrong to expect the RESET vector at address 0x00000000)

Related