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

Using external flash to store updates for MCUboot & App on nRF5340 which the existing MCUBoot will apply

How do I store updated images for both MCUboot and the main App in external flash on the nRF5340 such that the existing MCUboot will apply the updates to the internal flash and execute them? Does the existing MCUboot codebase support this?


I have a nRF5340 with a MX25R6435F flash chip connected via QSPI. It is also connected to an LTE modem (nRF9160) via another SPI bus. The app on the 5340 will download any needed update data from the internet with custom code interfacing to the modem and write the needed update data to the external flash (this functionality is not part of my question here, assume the download and write to external flash of arbitrary data is working).


My main questions are:

  1. In what format do the updated MCUboot and App images need to be stored in external flash? (address offsets, etc.)
  2. Are any changes required to be made to the MCUboot codebase to support this?
  3. Are any additional configuration changes needed other than I what I have listed below?

I have configured my build system to use the B0 Immutable bootloader as the first-stage bootloader and MCUboot as an upgradeable second-stage bootloader. For the flash layout, I believe I have correctly configured the build for a single app image in internal flash, dual MCUboot image slots in internal flash, and the "mcuboot_secondary" slot in external flash. That all appears to be configured, build, and run correctly.

My goal for functionality is:

  1. The old App runs, downloads the updated image(s) to external flash, and triggers a reboot.
  2. The old MCUboot checks the external flash, detects that an update is available, and begins to copy them to internal flash...
  3. The updated MCUboot code is overwritten to the "other" MCUboot slot (the one not currently running).
  4. The updated App code is overwritten to the single App slot which had the old App code.
  5. The old MCUboot triggers a reboot.
  6. B0 detects the updated MCUboot in the "other" slot and executes it.
  7. The updated MCUboot runs and executes the updated App code.

I have read over some of the guides for DFU and bootloaders, but they seem to only apply to BLE updates not using external flash, or to LTE modem updates, or update MCUboot only but not the app; and aren't clear to me for how to achieve my goals. For example:

Device Firmware Upgrade module

Device Firmware Upgrade

Serial Recovery 

Adding an upgradable bootloader

I have tried to debug/follow the code of context_boot_go() in workspace/bootloader/mcuboot/boot/bootutil/src/loader.c:1780 to better understand how MCUboot works and its upgrade process, but it's not clear to me how it needs to read from the external flash.

My configuration is as follows

Using NCS 1.6.0

Flash layout from west tool:

  external_flash (0x800000 - 8192kB):
+------------------------------------------------+
| 0x0: mcuboot_secondary (0x100000 - 1024kB)     |
| 0x100000: littlefs_storage (0x700000 - 7168kB) |
| 0x800000: external_flash (0x0 - 0B)            |
+------------------------------------------------+

  flash_primary (0x100000 - 1024kB):
+--------------------------------------------------+
+---0x0: b0_container (0x8000 - 32kB)--------------+
| 0x0: b0 (0x8000 - 32kB)                          |
+---0x8000: s0 (0x10000 - 64kB)--------------------+
| 0x8000: s0_pad (0x200 - 512B)                    |
+---0x8200: s0_image (0xfe00 - 63kB)---------------+
| 0x8200: mcuboot (0xfe00 - 63kB)                  |
+---0x18000: s1 (0x10000 - 64kB)-------------------+
| 0x18000: s1_pad (0x200 - 512B)                   |
| 0x18200: s1_image (0xfe00 - 63kB)                |
+---0x28000: mcuboot_primary (0xd2000 - 840kB)-----+
| 0x28000: mcuboot_pad (0x200 - 512B)              |
+---0x28200: mcuboot_primary_app (0xd1e00 - 839kB)-+
+---0x28200: spm_app (0xd1e00 - 839kB)-------------+
| 0x28200: app (0xd1e00 - 839kB)                   |
+--------------------------------------------------+
| 0xfa000: factory_cfg_1 (0x1000 - 4kB)            |
| 0xfb000: user_cfg_1 (0x1000 - 4kB)               |
| 0xfc000: developer_cfg_1 (0x1000 - 4kB)          |
| 0xfd000: factory_cfg_2 (0x1000 - 4kB)            |
| 0xfe000: user_cfg_2 (0x1000 - 4kB)               |
| 0xff000: developer_cfg_2 (0x1000 - 4kB)          |
+--------------------------------------------------+

  otp (0x2fc - 764B):
+------------------------------------+
| 0xff8100: provision (0x280 - 640B) |
| 0xff8380: otp (0x7c - 124B)        |
+------------------------------------+

  sram_primary (0x80000 - 512kB):
+--------------------------------------------+
| 0x20000000: sram_primary (0x7e000 - 504kB) |
| 0x2007e000: pcd_sram (0x2000 - 8kB)        |
+--------------------------------------------+

prj.conf (relevant sections)

# FLASH
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_SHELL=y
CONFIG_SETTINGS=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y

# Secure Immutable Bootloader (B0)
CONFIG_SECURE_BOOT=y

# MCUBOOT
CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_IMG_MANAGER=y
CONFIG_MCUBOOT_IMG_MANAGER=y
CONFIG_IMG_ERASE_PROGRESSIVELY=y
CONFIG_BUILD_S1_VARIANT=

mcuboot.conf (applied to the MCUboot image in CMake system)

