Cannot confirm image after swapping from external secondary mcuboot partition

Hello,

I have an nrf52833 that interfaces with an external flash module. It is configured  to store mcuboot's secondary partition. I am able to write the secondary image and after it swaps, it does boot into this image correctly, but I am not able to confirm the image.

I am using the dfu target api for the firmware image and the mcuboot image control api to confirm the image. The function ` boot_write_img_confirmed` returns 0 which supposedly means that it was successful, however reading the `mcuboot_swap_type` function still returns `revert` and the next time the chip is reset, it reverts to the old image.

I am using this same process on the Laird P100 which also uses an external flash and it works correctly.

I found other posts with this issue where the solution was switching from a dynamic partition to a static one. I am indeed already using a static partition, although it might be another related issue.

Here is the output of `west build -t partition_manager_report`

  external_flash (0x80000 - 512kB):
+------------------------------------------+
| 0x0: external_flash (0x80000 - 512kB)    |
| 0x0: mcuboot_secondary (0x6e000 - 440kB) |
+------------------------------------------+

  flash_primary (0x80000 - 512kB):
+--------------------------------------------------+
| 0x0: mcuboot (0x12000 - 72kB)                    |
+---0x12000: mcuboot_primary (0x6e000 - 440kB)-----+
| 0x12000: mcuboot_pad (0x200 - 512B)              |
+---0x12200: mcuboot_primary_app (0x6de00 - 439kB)-+
| 0x12200: app (0x6de00 - 439kB)                   |
+--------------------------------------------------+

  sram_primary (0x20000 - 128kB):
+--------------------------------------------+
| 0x20000000: sram_primary (0x20000 - 128kB) |
+--------------------------------------------+

and here's the full `pm_static.yml`

mcuboot:
  address: 0x0
  end_address: 0x12000
  placement:
    before:
    - mcuboot_primary
  region: flash_primary
  size: 0x12000
app:
  address: 0x12200
  end_address: 0x80000
  region: flash_primary
  size: 0x6de00
mcuboot_pad:
  address: 0x12000
  end_address: 0x12200
  region: flash_primary
  size: 0x200
mcuboot_primary:
  address: 0x12000
  end_address: 0x80000
  orig_span: &id001
  - mcuboot_pad
  region: flash_primary
  sharers: 0x1
  size: 0x6e000
  span: *id001
mcuboot_primary_app:
  address: 0x12200
  end_address: 0x80000
  orig_span: &id002
  - app
  region: flash_primary
  size: 0x6de00
  span: *id002
sram_primary:
  address: 0x20000000
  end_address: 0x20020000
  region: sram_primary
  size: 0x20000
external_flash:
  address: 0x0
  region: external_flash
  size: 0x80000
  device: AT25X
mcuboot_secondary:
  address: 0x0
  region: external_flash
  device: AT25X
  size: 0x6e000

Here are the mcuboot configs that we are using

CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD=6000
CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_MAX_SKIP=20
CONFIG_MAIN_STACK_SIZE=10240

CONFIG_FLASH=y
CONFIG_SPI=y

CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
CONFIG_BOOT_SIGNATURE_KEY_FILE="@MCUBOOT_KEY_FILE@"
CONFIG_CLOCK_CONTROL_NRF=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y

CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y
CONFIG_REBOOT=y
CONFIG_MULTITHREADING=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_SPI_NOR_IDLE_IN_DPD=y
CONFIG_PM=n
CONFIG_PM_DEVICE=y

CONFIG_CPP=y
CONFIG_STD_CPP20=y

CONFIG_RTT_CONSOLE=n

CONFIG_LOG_MODE_MINIMAL=n
CONFIG_CONSOLE=y
CONFIG_LOG_PRINTK=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_BACKEND_UART=n
CONFIG_DEBUG=y


CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y # former CONFIG_MODE_MINIMAL
### Ensure Zephyr logging changes don't use more resources
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_THREAD_NAME=y
### Decrease footprint by ~4 KB in comparison to CBPRINTF_COMPLETE=y
CONFIG_CBPRINTF_NANO=y

CONFIG_BOOT_UPGRADE_ONLY=n

CONFIG_DISABLE_FLASH_PATCH=y
CONFIG_BOOT_BOOTSTRAP=n
CONFIG_FPROTECT=n
CONFIG_BOOT_SWAP_SAVE_ENCTLV=n
CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h"

It is configured using CMake and added like so:

set(mcuboot_CONF_FILE
	${gen_dir}/mcuboot.conf
)

