DFU Target with MCUboot update file

Hello,

I am attempting to use the DFU Target library to receive an update file over a custom protocol. I aim to do an MCUboot-style upgrade such that after the file upload, I can call dfu_target_schedule_update() and MCUboot will recognize the new image upon reboot. 

So far, I am able to upload the app_update.bin file and write it to the secondary partition (external flash in my case) using the DFU Target libraries. I finish the upload by calling dfu_target_done(1); followed by dfu_target_schedule_update(0); where 0 is to signify the application core image. Upon reboot, I get the following message:

 

I: Starting bootloader
I: Image index: 0, Swap type: test
E: Image in the secondary slot is not valid!
I: Image index: 1, Swap type: none
I: Bootloader chainload address offset: 0x18000
I: Jumping to the first image slot

It seems that MCUboot recognized my new image, but after debugging, the calculated hash does not match the hash that MCUboot wants. 

Is app_update.bin the appropriate image to write into the secondary partition with the DFU Target library? If not, what is the appropriate image? Also, does the DFU Target library take care of writing the image trailer into the secondary partition as well? 

I will note that I am using a pm_static.yml file, and that is getting recognized correctly by the build system.

Thank you, and I appreciate your help.

Parents
  • Hello,

    Could you tell me which version of the nRF Connect SDK you are using here?

    Is app_update.bin the appropriate image to write into the secondary partition with the DFU Target library? I

    Yes, the app_update.bin file is the correct image to upload.

    The error message "Image in the secondary slot is not valid!" typically occurs when the image is not signed, or the image trailer (which contains the hash and metadata) is missing or incorrect.

    Since you're using a custom pm_static.yml, ensure that the secondary partition is correctly defined for MCUboot. The image is typically written to a specific partition (the secondary slot) where MCUboot expects to find it. Make sure the secondary partition in your pm_static.yml is properly configured and matches the expected partition layout that MCUboot uses.

    Kind Regards,

    Abhijith

  • Hello Abhijith

    I am using nRF Connect SDK v2.6.0. Thank you for confirming that app_update.bin is the correct image to upload. 

    Does the DFU Target library take care of writing the image trailer into the secondary partition?

    I am signing the image. I have used imgtool.py to generate the MCUboot key: 

    python3 <NCS_PATH>/bootloader/mcuboot/scripts/imgtool.py keygen -t ecdsa-p256 -k priv.pem

    Here is my mcuboot.conf file:

    # Increase main stack size
    CONFIG_MAIN_STACK_SIZE=10240
    
    # Configure logger
    CONFIG_LOG=y
    CONFIG_MCUBOOT_LOG_LEVEL_DBG=y
    CONFIG_MCUBOOT_UTIL_LOG_LEVEL_DBG=y
    ## Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y
    CONFIG_CBPRINTF_NANO=y
    
    # Configure MCUboot features
    CONFIG_NRF53_MULTI_IMAGE_UPDATE=y
    CONFIG_BOOT_UPGRADE_ONLY=y
    CONFIG_BOOT_MAX_IMG_SECTORS=256
    CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y
    
    # Allow for storing two images in MCUboot partitions
    CONFIG_UPDATEABLE_IMAGE_NUMBER=2
    
    # Store new images inside external flash
    CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
    CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y
    
    # Enable flash simulator
    CONFIG_PCD_APP=y
    CONFIG_FLASH_SIMULATOR=y
    CONFIG_FLASH_SIMULATOR_DOUBLE_WRITES=y
    CONFIG_FLASH_SIMULATOR_STATS=n
    
    # Configure QSPI for external flash
    CONFIG_FLASH=y
    CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x15000
    CONFIG_NORDIC_QSPI_NOR=y
    
    # Increase number of sectors
    CONFIG_BOOT_MAX_IMG_SECTORS=256
    
    # Enable direct image upload
    # CONFIG_MCUBOOT_SERIAL_DIRECT_IMAGE_UPLOAD=y
    
    # Set boot signature type
    CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y

    And here is the relevant portion of my prj.conf file: 

    # Bootloader configurations
    CONFIG_BOOTLOADER_MCUBOOT=y
    CONFIG_B0N_MINIMAL=y
    CONFIG_ZCBOR=y
    CONFIG_CRC=y
    CONFIG_BASE64=y
    
    # Configure dependencies for CONFIG_IMG_MANAGER  
    CONFIG_FLASH=y
    CONFIG_IMG_MANAGER=y
    CONFIG_STREAM_FLASH=y
    CONFIG_STREAM_FLASH_ERASE=y
    CONFIG_FLASH_MAP=y
     
    # DFU Target Library Configurations
    CONFIG_DFU_MULTI_IMAGE=y
    CONFIG_DFU_TARGET=y
    CONFIG_DFU_TARGET_MCUBOOT=y
    CONFIG_DFU_MULTI_IMAGE_PACKAGE_BUILD=y
    
    CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.2"

    Please let me know if you have any other advice.

    Thank you,

    Emily

  • Hello,

    If you're already signing the image using imgtool.py, and adding the signing key in your CMakeLists.txt, the build system should generate an image that includes the trailer as part of the image. This means the app_update.bin already has the required metadata and trailer that MCUboot needs for verification. DFU Target library's job is to write the image to the correct partition and manage the scheduling of the update.

    emilyd said:
    Please let me know if you have any other advice.

    Is it because of the versioning? MCUboot compares the version in the primary slot with the version of the new image in the secondary slot during the DFU process. If the version in the secondary slot is lower or the same as the version in the primary slot, MCUboot will refuse to perform the swap or validation, which can also be the reason for the error message you are getting.

    Kind Regards,

    Abhijith

