Custom MCUboot DFU bootloader nrf Connect

Hi,

We want to modify the bootloader process on MCUboot. To avoid someone having to press and hold a button the entire time on our custom boards we want as a minimum to set a pin high to ensure it doesn't turn off.

I was successfully able to try this using SYS_INIT and a custom board.c file by following this ticket  Modify the MCUboot's booting process however, the problem I've found with this method is it sets the pin high regardless of whether the unit goes through the bootloader or not - which makes sense. In some instances we want to indicate the bootloader is running by switching on an LED just as user feedback something's going on. So a potential flicker of the LED (e.g. switching it off ASAP in the main app) would be inappropriate for our devices. 

It looks therefore that the best way to achieve what we want is by modifying the bootloader and I've gone down a ticket rabbit hole through here  How to create custom MCUBOOT for DFU which ends up leading to this blog archive:  nRF Connect SDK Tutorial - Part 2 | NCS v1.3.0 

is there a more up to date and recommended way of customising the mcuboot? Our aim would be to have a file within the main project directory that handles the main functions of the boot but adds in our own "switch on this pin" code.

Thanks.

BR,
Richard

Parents
  • Hi,

    To avoid someone having to press and hold a button the entire time on our custom boards

    Could you explain this some more? Why does a use need to press and hold a button?

  • Hi Sigurd,

    On most of our boards we have a soft power on that maintains the power after being physically switched on via a button. The board is therefore either on by pressing and holding the button, or on if a pin is held high.

    BR,
    Richard

  • That looks promising. Where does the handler for mcuboot_status_change need to be placed?

    I've added it in the main project directory at the moment (which I suspected would be wrong), I'm getting this in the build log:

    c:/ncs/toolchains/v2.1.2/opt/zephyr-sdk/arm-zephyr-eabi/bin/../lib/gcc/arm-zephyr-eabi/10.3.0/../../../../arm-zephyr-eabi/bin/ld.exe: app/libapp.a(loader.c.obj): in function `context_boot_go':
    C:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\src\loader.c:2112: undefined reference to `mcuboot_status_change'
    collect2.exe: error: ld returned 1 exit status

    I added 

    CONFIG_MCUBOOT_ACTION_HOOKS=y into my mcuboot.conf file which is within a child_image folder.
  • Hi,

    I haven't tested it, but I'm thinking that you in CMakeLists.txt in boards/arm/your_board , can add something like this:

    if(CONFIG_MCUBOOT)
    zephyr_library()
    zephyr_library_sources(my_mcuboot_hook.c)
    endif()

    Then place a my_mcuboot_hook.c in boards/arm/your_board

    Might need to include these:

    #include "bootutil/boot_hooks.h"
    #include "bootutil/mcuboot_status.h"

  • Thank you, I've got that running. Unfortunately, not exactly how I was expecting.

    I realise I didn't mention we're doing the upgrade via bluetooth and nrf Connect google play store app. The lack of MCUBOOT_STATUS references to BLE types seem to indicate those status updates aren't supported?

    In which case, it's basically back to the initial query on the best process for this?

    I've added this:

    void mcuboot_status_change(mcuboot_status_type_t status)
    {
    	printk("mcuboot status: %d \n", status);
    }

    and my terminal output is below (emphasis mine). Perhaps my misunderstanding, but I wouldn't expect the 'normal' startup process to hit the status of 1 (MCUBOOT_STATUS_UPGRADING)?

    *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    I: Starting bootloader
    mcuboot status: 0
    I: Primary image: magic=good, swap_type=0x2, copy_done=0x1, image_ok=0x1
    I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    I: Boot source: none
    I: Swap type: none
    mcuboot status: 1
    I: Bootloader chainload address offset: 0xc000
    I: Jumping to the first image slot
    *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    Bluetooth initialized
    Advertising successfully started
    build time: Nov 30 2022 12:23:46


    uart:~$ Connected
    [00:00:26.260,498] <inf> mcuboot_util: Swap type: none
    [00:00:26.260,772] <inf> mcuboot_util: Swap type: none
    [00:00:26.412,780] <inf> mcuboot_util: Swap type: none
    [00:00:26.412,872] <inf> mcuboot_util: Swap type: none
    [00:00:34.729,522] <inf> mcumgr_img_mgmt: Erased 0x39000 bytes of image slot
    [00:00:34.875,823] <inf> mcumgr_img_mgmt: Erased 0x1000 bytes of image slot trailer
    uart:~$ *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    I: Starting bootloader
    mcuboot status: 0
    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: Swap type: test
    mcuboot status: 1
    I: Starting swap using move algorithm.
    I: Bootloader chainload address offset: 0xc000
    I: Jumping to the first image slot
    *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    Bluetooth initialized
    Advertising successfully started
    build time: Nov 30 2022 12:01:21


    uart:~$ Connected
    [00:00:01.227,844] <inf> mcuboot_util: Swap type: revert
    [00:00:01.227,905] <inf> mcuboot_util: Swap type: revert
    [00:00:01.228,546] <inf> mcuboot_util: Swap type: none
    [00:00:01.228,820] <inf> mcuboot_util: Swap type: none
    uart:~$