CONFIG_NORDIC_QSPI_NOR=y
CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=4
CONFIG_MULTITHREADING=y
CONFIG_BOOT_MAX_IMG_SECTORS=256
CONFIG_PM_EXTERNAL_FLASH=y
CONFIG_PM_EXTERNAL_FLASH_DEV_NAME="MX25R64"
CONFIG_PM_EXTERNAL_FLASH_SIZE=0x800000
CONFIG_PM_EXTERNAL_FLASH_BASE=0x000000

CONFIG_BUILD_S1_VARIANT=y

pm_static.yml

# Config/Settings Partition:
factory_cfg_1:
  address: 0xfa000
  end_address: 0xfb000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x1000

user_cfg_1:
  address: 0xfb000
  end_address: 0xfc000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x1000

developer_cfg_1:
  address: 0xfc000
  end_address: 0xfd000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x1000

#Backup Config Partitions
factory_cfg_2:
  address: 0xfd000
  end_address: 0xfe000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x1000

user_cfg_2:
  address: 0xfe000
  end_address: 0xff000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x1000

developer_cfg_2:
  address: 0xff000
  end_address: 0x100000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x1000


# External Flash Partitions
mcuboot_secondary:
  address: 0x0
  device: MX25R64
  end_address: 0x100000
  region: external_flash
  size: 0x100000

littlefs_storage:
  address: 0x100000
  device: MX25R64
  end_address: 0x800000
  region: external_flash
  size: 0x700000

normal boot log

*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
Attempting to boot slot 0.
Attempting to boot from address 0x8200.
Verifying signature against key 0.
Hash: 0xfa...2e
Firmware signature verified.
Firmware version 1
*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
I: Starting bootloader
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Swap type: none
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Swap type: none
I: Bootloader chainload address offset: 0x28000
�: Jumping to the first image slot

[00:00:00.020,080] <dbg> fs.fs_register: fs register 1: 0
*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
nrf5340:~$

With some debug prints in MCUboot, I was able to see that MCUboot does at least open the external flash partition for access

*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
Attempting to boot slot 0.
Attempting to boot from address 0x8200.
Verifying signature against key 0.
Hash: 0xfa...2e
Firmware signature verified.
Firmware version 1
Setting monotonic counter (version: 1, slot: 0)
*** Booting Zephyr OS build v2.6.0-rc1-ncs1  ***
I: Starting bootloader
Flash open 11 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
Flash open 11 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
Flash open 11 -NRF_FLASH_DRV_NAME
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
Flash open 2 -MX25R64
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
Flash open 11 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
Flash open 11 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
I: Swap type: none
Flash open 7 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
Flash open 7 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
Flash open 7 -NRF_FLASH_DRV_NAME
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
Flash open 2 -MX25R64
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
Flash open 7 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
Flash open 7 -NRF_FLASH_DRV_NAME
Flash open 2 -MX25R64
I: Swap type: none
Flash open 11 -NRF_FLASH_DRV_NAME
Flash open 11 -NRF_FLASH_DRV_NAME
I: Bootloader chainload address offset: 0x28000
�: Jumping to the first image slot

Parents
  • Hi,

     

    How do I store updated images for both MCUboot and the main App in external flash on the nRF5340 such that the existing MCUboot will apply the updates to the internal flash and execute them? Does the existing MCUboot codebase support this?

     We support using an external flash as a secondary slot, but you cannot boot directly from this external flash (ie. it needs to verify, copy, then run). In your current layout, the secondary slot should be 0xd2000 bytes.

    In what format do the updated MCUboot and App images need to be stored in external flash? (address offsets, etc.)

    This is up to you, and how you define your partition layout (pm_static.yml).

    There is a restriction in the mcuboot_secondary size, which must match the size of mcuboot_primary (with a slack of one flash size)

    • Are any changes required to be made to the MCUboot codebase to support this?

     You will need to configure mcuboot to understand that it should look for a secondary partition on a external flash device.

    • Are any additional configuration changes needed other than I what I have listed below?

     Here's a simplified example using hello_world for nrf5340:

    hello_world_mcuboot_qspi_nrf53.zip

    Could you try this and see if that works on your end? 

    This does not include b0, but the principle is quite similar if you add that "on-top"

     

    Kind regards,

    Håkon

Reply
  • Hi,

     

    How do I store updated images for both MCUboot and the main App in external flash on the nRF5340 such that the existing MCUboot will apply the updates to the internal flash and execute them? Does the existing MCUboot codebase support this?

     We support using an external flash as a secondary slot, but you cannot boot directly from this external flash (ie. it needs to verify, copy, then run). In your current layout, the secondary slot should be 0xd2000 bytes.

    In what format do the updated MCUboot and App images need to be stored in external flash? (address offsets, etc.)

    This is up to you, and how you define your partition layout (pm_static.yml).

    There is a restriction in the mcuboot_secondary size, which must match the size of mcuboot_primary (with a slack of one flash size)

    • Are any changes required to be made to the MCUboot codebase to support this?

     You will need to configure mcuboot to understand that it should look for a secondary partition on a external flash device.

    • Are any additional configuration changes needed other than I what I have listed below?

     Here's a simplified example using hello_world for nrf5340:

    hello_world_mcuboot_qspi_nrf53.zip

    Could you try this and see if that works on your end? 

    This does not include b0, but the principle is quite similar if you add that "on-top"

     

    Kind regards,

    Håkon

Children
No Data
Related