Reply
  • Hello,

    If you're already signing the image using imgtool.py, and adding the signing key in your CMakeLists.txt, the build system should generate an image that includes the trailer as part of the image. This means the app_update.bin already has the required metadata and trailer that MCUboot needs for verification. DFU Target library's job is to write the image to the correct partition and manage the scheduling of the update.

    emilyd said:
    Please let me know if you have any other advice.

    Is it because of the versioning? MCUboot compares the version in the primary slot with the version of the new image in the secondary slot during the DFU process. If the version in the secondary slot is lower or the same as the version in the primary slot, MCUboot will refuse to perform the swap or validation, which can also be the reason for the error message you are getting.

    Kind Regards,

    Abhijith

Children
  • Hello Abhijith,

    Thank you for your clarification about the image trailer.

    I believe I am including the versioning correctly. 

    CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.2" is in my prj.conf and I load an app_update.bin that has a higher revision compiled in. 
    I have now noticed that the in image header that MCUboot reads (hdr->ih_img_size), the size is always between 662 and 664 bytes less than the actual size of app_update.bin. For example, I have written 380692 bytes, but hdr->ih_img_size is 380028 bytes. I am assuming that this incorrect length contributes to the incorrect hash calculation. I am not sure where this length mismatch is coming from, as before I call dfu_target_done(1), I can see that the dfu_target_offset_get() returns the correct total file length. 
    I am now debugging to see where this image header is written and where the total image size is calculated incorrectly. Let me know if you have any insight on this. 
    Thank you,
    Emily
  • Hello,

    emilyd said:
    I have now noticed that the in image header that MCUboot reads (hdr->ih_img_size), the size is always between 662 and 664 bytes less than the actual size of app_update.bin. For example, I have written 380692 bytes, but hdr->ih_img_size is 380028 bytes

    That's actually a great finding. Do you have an update on this? Were you able to tackle the issue?

    The difference of around 662-664 bytes might be coming from the size of the image trailer itself. The image trailer is usually appended to the end of the image and is not part of the ih_img_size. The MCUboot image header contains the ih_img_size field, which should match the size of the actual image (excluding the trailer). The size recorded in the header is critical because MCUboot uses this size to compute the hash for verification. If this size is wrong, MCUboot will compute the wrong hash, leading to validation failure.

    Kind Regards,

    Abhijith

  • Hello Abhijith,

    Yes, I believe that 662-664 byte length difference is due to the image trailer. I have another project that uses MCUboot successfully, and I saw this byte difference there as well.

    My invalid image error was due to there being occasional empty pages in my external flash when there should've been a portion of an image. These empty pages therefore caused the calculated hash to be incorrect, since the image actually was invalid. 

    I was able to solve this by setting the sck-delay parameter in my qspi devicetree entry. It was previously unset and defaulted to 0. 

    After consulting with my particular QSPI flash chip's datasheet, sck-delay = <60> resolved the errors that I was seeing, and the image in the QSPI was correct. 
    My device will now successfully recognize the new image in the secondary partition (app_update.bin) and write that to the primary partition. Making sure that the image is versioned correctly as well as signed using a key generated by imgtool.py are also key components for this to be successful. 
    To anyone using an external QSPI flash, I found Nordic command line tools to be very helpful. The nrfjprog --readqspi command in particular was very helpful, as well as nrfjprog --qspieraseall
    Thank you for your help!
     
Related