Parents
  • Hi,

    I believe that what's causing the issue is an incorrect static partitioning map. In your case both MCUboot_secondary and external flash starts at 0x0 in your case, while from the sample below it is defined differently: Do note that the sample uses dynamic partitioning and is set up for the nRF52840, but similarly you could set this up for the nRF52833 (albeit with only 512kB of flash).

      external_flash (0x800000 - 8192kB):
    +---------------------------------------------+
    | 0x0: mcuboot_secondary (0xf0000 - 960kB)    |
    | 0xf0000: external_flash (0x710000 - 7232kB) |
    +---------------------------------------------+
    
      flash_primary (0x100000 - 1024kB):
    +--------------------------------------------------+
    | 0x0: mcuboot (0x10000 - 64kB)                    |
    +---0x10000: mcuboot_primary (0xf0000 - 960kB)-----+
    | 0x10000: mcuboot_pad (0x200 - 512B)              |
    +---0x10200: mcuboot_primary_app (0xefe00 - 959kB)-+
    | 0x10200: app (0xefe00 - 959kB)                   |
    +--------------------------------------------------+
    
      sram_primary (0x40000 - 256kB):
    +--------------------------------------------+
    | 0x20000000: sram_primary (0x40000 - 256kB) |
    +--------------------------------------------+

    In general what I typically do (and recommend to customers) is to develop everything with a dynamic partitioning (up until where you need to do static) and, then copy the generated dynamic partition into their static partition and tweak where you need.

    I do also note that you MCUBoot bootloader slot is 72kB, which is quite large (default in our samples is 48kB, and you can get minimal configurations down to 21kB), so in case you wish to do other optimizations w.r.t flash I recommend you to have a look at https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/test_and_optimize/optimizing/index.html and https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/end_product/bootloader.html#mcuboot_minimal_configuration 

    Let me know if resolving the static partition map fixes the issue

    Kind regards,
    Andreas

Reply
  • Hi,

    I believe that what's causing the issue is an incorrect static partitioning map. In your case both MCUboot_secondary and external flash starts at 0x0 in your case, while from the sample below it is defined differently: Do note that the sample uses dynamic partitioning and is set up for the nRF52840, but similarly you could set this up for the nRF52833 (albeit with only 512kB of flash).

      external_flash (0x800000 - 8192kB):
    +---------------------------------------------+
    | 0x0: mcuboot_secondary (0xf0000 - 960kB)    |
    | 0xf0000: external_flash (0x710000 - 7232kB) |
    +---------------------------------------------+
    
      flash_primary (0x100000 - 1024kB):
    +--------------------------------------------------+
    | 0x0: mcuboot (0x10000 - 64kB)                    |
    +---0x10000: mcuboot_primary (0xf0000 - 960kB)-----+
    | 0x10000: mcuboot_pad (0x200 - 512B)              |
    +---0x10200: mcuboot_primary_app (0xefe00 - 959kB)-+
    | 0x10200: app (0xefe00 - 959kB)                   |
    +--------------------------------------------------+
    
      sram_primary (0x40000 - 256kB):
    +--------------------------------------------+
    | 0x20000000: sram_primary (0x40000 - 256kB) |
    +--------------------------------------------+

    In general what I typically do (and recommend to customers) is to develop everything with a dynamic partitioning (up until where you need to do static) and, then copy the generated dynamic partition into their static partition and tweak where you need.

    I do also note that you MCUBoot bootloader slot is 72kB, which is quite large (default in our samples is 48kB, and you can get minimal configurations down to 21kB), so in case you wish to do other optimizations w.r.t flash I recommend you to have a look at https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/test_and_optimize/optimizing/index.html and https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/protocols/matter/end_product/bootloader.html#mcuboot_minimal_configuration 

    Let me know if resolving the static partition map fixes the issue

    Kind regards,
    Andreas

