What is the proper way to generate an image that is confirmed with MCUBoot

Hei!

I am currently working on a project where we have implemented FOTA and I have had a lot of issues with flashing fresh boards with the complete firmware package.

Our project has a "self test" procedure, so it will check if the currently running image is confirmed, do the self-test, which confirms the image, and then reboot.

What I have experienced is that flashing a brand new chip with the merged.hex file will cause an infinite reboot loop. I think I have concluded that the issue is with the MCUBoot trailer not being included in the merged.hex file. I have modded the CMake files in the nRF Connect SDK to create a confirmed image by adding the --confirm flag to the target which creates the test update.

Flashing first the merged.hex, then the app_test_update.hex, which now is padded and confirmed, fixes this issue.

Is there a way that I can generate a fully confirmed image with the nRF Connect SDK?

We are using v1.9.1 of the SDK.

Parents
  • Hi,

    When you build an application with MCUboot you will get an autogenerated signed image, app_signed.hex. So you can just program the chip with this instead of merged.hex. You can find an overview of the different files that are generated here: Using MCUboot in nRF Connect SDK.

    Best regards,

    Marte

  • This is the output from MCUBoot after flashing merged.hex, then app_signed.hex:

    *** Booting Zephyr OS build v2.7.99-ncs1-1  ***
    [00:00:00.226,409] <inf> mcuboot: Starting bootloader
    [00:00:00.227,630] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,118] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,546] <inf> mcuboot: Boot source: none
    [00:00:00.228,942] <inf> mcuboot: Swap type: none
    [00:00:00.622,161] <inf> mcuboot: Bootloader chainload address offset: 0x10000
    [00:00:00.622,497] <inf> mcuboot: Jumping to the first image slot
    *** Booting Zephyr OS build v2.7.99-ncs1-1  ***
    [00:00:00.226,409] <inf> mcuboot: Starting bootloader
    [00:00:00.227,630] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,118] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,546] <inf> mcuboot: Boot source: none
    [00:00:00.228,942] <inf> mcuboot: Swap type: none
    [00:00:00.622,100] <inf> mcuboot: Bootloader chainload address offset: 0x10000
    [00:00:00.622,467] <inf> mcuboot: Jumping to the first image slot
    *** Booting Zephyr OS build v2.7.99-ncs1-1  ***
    [00:00:00.226,379] <inf> mcuboot: Starting bootloader
    [00:00:00.227,600] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,088] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,515] <inf> mcuboot: Boot source: none
    [00:00:00.228,881] <inf> mcuboot: Swap type: none
    [00:00:00.621,673] <inf> mcuboot: Bootloader chainload address offset: 0x10000
    [00:00:00.622,039] <inf> mcuboot: Jumping to the first image slot
    *** Booting Zephyr OS build v2.7.99-ncs1-1  ***
    [00:00:00.226,440] <inf> mcuboot: Starting bootloader
    [00:00:00.227,661] <inf> mcuboot: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,149] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.228,576] <inf> mcuboot: Boot source: none
    [00:00:00.228,942] <inf> mcuboot: Swap type: none
    [00:00:00.621,673] <inf> mcuboot: Bootloader chainload address offset: 0x10000
    [00:00:00.622,009] <inf> mcuboot: Jumping to the first image slot
    

    This is the output using my generated image:

    *** Booting Zephyr OS build v2.7.99-ncs1-1  ***
    [00:00:00.362,670] <inf> mcuboot: Starting bootloader
    [00:00:00.363,891] <inf> mcuboot: Primary image: magic=good, swap_type=0x1, copy_done=0x3, image_ok=0x1
    [00:00:00.364,379] <inf> mcuboot: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    [00:00:00.364,807] <inf> mcuboot: Boot source: primary slot
    [00:00:00.368,591] <inf> mcuboot: Swap type: none
    [00:00:00.761,627] <inf> mcuboot: Bootloader chainload address offset: 0x10000
    [00:00:00.761,993] <inf> mcuboot: Jumping to the first image slot

  • We connect  to LTE, read some data from MQTT, and call the `boot_write_img_confirmed`, when all functionality is verified.

    The `boot_write_img_confirmed` call never fails, but an image without the image trailer seems to not be able to write this flag properly.

    The functionality works as expected, as long as the mcuboot image trailer is present in flash.

  • Hi,

    One option that is similar to what you are doing originally is to use CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS to add --confirm as an argument. Then you do not have to change different SDK CMake files. However, you should be careful with this approach, as this will cause it to skip testing even if you are using app_update.bin, which is unsigned, later.

    If the image is not confirmed, MCUboot should hang, and not reboot, so the question is what in the application is causing the reboot. Can you enable more logging, and try to debug to see where it fails?

    Best regards,

    Marte

  • Having all the images confirmed is not very desirable as I still would like to have unconfirmed images for testing and the actual firmware update.

    In my application the self-test is only run if the image is not confirmed. So when flashing the unconfirmed merged.hex image the following happens:

    1. MCUBoot boots and loads the image in slot 1(which is unconfirmed and has no image trailed)

    2. The application boots and checks if the running image is confirmed.

    3. Since the image is not confirmed a self-test is run. The application calls boot_write_img_confirmed.

    4. After the self-test is completed the application reboots.

    5. MCUBoot boots back up after the reset and loads application in slot 1(which for some reason is still not confirmed).

    6. Go to step 2.

    I have confirmed that the image does indeed call boot_write_img_confirmed and the call does not fail.

    I have found out, from the zephyr implementation, that if the image magic is unset it counts the image as already confirmed if you are trying to write the image confirmed, but when your read out the boot_is_img_confirmed, no such check is done, so an image that does not have the image trailer cannot be confirmed.

    So having a way to have a confirmed image built would really help.

  • Hi,

    I agree that there seems to be some inconsistent behavior between boot_write_img_confirmed and boot_is_img_confirmed. I have asked the development team about this, and I will let get back to you when I hear back from them.

    Best regards,

    Marte

  • Hi,

    The developers have made a possible fix for the issue: https://github.com/zephyrproject-rtos/zephyr/pull/51743/files. Can you try this and see if it fixes the issue?

    Best regards,

    Marte

Reply Children
Related