Reply
  • Thank you, I've got that running. Unfortunately, not exactly how I was expecting.

    I realise I didn't mention we're doing the upgrade via bluetooth and nrf Connect google play store app. The lack of MCUBOOT_STATUS references to BLE types seem to indicate those status updates aren't supported?

    In which case, it's basically back to the initial query on the best process for this?

    I've added this:

    void mcuboot_status_change(mcuboot_status_type_t status)
    {
    	printk("mcuboot status: %d \n", status);
    }

    and my terminal output is below (emphasis mine). Perhaps my misunderstanding, but I wouldn't expect the 'normal' startup process to hit the status of 1 (MCUBOOT_STATUS_UPGRADING)?

    *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    I: Starting bootloader
    mcuboot status: 0
    I: Primary image: magic=good, swap_type=0x2, copy_done=0x1, image_ok=0x1
    I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    I: Boot source: none
    I: Swap type: none
    mcuboot status: 1
    I: Bootloader chainload address offset: 0xc000
    I: Jumping to the first image slot
    *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    Bluetooth initialized
    Advertising successfully started
    build time: Nov 30 2022 12:23:46


    uart:~$ Connected
    [00:00:26.260,498] <inf> mcuboot_util: Swap type: none
    [00:00:26.260,772] <inf> mcuboot_util: Swap type: none
    [00:00:26.412,780] <inf> mcuboot_util: Swap type: none
    [00:00:26.412,872] <inf> mcuboot_util: Swap type: none
    [00:00:34.729,522] <inf> mcumgr_img_mgmt: Erased 0x39000 bytes of image slot
    [00:00:34.875,823] <inf> mcumgr_img_mgmt: Erased 0x1000 bytes of image slot trailer
    uart:~$ *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    I: Starting bootloader
    mcuboot status: 0
    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: Swap type: test
    mcuboot status: 1
    I: Starting swap using move algorithm.
    I: Bootloader chainload address offset: 0xc000
    I: Jumping to the first image slot
    *** Booting Zephyr OS build v3.1.99-ncs1-1 ***
    Bluetooth initialized
    Advertising successfully started
    build time: Nov 30 2022 12:01:21


    uart:~$ Connected
    [00:00:01.227,844] <inf> mcuboot_util: Swap type: revert
    [00:00:01.227,905] <inf> mcuboot_util: Swap type: revert
    [00:00:01.228,546] <inf> mcuboot_util: Swap type: none
    [00:00:01.228,820] <inf> mcuboot_util: Swap type: none
    uart:~$

