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

custom DFU in App

Hello,

I am developing DFU over a custom IEEE802.15.4 Protocol in our own embedded OS. I managed to write the new Firmware starting at bank1_start address. Now I need to tell the Bootloader (the BTL from SDK16) to do its magic (verifying and copying the Firmware to bank0). For now I fill the init_command in the nrf_dfu_settings_t at BOOTLOADER_SETTINGS_ADDRESS with the values I get from nrfutil and write it back to flash, but that doesn't impress the bootloader. What else do I need to do so the bootloader knows that there is a new Firmware it should take care of?

This is what I am doing right now:

> nrfutil settings generate --application ./Firmware.hex --application-version 0x0100 --family NRF52840 --bootloader-version 1 --bl-settings-version 2 Firmware_btl_settings.hex

Note: Generating a DFU settings page with backup page included.
This is only required for bootloaders from nRF5 SDK 15.1 and newer.
If you want to skip backup page generation, use --no-backup option.

Generated Bootloader DFU settings .hex file and stored it in: Firmware_btl_settings.hex

Bootloader DFU Settings:
* File:                     MPS_Master_btl_settings.hex
* Family:                   NRF52840
* Start Address:            0x000FF000
* CRC:                      0x8800843F
* Settings Version:         0x00000002 (2)
* App Version:              0x00000100 (256)
* Bootloader Version:       0x00000001 (1)
* Bank Layout:              0x00000000
* Current Bank:             0x00000000
* Application Size:         0x00024C3C (150588 bytes)
* Application CRC:          0xF899D96C
* Bank0 Bank Code:          0x00000001
* Softdevice Size:          0x00000000 (0 bytes)
* Boot Validation CRC:      0x5FF8E2DA
* SD Boot Validation Type:  0x00000000 (0)
* App Boot Validation Type: 0x00000001 (1)

----------------------------------------------------------------------

nrf_dfu_settings_t * p_dfu_settings = (nrf_dfu_settings_t *)BOOTLOADER_SETTINGS_ADDRESS;
nrf_dfu_settings_t dfu_settings;
dfu_init_command_t init_cmd;

memcpy(&dfu_settings, p_dfu_settings, sizeof(nrf_dfu_settings_t));

init_cmd.has_fw_version = true;
init_cmd.fw_version     = 0x0100;
init_cmd.has_hw_version = false;
init_cmd.hw_version     = 0xFFF00000;
init_cmd.sd_req_count   = 0;
// init_cmd.sd_req[16]  = ;
init_cmd.has_type       = true;
init_cmd.type           = DFU_FW_TYPE_APPLICATION;
init_cmd.has_sd_size    = false;
// init_cmd.sd_size     = ;
init_cmd.has_bl_size    = false;
// init_cmd.bl_size     = ;
init_cmd.has_app_size   = true;
init_cmd.app_size       = 0x00024C3C;
init_cmd.has_hash       = false;
// init_cmd.hash        = ;
init_cmd.has_is_debug   = false;
init_cmd.is_debug       = false;
init_cmd.boot_validation_count             = 1;
init_cmd.boot_validation[0].type           = DFU_VALIDATION_TYPE_VALIDATE_GENERATED_CRC;
init_cmd.boot_validation[0].bytes.size     = 4;
init_cmd.boot_validation[0].bytes.bytes[0] = 0xF8;
init_cmd.boot_validation[0].bytes.bytes[1] = 0x99;
init_cmd.boot_validation[0].bytes.bytes[2] = 0xD9;
init_cmd.boot_validation[0].bytes.bytes[3] = 0x6C;
memcpy(dfu_settings.init_command, &init_cmd, sizeof(init_cmd));

nrf_dfu_settings_write(&dfu_settings);

enter_bootloader(); // set NRF_POWER->GPREGRET and reboot

----------------------------------------------------------------------

void nrf_dfu_settings_write(nrf_dfu_settings_t * pData) {
    /* g_btl_info need to be the start of a page */
    assert(((uint32_t)p_dfu_settings % NRF_FICR->CODEPAGESIZE) == 0);
    assert(pData);

    if (0 == memcmp(pData, &p_dfu_settings, sizeof(nrf_dfu_settings_t))) {
        return;
    }
    nrf_nvmc_page_erase((uint32_t)p_dfu_settings);
    nrf_nvmc_bytes_write((uint32_t)p_dfu_settings, pData, sizeof(nrf_dfu_settings_t));
}

  • It's in sdk_config.h. Actualy NRF_CRYPTO_BACKEND_CC310_BL wasn't enabled. So I disabled the CC310 backend and enabled the CC310_BL backend, added some src files and include pathes to the Makefile and was finaly able to update the firmware from the app.

    I pushed the code to https://github.com/MeisterBob/nrf52_blinky_dfu_in_app for anyone who needs a minimal example for DFU_IN_APP, it's based on SDK 17.0.2 and uses UART transport.

    I was able to find the answer to my initial question. My major missunderstanding was, that the init command needs to be stored protobuf encoded, I was trying to safe it decoded. The steps to success are:

    nrf_dfu_settings_t *p_dfu_settings = /* Pointer to bootloader settings page (0xFF000 on nRF52840) */
    nrf_dfu_settings_t mku_dfu_settings;
    
    // copy old dfu_settings
    memcpy(&dfu_settings, p_dfu_settings, sizeof(nrf_dfu_settings_t));
    
    // update init command (protobuf encoded !)
    memcpy(dfu_settings.init_command, /* init command */, /* init command size */);
    
    // update .progress
    dfu_settings.progress.command_size               = /* size of the init command */;
    dfu_settings.progress.command_offset             = dfu_settings.progress.command_size;
    dfu_settings.progress.data_object_size           = 0;
    dfu_settings.progress.firmware_image_crc         = /* application crc returned by nrfutil settings generate */;
    dfu_settings.progress.firmware_image_crc_last    = dfu_settings.progress.firmware_image_crc;
    dfu_settings.progress.firmware_image_offset      = /* application size */
    dfu_settings.progress.firmware_image_offset_last = dfu_settings.progress.firmware_image_offset;
    dfu_settings.progress.command_crc                = crc32_compute((uint8_t *)(dfu_settings.init_command), dfu_settings.progress.command_size, NULL);
    
    // set bank current to 1
    dfu_settings.bank_current = 1;  // NRF_DFU_CURRENT_BANK_1
    
    // update settings crc
    dfu_settings.crc = crc32_compute((uint8_t *)(&dfu_settings) + 4, offsetof(nrf_dfu_settings_t, init_command) - 4, NULL);
    
    // write dfu_settings back to p_dfu_settings
    // write new app to MBR_SIZE + dfu_settings->bank_0.image_size (if you use a softdevice MBR_SIZE is a bad choice here)
    // reboot the system

Related