DFU using USB file system (not serial emulation)?

My project has a nrf5340+external flash, and an external USB-C connector. The device exposes a USB file system (FAT) which is hosted on the external flash partition, and appears as an external disk when connected to a host. This all works well and is used to update config, image files etc for the device to use.

I would like to be able to do application / network firmware updates by simply copying the new image (hex or bin) to this file system and rebooting. Has anyone done this? I'm guessing it involves using MCUBoot bootloader and copying the image into the secondary image slot somehow? I also want to put the secondard image slot on my external flash as won't have space on the internal flash - even better would be if MCUBoot could take the image directly from the file in the FS....

by the way, to be clear, I do NOT want to use the 'DFU over USB serial emulation' method, as this requires the user to install the specific tool to the host machine, which may not be available for their host or may not be allowed by IT policy (or by their level of expertise...). 

thanks for any pointers!

Parents
  • Hi Brian, 
    You should set 

    CONFIG_MCUBOOT_SERIAL=n in the mcuboot.conf overlay to apply the config to the MCUBoot child image, not the application. Usually you put that file into child_image folder.  
    Anyway , by default MCUBOOT_SERIAL is not enable so you don't really have to worry about it. (double check with .config file in the MCUBoot build folder)
  • Ok... I removed all the wifi stuff from my app, added a mcuboot.cong in the child_image folder with:

    CONFIG_MCUBOOT_SERIAL=n
    CONFIG_BOOT_USE_MIN_PARTITION_SIZE=y

    This didn't fix it, although it has changed things.

    Latest build error is:

    [373/415] Performing build step for 'mcuboot_subimage'

    ...

    `text' will not fit in region `FLASH'
    c:/ncs/toolchains/cf2149caf2/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd.exe: region `FLASH' overflowed by 37320 bytes
    collect2.exe: error: ld returned 1 exit status
    ninja: build stopped: subcommand failed.

    ...
    [396/415] Linking C executable zephyr\zephyr_pre0.elf
    c:/ncs/toolchains/cf2149caf2/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/12.2.0/../../../../arm-zephyr-eabi/bin/ld.bfd.exe: warning: orphan section `.fonts' from `app/libapp.a(u8g2_fonts.c.obj)' being placed in section `.fonts'
    [397/415] Generating ../../zephyr/net_core_app_test_update.hex
    image.py: sign the payload
    [402/415] Linking C executable zephyr\zephyr.elf
    FAILED: modules/mcuboot/mcuboot_subimage-prefix/src/mcuboot_subimage-stamp/mcuboot_subimage-build mcuboot/zephyr/zephyr.hex mcuboot/zephyr/zephyr.elf C:/work/dev/if-device-nrf53/cc1-med/build/modules/mcuboot/mcuboot_subimage-prefix/src/mcuboot_subimage-stamp/mcuboot_subimage-build C:/work/dev/if-device-nrf53/cc1-med/build/mcuboot/zephyr/zephyr.hex C:/work/dev/if-device-nrf53/cc1-med/build/mcuboot/zephyr/zephyr.elf
    ...
    Memory region Used Size Region Size %age Used
    FLASH: 446762 B 1031680 B 43.30%
    RAM: 152572 B 440 KB 33.86%
    IDT_LIST: 0 GB 32 KB 0.00%
    ninja: build stopped: subcommand failed.

    I note that the application built correctly, and is around 446Kb (with the wifi enabled I'm thinking this was showing 901kB...). But this didnt stop the mcuboot subimage failing, this time with its 'text' segment overflowing the FLASH...

    Maybe I should try to reconfigure to stop using the partition manager if its creating a partition for mcuboot which is too small?

    or just build the mcuboot child image to check if that is the issue?

  • From pm.config in the build directory:

    PM_MCUBOOT_OFFSET=0x0

    PM_MCUBOOT_PRIMARY_OFFSET=0xfe00

    This is exactly what I expect given my pm_static.yml which starts like:

    mcuboot:
        address: 0x0
        end_address: 0xfe00
        #placement:
        #  before:
        #  - mcuboot_primary
        region: flash_primary
        size: 0xfe00
    
    mcuboot_pad:
        address: 0xfe00
        end_address: 0x10000
        #placement:
        #  align:
        #    start: 0xfe00
        #  before:
        #  - mcuboot_primary
        region: flash_primary
        size: 0x200
    
    app:
        address: 0x10000
        end_address: 0x100000
        region: flash_primary
        size: 0xf0000
    
    mcuboot_primary_app:
        address: 0x10000
        end_address: 0x100000
        region: flash_primary
        size: 0xf0000
        #  span: *id002
        span: [app]
    
    mcuboot_primary:
        address: 0xfe00
        end_address: 0x100000
        region: flash_primary
        size: 0xf0200
        #  span: *id001
        span: [mcuboot_pad, mcuboot_primary_app]
     

    I don't see how to attach files to a ticket? Simple drag-n-drop tells me the file type yml is not allowed...

    partition_manager_report target gives me:

    external_flash (0x800000 - 8192kB):
    +-------------------------------------------------+
    | 0x0: fatfs_storage (0x600000 - 6144kB) |
    | 0x600000: nvs_storage (0x10000 - 64kB) |
    | 0x610000: mcuboot_secondary_1 (0x40000 - 256kB) |
    | 0x650000: mcuboot_secondary (0xfc000 - 1008kB) |
    | 0x74c000: external_flash (0xb4000 - 720kB) |
    +-------------------------------------------------+
    
    flash_primary (0x100000 - 1024kB):
    +--------------------------------------------------+
    | 0x0: mcuboot (0xfe00 - 63kB) |
    +---0xfe00: mcuboot_primary (0xf0200 - 960kB)------+
    | 0xfe00: mcuboot_pad (0x200 - 512B) |
    +---0x10000: mcuboot_primary_app (0xf0000 - 960kB)-+
    | 0x10000: app (0xf0000 - 960kB) |
    +--------------------------------------------------+
    
    otp (0x2fc - 764B):
    +------------------------------+
    | 0xff8100: otp (0x2fc - 764B) |
    +------------------------------+
    
    sram_primary (0x80000 - 512kB):
    +-----------------------------------------------+
    | 0x20000000: pcd_sram (0x2000 - 8kB) |
    | 0x20002000: sram_primary (0x6e000 - 440kB) |
    | 0x20070000: rpmsg_nrf53_sram (0x10000 - 64kB) |
    +-----------------------------------------------+
    
    CPUNET flash_primary (0x40000 - 256kB):
    +--------------------------------------------+
    +---0x1000000: b0n_container (0x8800 - 34kB)-+
    | 0x1000000: b0n (0x8580 - 33kB) |
    | 0x1008580: provision (0x280 - 640B) |
    +---0x1008800: app (0x37800 - 222kB)---------+
    | 0x1008800: hci_ipc (0x37800 - 222kB) |
    +--------------------------------------------+
    
    CPUNET sram_primary (0x10000 - 64kB):
    +-------------------------------------------+
    | 0x21000000: sram_primary (0x10000 - 64kB) |
    +-------------------------------------------+

    which is prettier anyway...

  • So, now that mcuboot is actually bootingmy code (FPROTECT disabled) I have added 

    CONFIG_STREAM_FLASH=y
    CONFIG_STREAM_FLASH_ERASE=y
    CONFIG_DFU_TARGET_STREAM=y
    CONFIG_IMG_MANAGER=y
    CONFIG_DFU_TARGET_MCUBOOT=y
    and using the dfu_target library to copy the contents of app_update.bin to the mcuboot_secondary partition.
    However, it failed with this log
    "Missing stream_buf, call '..set_buf' before '..init"
    as found in dfu_target_mcuboot.c
    I use the dfu_target api as described in the doc
    but it doesn't mention having to set a buffer for mcuboot before the call to dfu_target_init()
    And nowhere in dfu_target.c does it do this?!
    What is the point of having a 'standard' api dfu_target to mask the different 'targets', if app has to explicitly call a target specific function to get it to work? And not described in the doc either?
     
  • Hi again, 

    You can attach file by clicking Insert -> Image/Video/file 

    Or you can add code by Insert -> Code 

    Regarding the mcuboot partition, can you tell why you choose 0xfe00 ( mcuboot end address) and 0x10000 (mcuboot pad end address) ? 
    The problem of this address is that it doesn't allign with FPROTECT_BLOCK_SIZE ( =NRF_SPU_FLASH_REGION_SIZE = 0x4000). 


    Could you try again with 0xc000 and 0xc200 respectively or try 0x10000 and 0x10200 respectively. 

  • I chose 0xfe00 because the original problem was that mcuboot was too big for the flash size selected by PM (0xc000 = 48kB, mcuboot image is around 53kB...), so I aligned the app start partition nicely on 0x10000 -> which when you take off the 0x200 pad gives 0xfe00.

    Sadly the build process and the PM didn't flag up this alignment requirement for FPROTECT...

    I will change it to 0xe000 size for mcuboot and see if that lets FPROTECT be happy... with the primary partition therefore at 0xe200.

  • Still complains:

    *** Booting nRF Connect SDK 3758bcbfa5cd ***
    I: Starting bootloader
    W: Cannot upgrade: not a compatible amount of sectors
    I: Bootloader chainload address offset: 0xe000
    I: Jumping to the first image slot
    E: Protect mcuboot flash failed, cancel startup.

    partitions.yml : insert->file "type yml still not allowed."

    app:
      address: 0xe200
      end_address: 0x100000
      region: flash_primary
      size: 0xf1e00
    external_flash:
      address: 0x750000
      end_address: 0x800000
      region: external_flash
      size: 0xb0000
    fatfs_storage:
      address: 0x0
      affiliation:
      - disk
      end_address: 0x600000
      extra_params:
        disk_cache_size: 0x1000
        disk_name: NAND
        disk_read_only: 0x0
        disk_sector_size: 0x200
      region: external_flash
      size: 0x600000
    mcuboot:
      address: 0x0
      end_address: 0xe000
      region: flash_primary
      size: 0xe000
    mcuboot_pad:
      address: 0xe000
      end_address: 0xe200
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0xe000
      end_address: 0x100000
      region: flash_primary
      size: 0xf2000
      span:
      - mcuboot_pad
      - mcuboot_primary_app
    mcuboot_primary_app:
      address: 0xe200
      end_address: 0x100000
      region: flash_primary
      size: 0xf1e00
      span:
      - app
    mcuboot_secondary:
      address: 0x650000
      affiliation:
      - mcuboot
      end_address: 0x750000
      region: external_flash
      size: 0x100000
    mcuboot_secondary_1:
      address: 0x610000
      affiliation:
      - mcuboot
      end_address: 0x650000
      region: external_flash
      size: 0x40000
    nvs_storage:
      address: 0x600000
      affiliation:
      - nvs
      end_address: 0x610000
      region: external_flash
      size: 0x10000
    otp:
      address: 0xff8100
      end_address: 0xff83fc
      region: otp
      size: 0x2fc
    pcd_sram:
      address: 0x20000000
      end_address: 0x20002000
      region: sram_primary
      size: 0x2000
    rpmsg_nrf53_sram:
      address: 0x20070000
      end_address: 0x20080000
      region: sram_primary
      size: 0x10000
    sram_primary:
      address: 0x20002000
      end_address: 0x20070000
      region: sram_primary
      size: 0x6e000
    

    pm_static.yml

    mcuboot:
        address: 0x0
        end_address: 0xe000
        region: flash_primary
        size: 0xe000
    
    mcuboot_pad:
        address: 0xe000
        end_address: 0xe200
        region: flash_primary
        size: 0x200
    
    app:
        address: 0xe200
        end_address: 0x100000
        region: flash_primary
        size: 0xf1e00
    
    mcuboot_primary_app:
        address: 0xe200
        end_address: 0x100000
        region: flash_primary
        size: 0xf1e00
        span: [app]
    
    mcuboot_primary:
        address: 0xe000
        end_address: 0x100000
        region: flash_primary
        size: 0xf2000
        span: [mcuboot_pad, mcuboot_primary_app]
    
    # define partition for fatfs disk, on the external flash storage (probably the device defined by nordic,pm-ext-flash in the DTS)
    fatfs_storage:
        region: external_flash
        affiliation: 
            - disk
        extra_params: {
            disk_name: "NAND",
            disk_cache_size: 4096,
            disk_sector_size: 512,
            disk_read_only: 0
        }
        # 6Mb size, external flash is 8Mb total
        address: 0x0
        size: 0x600000
    
    nvs_storage:
        region: external_flash
        affiliation: 
            - nvs
        # 64kB size, its just for small stuff
        address: 0x600000
        size: 0x10000
    
    mcuboot_secondary_1:
        region: external_flash
        affiliation: 
            - mcuboot
        # 256kb size, its for netcore flash image
        address: 0x610000
        size: 0x40000
    
    mcuboot_secondary:
        region: external_flash
        affiliation: 
            - mcuboot
        # 1Mb size, its for an application flash image
        address: 0x650000
        size: 0x100000
        #share_size: [mcuboot_primary_app]
    
    # internal cuisine
    otp:
        address: 0xff8100
        end_address: 0xff83fc
        region: otp
        size: 0x2fc
    pcd_sram:
        address: 0x20000000
        end_address: 0x20002000
        #placement:
        #    after:
        #    - start
        region: sram_primary
        size: 0x2000
    rpmsg_nrf53_sram:
        address: 0x20070000
        end_address: 0x20080000
        #placement:
        #    before:
        #    - end
        region: sram_primary
        size: 0x10000
    sram_primary:
        address: 0x20002000
        end_address: 0x20070000
        region: sram_primary
        size: 0x6e000
    
    # TODO need fake flash ram flash partition to do cpunet DFU...
    #mcuboot_primary_1:
    #  address: 0x0
    #  device: nordic_ram_flash_controller
    #  end_address: 0x40000
    #  region: ram_flash
    #  size: 0x40000
    #
    #ram_flash:
    #  address: 0x40000
    #  end_address: 0x40000
    #  region: ram_flash
    #  size: 0x0
    

    ie partition table for internal flash:

    flash_primary (0x100000 - 1024kB):
    +-------------------------------------------------+
    | 0x0: mcuboot (0xe000 - 56kB) |
    +---0xe000: mcuboot_primary (0xf2000 - 968kB)-----+
    | 0xe000: mcuboot_pad (0x200 - 512B) |
    +---0xe200: mcuboot_primary_app (0xf1e00 - 967kB)-+
    | 0xe200: app (0xf1e00 - 967kB) |
    +-------------------------------------------------+

Reply
  • Still complains:

    *** Booting nRF Connect SDK 3758bcbfa5cd ***
    I: Starting bootloader
    W: Cannot upgrade: not a compatible amount of sectors
    I: Bootloader chainload address offset: 0xe000
    I: Jumping to the first image slot
    E: Protect mcuboot flash failed, cancel startup.

    partitions.yml : insert->file "type yml still not allowed."

    app:
      address: 0xe200
      end_address: 0x100000
      region: flash_primary
      size: 0xf1e00
    external_flash:
      address: 0x750000
      end_address: 0x800000
      region: external_flash
      size: 0xb0000
    fatfs_storage:
      address: 0x0
      affiliation:
      - disk
      end_address: 0x600000
      extra_params:
        disk_cache_size: 0x1000
        disk_name: NAND
        disk_read_only: 0x0
        disk_sector_size: 0x200
      region: external_flash
      size: 0x600000
    mcuboot:
      address: 0x0
      end_address: 0xe000
      region: flash_primary
      size: 0xe000
    mcuboot_pad:
      address: 0xe000
      end_address: 0xe200
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0xe000
      end_address: 0x100000
      region: flash_primary
      size: 0xf2000
      span:
      - mcuboot_pad
      - mcuboot_primary_app
    mcuboot_primary_app:
      address: 0xe200
      end_address: 0x100000
      region: flash_primary
      size: 0xf1e00
      span:
      - app
    mcuboot_secondary:
      address: 0x650000
      affiliation:
      - mcuboot
      end_address: 0x750000
      region: external_flash
      size: 0x100000
    mcuboot_secondary_1:
      address: 0x610000
      affiliation:
      - mcuboot
      end_address: 0x650000
      region: external_flash
      size: 0x40000
    nvs_storage:
      address: 0x600000
      affiliation:
      - nvs
      end_address: 0x610000
      region: external_flash
      size: 0x10000
    otp:
      address: 0xff8100
      end_address: 0xff83fc
      region: otp
      size: 0x2fc
    pcd_sram:
      address: 0x20000000
      end_address: 0x20002000
      region: sram_primary
      size: 0x2000
    rpmsg_nrf53_sram:
      address: 0x20070000
      end_address: 0x20080000
      region: sram_primary
      size: 0x10000
    sram_primary:
      address: 0x20002000
      end_address: 0x20070000
      region: sram_primary
      size: 0x6e000
    

    pm_static.yml

    mcuboot:
        address: 0x0
        end_address: 0xe000
        region: flash_primary
        size: 0xe000
    
    mcuboot_pad:
        address: 0xe000
        end_address: 0xe200
        region: flash_primary
        size: 0x200
    
    app:
        address: 0xe200
        end_address: 0x100000
        region: flash_primary
        size: 0xf1e00
    
    mcuboot_primary_app:
        address: 0xe200
        end_address: 0x100000
        region: flash_primary
        size: 0xf1e00
        span: [app]
    
    mcuboot_primary:
        address: 0xe000
        end_address: 0x100000
        region: flash_primary
        size: 0xf2000
        span: [mcuboot_pad, mcuboot_primary_app]
    
    # define partition for fatfs disk, on the external flash storage (probably the device defined by nordic,pm-ext-flash in the DTS)
    fatfs_storage:
        region: external_flash
        affiliation: 
            - disk
        extra_params: {
            disk_name: "NAND",
            disk_cache_size: 4096,
            disk_sector_size: 512,
            disk_read_only: 0
        }
        # 6Mb size, external flash is 8Mb total
        address: 0x0
        size: 0x600000
    
    nvs_storage:
        region: external_flash
        affiliation: 
            - nvs
        # 64kB size, its just for small stuff
        address: 0x600000
        size: 0x10000
    
    mcuboot_secondary_1:
        region: external_flash
        affiliation: 
            - mcuboot
        # 256kb size, its for netcore flash image
        address: 0x610000
        size: 0x40000
    
    mcuboot_secondary:
        region: external_flash
        affiliation: 
            - mcuboot
        # 1Mb size, its for an application flash image
        address: 0x650000
        size: 0x100000
        #share_size: [mcuboot_primary_app]
    
    # internal cuisine
    otp:
        address: 0xff8100
        end_address: 0xff83fc
        region: otp
        size: 0x2fc
    pcd_sram:
        address: 0x20000000
        end_address: 0x20002000
        #placement:
        #    after:
        #    - start
        region: sram_primary
        size: 0x2000
    rpmsg_nrf53_sram:
        address: 0x20070000
        end_address: 0x20080000
        #placement:
        #    before:
        #    - end
        region: sram_primary
        size: 0x10000
    sram_primary:
        address: 0x20002000
        end_address: 0x20070000
        region: sram_primary
        size: 0x6e000
    
    # TODO need fake flash ram flash partition to do cpunet DFU...
    #mcuboot_primary_1:
    #  address: 0x0
    #  device: nordic_ram_flash_controller
    #  end_address: 0x40000
    #  region: ram_flash
    #  size: 0x40000
    #
    #ram_flash:
    #  address: 0x40000
    #  end_address: 0x40000
    #  region: ram_flash
    #  size: 0x0
    

    ie partition table for internal flash:

    flash_primary (0x100000 - 1024kB):
    +-------------------------------------------------+
    | 0x0: mcuboot (0xe000 - 56kB) |
    +---0xe000: mcuboot_primary (0xf2000 - 968kB)-----+
    | 0xe000: mcuboot_pad (0x200 - 512B) |
    +---0xe200: mcuboot_primary_app (0xf1e00 - 967kB)-+
    | 0xe200: app (0xf1e00 - 967kB) |
    +-------------------------------------------------+

Children
  • but it doesn't mention having to set a buffer for mcuboot before the call to dfu_target_init()
    And nowhere in dfu_target.c does it do this?!
    What is the point of having a 'standard' api dfu_target to mask the different 'targets', if app has to explicitly call a target specific function to get it to work? And not described in the doc either?

    So... I changed my code to just use the dfu_target_mscuboot_XXX API directly. This all seems to work just fine, except that after dfu_target completes (with no errors), mcuboot still refuses to update from the secondary slot : the relevant logs:

    [00:00:00.544,769] <inf> base: dfu: opened app_update.bin, image type identified as mcuboot
    [00:00:00.555,236] <inf> base: dfu: starting update of image for app_update.bin
    Copying to secondard slot.................................................................................................................................................................................................................................. DONE
    [00:00:27.828,277] <inf> dfu_target_mcuboot: MCUBoot image-0 upgrade scheduled. Reset device to apply
    [00:00:27.838,562] <inf> base: dfu: no image file for net_core_app_update.bin
    [00:00:27.846,130] <wrn> base: dfu : found new images, rebooting in 5s to update....see you on the other side...
    Rebooting...

    *** Booting nRF Connect SDK 3758bcbfa5cd ***
    I: Starting bootloader
    W: Cannot upgrade: not a compatible amount of sectors
    I: Bootloader chainload address offset: 0xe000

    After a search on this forum, I found this: 

     https://devzone.nordicsemi.com/f/nordic-q-a/94313/mcuboot-runtime-error-cannot-upgrade-not-a-compatible-amount-of-sectors-with-external-flash-on-nrf9160 

    Turns out that the size of the secondard slot MUST be exactly equal to the primary (not just bigger), and that a) this is not enforced at build time and b) the share_size directive does not work in your pm_static.yml.

    [as an aside, I note that post was over 2 years ago, and the information about these 2 points was supposed to being fed back to developers.... but still no fix or even any documentation....]

    Making my mcuboot_secondary partition be the same size as the mcuboot_primary_app one fixed the mcuboot log and now I get:

    ............................................................................................................................................................................................................................ DONE
    [00:00:27.582,580] <inf> dfu_target_mcuboot: MCUBoot image-0 upgrade scheduled. Reset device to apply
    [00:00:27.592,864] <inf> base: dfu: no image file for net_core_app_update.bin
    [00:00:27.600,402] <inf> base: dfu :System write boot ok flag to NVM
    [00:00:27.607,360] <wrn> base: dfu : found new images, rebooting in 5s to update....
    [00:00:30.319,671] <inf> base: System running ok, write boot ok flag to NVM
    Rebooting...see you on the other side...

    *** Booting nRF Connect SDK 3758bcbfa5cd ***
    I: Starting bootloader
    I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
    I: Boot source: none
    I: Image index: 0, Swap type: test
    I: Starting swap using move algorithm.
    I: Bootloader chainload address offset: 0xe000

    And miracle : a working DFU from USB filesystem!

    For those also looking to do this:

    the 'dfu from local file' fn (call it with the name of the file on the FS, and reboot if it returns true). You will need to implement the usb_fs_XX functions, but these are just wrappers round the FAT FS fs_XX api.

    // DFU related code
    static void _dfu_cb(enum dfu_target_evt_id evt_id) {
    	log_info("dfu: callback says event %d", evt_id);
    }
    
    // read blocks of 4K from fle and pass to DFU updater
    // Returns false if couldn't access or dfu the given file 
    #define DFU_BUF_SZ	(4096)
    static bool _do_dfu(char* filename, int img_num) {
    	int32_t fsize = usb_fs_get_file_size(filename);
    	if (fsize<0) {
    		log_info("dfu: no image file for %s",filename);
    		return false;
    	}
    	file_handle_t fh = usb_fs_open_file(filename, true);	// open in read only
    	if (fh==NULL) {
    		log_warn("dfu : failed to open file %s", filename);
    		return false;
    	}
    	uint8_t* buf = Util_amalloc(DFU_BUF_SZ);
    	if (buf==NULL) {
    		usb_fs_close_file(fh);
    		log_warn("dfu : failed to alloc buffer to read %s", filename);
    		return false;
    	}
    	uint32_t buf_sz = 0;
    	// Read first block to let dfu analyse file type
    	buf_sz = usb_fs_read_file(fh, buf, DFU_BUF_SZ);
    	if (buf_sz!=DFU_BUF_SZ) {
    		// image file must be > 4K so if fail to read then give up
    		usb_fs_close_file(fh);
    		Util_afree(buf);
    		log_warn("dfu : failed to read 4K from file %s, %d", filename, buf_sz);
    		return false;
    	}
    	if (!dfu_target_mcuboot_identify(buf)) {
    		usb_fs_close_file(fh);
    		Util_afree(buf);
    		log_warn("dfu : file %s is not an mcuboot image, cannot DFU", filename);
    		return false;
    	}
    	log_info("dfu: opened %s, image type identified as mcuboot", filename);
    	dfu_target_mcuboot_reset();	// always start from beginning as not downloading
    
    	// Give it a scratch buffer for flash writing
    	uint8_t* mcuboot_buf = Util_amalloc(DFU_BUF_SZ);
    	dfu_target_mcuboot_set_buf(mcuboot_buf, DFU_BUF_SZ);
    
    	int ret = dfu_target_mcuboot_init(fsize, img_num, _dfu_cb);
    	if (ret<0) {
    		usb_fs_close_file(fh);
    		Util_afree(buf);
    		Util_afree(mcuboot_buf);
    		log_warn("dfu : init for %s image identified as type mcuboot failed code %d", filename, ret);
    		return false;
    	}
    	log_info("dfu: starting update of image for %s", filename);
    	printk("Copying to secondard slot.");
    	while(buf_sz==DFU_BUF_SZ) {
    		// write the block
    		int wret = dfu_target_mcuboot_write(buf, buf_sz);
    		if (wret==0) {
    			// read the next
    			buf_sz = usb_fs_read_file(fh, buf, DFU_BUF_SZ);
    			printk(".");
    		} else {
    			buf_sz = wret;
    			printk("[WRITE FAIL %d]\n", wret);
    		}
    	}
    	if (buf_sz>0) {
    		// Write the final block
    		buf_sz = dfu_target_mcuboot_write(buf, buf_sz);
    		printk(". DONE\n");
    	}
    	usb_fs_close_file(fh);
    	Util_afree(buf);
    	Util_afree(mcuboot_buf);
    	if (buf_sz<0) {
    		log_warn("dfu : failed during install of file %s, %d", filename, buf_sz);
    		dfu_target_mcuboot_done(false);
    		// TBD : should we delete the 'bad' bin file? or try again next boot?
    		return false;
    	}
    	// Success! Delete the file (we don't want it hanging about and triggering dfu again next boot time!)
    	usb_fs_delete_file(filename);
    	int dret = dfu_target_mcuboot_done(true);
    	if (dret==0) {
    		dret = dfu_target_mcuboot_schedule_update(img_num);
    		if (dret==0) {
    			return true;
    		} else {
    			log_warn("dfu : schedule_update() returns error %d, dfu filed for %s", dret, filename);
    		}
    	} else {
    		log_warn("dfu : done() returns error %d, dfu filed for %s", dret, filename);
    	}
    	return false;
    }
    

    And my pm_static.yml also, as this is also a pain in the neck to get right...

    mcuboot:
        address: 0x0
        end_address: 0xe000
        region: flash_primary
        size: 0xe000
    
    mcuboot_pad:
        address: 0xe000
        end_address: 0xe200
        region: flash_primary
        size: 0x200
    
    app:
        address: 0xe200
        end_address: 0x100000
        region: flash_primary
        size: 0xf1e00
    
    mcuboot_primary_app:
        address: 0xe200
        end_address: 0x100000
        region: flash_primary
        size: 0xf1e00
        span: [app]
    
    mcuboot_primary:
        address: 0xe000
        end_address: 0x100000
        region: flash_primary
        size: 0xf2000
        span: [mcuboot_pad, mcuboot_primary_app]
    
    # define partition for fatfs disk, on the external flash storage (probably the device defined by nordic,pm-ext-flash in the DTS)
    fatfs_storage:
        region: external_flash
        affiliation: 
            - disk
        extra_params: {
            disk_name: "NAND",
            disk_cache_size: 4096,
            disk_sector_size: 512,
            disk_read_only: 0
        }
        # 6Mb size, external flash is 8Mb total
        address: 0x0
        size: 0x600000
    
    nvs_storage:
        region: external_flash
        affiliation: 
            - nvs
        # 64kB size, its just for small stuff
        address: 0x600000
        size: 0x10000
    
    mcuboot_secondary_1:
        region: external_flash
        affiliation: 
            - mcuboot
        # 256kb size, its for netcore flash image
        address: 0x610000
        size: 0x40000
    
    mcuboot_secondary:
        region: external_flash
        affiliation: 
            - mcuboot
        address: 0x650000
        # MUST be same size as the primary application slot size, and share_size does not appear to work
        size: 0xf1e00
        #share_size: [mcuboot_primary_app]
    
    # internal cuisine
    otp:
        address: 0xff8100
        end_address: 0xff83fc
        region: otp
        size: 0x2fc
    pcd_sram:
        address: 0x20000000
        end_address: 0x20002000
        #placement:
        #    after:
        #    - start
        region: sram_primary
        size: 0x2000
    rpmsg_nrf53_sram:
        address: 0x20070000
        end_address: 0x20080000
        #placement:
        #    before:
        #    - end
        region: sram_primary
        size: 0x10000
    sram_primary:
        address: 0x20002000
        end_address: 0x20070000
        region: sram_primary
        size: 0x6e000
    
    # TODO need fake flash ram flash partition to do cpunet DFU...
    #mcuboot_primary_1:
    #  address: 0x0
    #  device: nordic_ram_flash_controller
    #  end_address: 0x40000
    #  region: ram_flash
    #  size: 0x40000
    #
    #ram_flash:
    #  address: 0x40000
    #  end_address: 0x40000
    #  region: ram_flash
    #  size: 0x0
    

    (you're welcome)

    Note app_update.bin is the file generated by the build, and has the mcuboot magic number at the start...

    I haven't yet tried the CPUNET update (as you can see the ram flash simulator is still commented out).

  • Post update : once mcuboot has sucessfully swapped the slots, it runs the new image - great.

    But at the next boot, it swaps back, as it had done the swap in 'test' mode... and then next boot it swaps again... 

    Normally, to stop this 'revert', I understand from the mcuboot doc that the new image must make itself as 'good'. No thanks to the mcuboot doc page (which says nothing about how to do this), it seems this should be as simple as a call to 

    boot_write_img_confirmed();
    (definition in zephyr/dfu/mcuboot.h)
    So, I set a timer, and  60s after boot it pops and I call this method. return is 0, so success. 
    And on the next reset, mcuboot does indeed see the image_ok flag as 0x1 which (according to the doc) is OK.
    But... it swaps anyway
    *** Booting nRF Connect SDK 3758bcbfa5cd ***
    I: Starting bootloader
    I: Primary image: magic=good, swap_type=0x2, copy_done=0x1, image_ok=0x1
    I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
    I: Boot source: none
    I: Image index: 0, Swap type: test
    I: Starting swap using move algorithm.
    I: Bootloader chainload address offset: 0xe000
    I guess this is because although primary image slot is OK, the secondard slot is also still OK, and it didn't set its flag to know ifs the old version or that the 'test' swap was really OK? ALso, image_ok=0x3 - can't find the doc that says what this value is : 0x1 or 0xFF are the only values noted....
    The mcuboot doc (https://docs.nordicsemi.com/bundle/ncs-2.6.2/page/mcuboot/design.html#image_swapping) implies that mcuboot itself should set the magic of the secondary slot to None, to disable it... I would have thought this would be when I call the confirmed() function.... but clearly this has not happend.
     
    Do I need to overwrite the secondary slot image header myself to remove the revert? 
  • After a look at the mcuboot bootutil code, I understand that the value 0x1 means "SET" and 0x3 means "UNSET". So at boot, copy_done=SET, image_ok=SET for primary slot.

    And as I understand the algorithm of mcuboot, ths should mean that even though the swap_type=0x2 (TEST), it should NOT swap to the secondary slot (unless my code expliclty asked for this as part of DFU - which it didn't).

    So, why did mcuboot swap in this case?

  • Hi Brian, 

    As far as I know you only need to call boot_write_img_confirmed() in the application at its first boot after the swap then it should be permanent. 

    You can find the call in the \nrf\samples\bluetooth\mesh\dfu\target sample. Where we call dfu_target_image_confirm() after bluetooth initialized. 

    From what I can see in the code swap type should be set to 

    swap_type = BOOT_SWAP_TYPE_PERM
    in boot_write_img_confirmed-> boot_set_next()

    Could you confirm you call dfu_target_image_confirm() in the application after the first boot after swapping ? 
    Please make sure you give the application enough time to write to flash before reset. 
  • As far as I know you only need to call boot_write_img_confirmed() in the application at its first boot after the swap then it should be permanent. 

    Yes, that was my understanding. My code calls 

    ret = boot_write_img_confirmed();
    exactly as per the sample. However the swap_type remains as BOOT_SWAP_TYPE_TEST - as far as I can see the bootutil code for boot_set_next() just updates the image_ok flag to SET...
    (inspecting the bootutil code on the mcu github)
    Where do you see the swap_type being updated?
Related