Children
  • Hello, Thanks for the quick reply.

    Using dynamic partitioning is a good suggestion. When I switch to it (by removing `pm_static.yml`) the application no longer compiles because the flash region is overrun. It looks like it's no longer using the external flash chip. Unfortunately, I'm not the one who original set up this project, so I'm not totally familiar with how the external flash is set up. I know we had to write custom zephyr drivers for it though.

    Which sample are you referring to that has that partition map? That might be a good reference to see how dynamic partitioning works with the external flash.

  • Actually it does look like the external flash is being detected using dynamic partitioning. The flash region for mcuboot is being overflowed because the dynamic partitioner chose 48K for the mcuboot partition, but that is too small I believe because we need to compile in our drivers for the external flash chip.

  • Hi Andreas,

    I increased the size of the mcuboot partition to 56K and it was able to create the dynamic partition and compile successfully. Unfortunately, that did not solve the issue. There are exactly the same symptoms as before. It boots into the new image, but cannot confirm it.

    Here is what the new partition looks like:

      external_flash (0x80000 - 512kB):
    +------------------------------------------+
    | 0x0: mcuboot_secondary (0x72000 - 456kB) |
    | 0x72000: external_flash (0xe000 - 56kB)  |
    +------------------------------------------+
    
      flash_primary (0x80000 - 512kB):
    +-------------------------------------------------+
    | 0x0: mcuboot (0xe000 - 56kB)                    |
    +---0xe000: mcuboot_primary (0x72000 - 456kB)-----+
    | 0xe000: mcuboot_pad (0x200 - 512B)              |
    +---0xe200: mcuboot_primary_app (0x71e00 - 455kB)-+
    | 0xe200: app (0x71e00 - 455kB)                   |
    +-------------------------------------------------+
    
      sram_primary (0x20000 - 128kB):
    +--------------------------------------------+
    | 0x20000000: sram_primary (0x20000 - 128kB) |
    +--------------------------------------------+

    and the pm_static.yml:

    app:
      address: 0xe200
      end_address: 0x80000
      region: flash_primary
      size: 0x7e100
    external_flash:
      address: 0x72000
      end_address: 0x80000
      region: external_flash
      size: 0xe000
    mcuboot:
      address: 0x0
      end_address: 0xe000
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0xe000
    mcuboot_pad:
      address: 0xe000
      end_address: 0xe200
      placement:
        align:
          start: 0x1000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    mcuboot_primary:
      address: 0xe000
      end_address: 0x80000
      orig_span: &id001
      - mcuboot_pad
      - app
      region: flash_primary
      size: 0x72000
      span: *id001
    mcuboot_primary_app:
      address: 0xe200
      end_address: 0x80000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0x71e00
      span: *id002
    mcuboot_secondary:
      address: 0x0
      device: DT_CHOSEN(nordic_pm_ext_flash)
      end_address: 0x72000
      placement:
        align:
          start: 0x4
      region: external_flash
      share_size:
      - mcuboot_primary
      size: 0x72000
    sram_primary:
      address: 0x20000000
      end_address: 0x20020000
      region: sram_primary
      size: 0x20000
    

  • Hi,

    alexdr5398 said:
    Which sample are you referring to that has that partition map? That might be a good reference to see how dynamic partitioning works with the external flash.

    The sample is a generic BLE SMP sample using SPI over BLE that you can find here https://github.com/aHaugl/samples_for_NCS/tree/main/bootloader/SPI_samples/smp_ble_feat_spi (disclaimer: this is an unofficial sample that I've made, so it is not tested similarly to the official SDK samples)

    alexdr5398 said:
    The flash region for mcuboot is being overflowed because the dynamic partitioner chose 48K for the mcuboot partition, but that is too small I believe because we need to compile in our drivers for the external flash chip.

    Ah, then I understand the reason for why the MCUboot partition size is set larger than our default 48kB selected by the dynamic partitioner.

    I am using the dfu target api for the firmware image and the mcuboot image control api to confirm the image. The function ` boot_write_img_confirmed` returns 0 which supposedly means that it was successful, however reading the `mcuboot_swap_type` function still returns `revert` and the next time the chip is reset, it reverts to the old image.

    From what I can see from the API documentation you refer to I agree. boot_write_img_confirmed returning 0 should mark the image as "good to go" after the upgrade, leading me to believe that there is something in the DFU-target that reverts the image. Are you able to track down where and when the REVERT flag gets set into mcuboot_swap_type? 

    Kind regards,
    Andreas

  • There is nothing in our firmware that could be setting the flag after it boots into the new image. The only dfu target or mcuboot api calls after it boots into the new image are simply checking if the image is confirmed and reading the swap type.

    I have also tried using `boot_request_upgrade(BOOT_UPGRADE_PERMANENT)` rather than `boot_request_upgrade(BOOT_UPGRADE_TEST)` and the image still does not get confirmed and will revert upon the next reset.

    I have also noticed that after an OTA update was attempted, subsequent `west flash` will also result in an image that is not confirmed. `west flash --recover` will fix it and result in image that is confirmed with a swap time of `none`

    It seems to me like there are issues with our custom flash drivers? Since I know this API does work on other projects with an external flash chip.

Related