Children
  • Hi,

    I checked this with the developer, MCUBOOT_STATUS_UPGRADING does not necessarily mean that it is upgrading the image, just that it is at the point of mcuboot where upgrades take place... https://github.com/zephyrproject-rtos/mcuboot/blob/main/boot/bootutil/src/loader.c#L2059

    to make it only run if an upgrade is present, it could be placed in an if()

    PS: It might be getting cut off due to booting the application but the status does change prior to the application booting: mcuboot_status_change(MCUBOOT_STATUS_BOOTABLE_IMAGE_FOUND);

  • to make it only run if an upgrade is present, it could be placed in an if()

    Excuse my ignorance, but which part exactly would be placed in an if, and what's being checked?

    I'm already doing this:

    if(CONFIG_MCUBOOT)
    zephyr_library()
    zephyr_library_sources(my_mcuboot_hook.c)
    endif()

    BR,
    Richard

  • Richard said:
    Excuse my ignorance, but which part exactly would be placed in an if, and what's being checked?

    Something like this at https://github.com/zephyrproject-rtos/mcuboot/blob/main/boot/bootutil/src/loader.c#L2059

    if(has_upgrade) {
        mcuboot_status_change(MCUBOOT_STATUS_UPGRADING);
    
    }

    Some other alternatives that might work is to use boot_perform_update_hook() instead

    https://github.com/nrfconnect/sdk-mcuboot/blob/main/boot/zephyr/hooks_sample.c

  • Our preference is to avoid editing the files in the SDK, I've done it to test it out and it has worked in the sense that the state of the pin no longer persists into the main app, however the LED i'm using to test the pin change only comes on right at the end of the DFU process during validation and not during the actual update process, this is too late.

    boot_perform_update_hook doesn't seem to work in the same way as the status change?

    Lots of warnings when the boot_hooks.h is included:

    c:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\include\bootutil\boot_hooks.h:71:40: warning: 'struct image_header' declared inside parameter list will not be visible outside of this definition or declaration
    71 | struct image_header *img_head);
    | ^~~~~~~~~~~~
    c:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\include\bootutil\boot_hooks.h:101:43: warning: 'struct flash_area' declared inside parameter list will not be visible outside of this definition or declaration
    101 | const struct flash_area *area);
    | ^~~~~~~~~~
    c:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\include\bootutil\boot_hooks.h:100:52: warning: 'struct image_header' declared inside parameter list will not be visible outside of this definition or declaration
    100 | int boot_perform_update_hook(int img_index, struct image_header *img_head,
    | ^~~~~~~~~~~~
    c:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\include\bootutil\boot_hooks.h:119:60: warning: 'struct flash_area' declared inside parameter list will not be visible outside of this definition or declaration
    119 | int boot_copy_region_post_hook(int img_index, const struct flash_area *area,
    | ^~~~~~~~~~
    c:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\include\bootutil\boot_hooks.h:137:59: warning: 'struct flash_area' declared inside parameter list will not be visible outside of this definition or declaration
    137 | int boot_serial_uploaded_hook(int img_index, const struct flash_area *area,
    | ^~~~~~~~~~
    C:\ncs\v2.1.2\zephyr\boards\arm\nrf52840dk_nrf52840\board.c:61:52: warning: 'struct image_header' declared inside parameter list will not be visible outside of this definition or declaration
    61 | int boot_perform_update_hook(int img_index, struct image_header *img_head,
    | ^~~~~~~~~~~~
    C:\ncs\v2.1.2\zephyr\boards\arm\nrf52840dk_nrf52840\board.c:61:5: error: conflicting types for 'boot_perform_update_hook'
    61 | int boot_perform_update_hook(int img_index, struct image_header *img_head,
    | ^~~~~~~~~~~~~~~~~~~~~~~~
    In file included from C:\ncs\v2.1.2\zephyr\boards\arm\nrf52840dk_nrf52840\board.c:12:
    c:\ncs\v2.1.2\bootloader\mcuboot\boot\bootutil\include\bootutil\boot_hooks.h:100:5: note: previous declaration of 'boot_perform_update_hook' was here
    100 | int boot_perform_update_hook(int img_index, struct image_header *img_head,

  • Hi,

    1)

    You might need to add this to include

    #include "bootutil/bootutil.h"

    and maybe this to CMakeLists.txt

    add_subdirectory(${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/bootutil/zephyr
                     ${CMAKE_CURRENT_BINARY_DIR}/boot/bootutil/zephyr
    )

    2)

    Another alternative, that might be suitable, is to use CONFIG_OS_MGMT_RESET_HOOK

    https://github.com/nrfconnect/sdk-zephyr/commit/d67a364ace006f16019dc4fe0bc689df2dea55f8

    Register the callback with os_mgmt_register_reset_evt_cb(). Do this in the main application

    When mcumgr requests the application to reboot(typically after a new image has been sent), you can set a GPIO high in the reset callback.

Related