Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

Update Firmware (Bootloader and Application) from external flash

I am using the nRF52840-dk with the nRF Connect SDK v2.0.0 and for the development itself I use Visual Studio Code.

My Goal: Both the bootloader and the actual application should be upgradeable, with firmware updates stored on an external flash. Supposedly this should be possible.
The firmware is stored in the external flash via specially developed methods. Afterwards the bootloader should detect these firmware updates in the external flash and copy/swap them to the internal flash.


According to the documentation I need the nRF Secure Immutable Bootloader and MCUboot as a second stage bootloader.
This actual bootloader chain works fine so far even with my own private keys.

Currently I am getting the following output with my configuration:

*** Booting Zephyr OS build v3.0.99-ncs1  ***
Attempting to boot slot 0.
Attempting to boot from address 0x9200.
Verifying signature against key 0.
Hash: 0xea...6a
Firmware signature verified.
Firmware version 1
Setting monotonic counter (version: 1, slot: 0)
*** Booting Zephyr OS build v3.0.99-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=bad, swap_type=0x2, copy_done=0x2, image_ok=0x2
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: 0x23000
▒*** Booting Zephyr OS build v3.0.99-ncs1  ***
[00:0Bluetooth initialized

I do not understand the output of MCUboot at all. Why do two passes take place? Why is magic from the primary image suddenly bad on the second pass, but loads the firmware anyway?

I can change the version number of MCUboot. This is also shown correctly by the first bootloader.

But that's it. I can't get it to recognize the firmware updates.
MCUboot doesn't seem to make any attempt at all to read anything from the external flash. Well I don't know. The bootloader doesn't give any further relevant information, even if I adjust the log level.

For now, I'd be happy to at least have MCUboot upgradeable.

The following already works:
The firmware update is in the right position in the external flash. For testing purposes at offset 0x0.
As the firmware update for MCUboot I use the file "signed_by_b0_s0_image.bin" from the "build/zephyr" directory. If I open this binary
I see the first 0x200 bytes with some meta information. See here:

$ head --bytes=$((16#200)) signed_by_b0_s0_image.bin | xxd
00000000: c05d 0020 5dbc 0000 1907 0100 31bc 0000  .]. ].......1...
00000010: 31bc 0000 31bc 0000 31bc 0000 0000 0000  1...1...1.......
00000020: 0000 0000 0000 0000 0000 0000 69b7 0000  ............i...
00000030: 31bc 0000 0000 0000 15b7 0000 31bc 0000  1...........1...
00000040: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
00000050: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
00000060: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
00000070: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
00000080: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
00000090: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
000000a0: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
000000b0: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
000000c0: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
000000d0: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
000000e0: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
000000f0: 19b8 0000 19b8 0000 19b8 0000 19b8 0000  ................
00000100: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000130: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000140: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000150: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000160: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000170: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000180: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000190: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000001f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

My expectation would be: Since it is signed_by_b0_s0_image.bin, which is (presumably) a valid MCUboot firmware, the bootloader would have to output some message and validate the update or do something else. But I don't see anything of that.

Below I list the most important configurations I use. These are mainly for the current development.
And yes, due to days of desperate attempts, the configuration files are now very messy.

pm_static.yml (originally taken from a sample project - but couldn't even be built in the first place)

external_flash:
  address: 0x000000
  region: external_flash
  size: 0x0
  device: MX25R64

mcuboot_secondary:
  address: 0x00000
  device: MX25R64
  region: external_flash
  size: 0xdb000

rest_storage:
  address: 0xdb000
  size: 0x725000
  device: MX25R64
  region: external_flash

nrf52840dk_nrf52840.overlay:

/ {
	chosen {
		nordic,pm-ext-flash = &mx25r64;
	};
};

The generated partitions.yml:

EMPTY_0:
  address: 0x15200
  end_address: 0x16000
  placement:
    before:
    - s1_pad
  region: flash_primary
  size: 0xe00
EMPTY_1:
  address: 0x22200
  end_address: 0x23000
  placement:
    before:
    - mcuboot_pad
  region: flash_primary
  size: 0xe00
app:
  address: 0x23200
  end_address: 0xfe000
  region: flash_primary
  size: 0xdae00
app_image:
  address: 0x23200
  end_address: 0xfe000
  orig_span: &id001
  - app
  region: flash_primary
  size: 0xdae00
  span: *id001
b0:
  address: 0x0
  end_address: 0x8000
  placement:
    after:
    - start
  region: flash_primary
  size: 0x8000
b0_container:
  address: 0x0
  end_address: 0x9000
  orig_span: &id002
  - b0
  - provision
  region: flash_primary
  size: 0x9000
  span: *id002
external_flash:
  address: 0x0
  device: MX25R64
  end_address: 0x0
  region: external_flash
  size: 0x0
mcuboot:
  address: 0x9200
  end_address: 0x15200
  placement:
    before:
    - mcuboot_primary
  region: flash_primary
  sharers: 0x1
  size: 0xc000
mcuboot_pad:
  address: 0x23000
  end_address: 0x23200
  placement:
    align:
      start: 0x1000
    before:
    - mcuboot_primary_app
  region: flash_primary
  sharers: 0x2
  size: 0x200
mcuboot_primary:
  address: 0x23000
  end_address: 0xfe000
  orig_span: &id003
  - mcuboot_pad
  - app
  region: flash_primary
  size: 0xdb000
  span: *id003
mcuboot_primary_app:
  address: 0x23200
  end_address: 0xfe000
  orig_span: &id004
  - app
  region: flash_primary
  size: 0xdae00
  span: *id004
mcuboot_secondary:
  address: 0x0
  device: MX25R64
  end_address: 0xdb000
  region: external_flash
  size: 0xdb000
provision:
  address: 0x8000
  end_address: 0x9000
  placement:
    after:
    - b0
    align:
      start: 0x1000
  region: flash_primary
  size: 0x1000
rest_storage:
  address: 0xdb000
  device: MX25R64
  end_address: 0x800000
  region: external_flash
  size: 0x725000
s0:
  address: 0x9000
  end_address: 0x15200
  orig_span: &id005
  - mcuboot
  - s0_pad
  region: flash_primary
  size: 0xc200
  span: *id005
s0_image:
  address: 0x9200
  end_address: 0x15200
  orig_span: &id006
  - mcuboot
  region: flash_primary
  size: 0xc000
  span: *id006
s0_pad:
  address: 0x9000
  end_address: 0x9200
  placement:
    after:
    - b0_container
    align:
      start: 0x1000
  region: flash_primary
  share_size:
  - mcuboot_pad
  size: 0x200
s1:
  address: 0x16000
  end_address: 0x22200
  orig_span: &id007
  - s1_pad
  - s1_image
  region: flash_primary
  size: 0xc200
  span: *id007
s1_image:
  address: 0x16200
  end_address: 0x22200
  placement:
    after:
    - s1_pad
    - s0
  region: flash_primary
  share_size:
  - mcuboot
  size: 0xc000
s1_pad:
  address: 0x16000
  end_address: 0x16200
  placement:
    after:
    - s0
    align:
      start: 0x1000
  region: flash_primary
  share_size:
  - mcuboot_pad
  size: 0x200
settings_storage:
  address: 0xfe000
  end_address: 0x100000
  placement:
    before:
    - end
  region: flash_primary
  size: 0x2000
sram_primary:
  address: 0x20000000
  end_address: 0x20040000
  region: sram_primary
  size: 0x40000

prj.conf

CONFIG_NEWLIB_LIBC=y

CONFIG_CPLUSPLUS=y
CONFIG_STD_CPP2A=y
CONFIG_LIB_CPLUSPLUS=y
CONFIG_NEWLIB_LIBC_NANO=y
CONFIG_EXCEPTIONS=y

CONFIG_SENSOR=y
CONFIG_TEMP_NRF5=y
CONFIG_NRFX_TEMP=y

CONFIG_STDOUT_CONSOLE=y
CONFIG_FLASH=y
CONFIG_I2C=n
CONFIG_SPI=y
CONFIG_NORDIC_QSPI_NOR=y

CONFIG_SPI_SLAVE=n
CONFIG_SPI_NRFX=y
CONFIG_SPI_ASYNC=y
CONFIG_NRFX_SPIS0=y
CONFIG_GPIO=y
CONFIG_SPI_0_NRF_ORC=0x80

CONFIG_THREAD_STACK_INFO=y
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_BT_RX_STACK_SIZE=4096

CONFIG_BT_GATT_AUTO_SEC_REQ=n
CONFIG_BT=y
CONFIG_BT_SMP=y
CONFIG_BT_SIGNING=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_EXT_ADV=y
CONFIG_BT_PER_ADV=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_DEBUG_SMP=y
CONFIG_BT_DIS=y
CONFIG_BT_ATT_PREPARE_COUNT=5
CONFIG_BT_PRIVACY=n
CONFIG_BT_DEVICE_NAME="MyName"
CONFIG_BT_DEVICE_APPEARANCE=833
CONFIG_BT_DEVICE_NAME_DYNAMIC=y
CONFIG_BT_DEVICE_NAME_MAX=65
CONFIG_BT_SMP_ENFORCE_MITM=y
CONFIG_BT_GATT_DYNAMIC_DB=y
CONFIG_BT_BUF_ACL_RX_SIZE=517
CONFIG_BT_L2CAP_TX_MTU=517
CONFIG_BT_BUF_ACL_TX_SIZE=517
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
CONFIG_BT_SETTINGS=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y

CONFIG_LZ4=y
CONFIG_HEAP_MEM_POOL_SIZE=16384

CONFIG_SMF=y
CONFIG_DEBUG_THREAD_INFO=y
CONFIG_DEBUG_OPTIMIZATIONS=y
CONFIG_DEBUG_INFO=y

CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
CONFIG_BT_MAX_CONN=10

CONFIG_ASSERT=n

CONFIG_NORDIC_QSPI_NOR=y
CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16

CONFIG_STDOUT_CONSOLE=y

CONFIG_FPU=y
CONFIG_FPU_SHARING=y

CONFIG_DEBUG_THREAD_INFO=y
CONFIG_DEBUG_OPTIMIZATIONS=y
CONFIG_DEBUG_INFO=y

CONFIG_NRFX_NVMC=y
CONFIG_FW_INFO=y
CONFIG_FW_INFO_OFFSET=0x200

CONFIG_SECURE_BOOT=y
CONFIG_DISABLE_FLASH_PATCH=y

CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_MCUBOOT_IMAGE_VERSION="1.1.1+1"
CONFIG_SB_SIGNING_KEY_FILE="private.pem"
CONFIG_SB_SIGNING_PUBLIC_KEY="public.pem"

CONFIG_TIMING_FUNCTIONS=y
CONFIG_DISABLE_FLASH_PATCH=y

CONFIG_BOOT_BANNER=y

CONFIG_IMG_MANAGER=y
CONFIG_MCUBOOT_IMG_MANAGER=y

CONFIG_UPDATEABLE_IMAGE_NUMBER=1
CONFIG_PM_EXTERNAL_FLASH_BASE=0x0
CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y

CONFIG_DFU_TARGET_MCUBOOT=y

child_image/b0.conf:

CONFIG_IS_SECURE_BOOTLOADER=y
CONFIG_MULTITHREADING=n
CONFIG_GPIO=n
CONFIG_ARM_MPU=n
CONFIG_PM=n
CONFIG_TICKLESS_KERNEL=n
CONFIG_ERRNO=n
CONFIG_FPROTECT=y
CONFIG_SECURE_BOOT_CRYPTO=y
CONFIG_SECURE_BOOT_DEBUG=y
CONFIG_SECURE_BOOT_VALIDATION=y
CONFIG_SECURE_BOOT_STORAGE=y
CONFIG_BL_ROT_VERIFY_EXT_API_ENABLED=y
CONFIG_BL_SHA256_EXT_API_ENABLED=y
CONFIG_BL_SECP256R1_EXT_API_ENABLED=y
CONFIG_BL_VALIDATE_FW_EXT_API_ENABLED=y
CONFIG_EXT_API_PROVIDE_EXT_API_ENABLED=y
CONFIG_NRFX_NVMC=y
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_TIMEOUT_64BIT=n

CONFIG_ASSERT=n

CONFIG_NRF_RTC_TIMER=n

CONFIG_FW_INFO=y

CONFIG_PM_EXTERNAL_FLASH_BASE=0x0

child_image/mcuboot.conf:

CONFIG_PM=n

CONFIG_MAIN_STACK_SIZE=10240
CONFIG_MBEDTLS_CFG_FILE="mcuboot-mbedtls-cfg.h"

CONFIG_BOOT_SWAP_SAVE_ENCTLV=n
CONFIG_BOOT_ENCRYPT_RSA=n
CONFIG_BOOT_ENCRYPT_EC256=n
CONFIG_BOOT_ENCRYPT_X25519=n

CONFIG_BOOT_UPGRADE_ONLY=n 
CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=n 
CONFIG_BOOT_BOOTSTRAP=n

CONFIG_FLASH=y
CONFIG_FPROTECT=y

CONFIG_LOG=y
CONFIG_LOG_MODE_MINIMAL=y # former CONFIG_MODE_MINIMAL
CONFIG_LOG_DEFAULT_LEVEL=0
CONFIG_CBPRINTF_NANO=y
CONFIG_NRF_RTC_TIMER_USER_CHAN_COUNT=0

CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y

CONFIG_BOOT_NRF_EXTERNAL_CRYPTO=y
CONFIG_SECURE_BOOT_CRYPTO=y
CONFIG_SB_CRYPTO_CLIENT_ECDSA_SECP256R1=y
CONFIG_SB_CRYPTO_CLIENT_SHA256=y
CONFIG_BL_SHA256_EXT_API_REQUIRED=y
CONFIG_BL_SECP256R1_EXT_API_REQUIRED=y
CONFIG_EXT_API_PROVIDE_EXT_API_ATLEAST_OPTIONAL=y

CONFIG_BOOT_SIGNATURE_KEY_FILE="private.pem"

CONFIG_FW_INFO_FIRMWARE_VERSION=1

CONFIG_NORDIC_QSPI_NOR=y
CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE=16
CONFIG_MULTITHREADING=y
CONFIG_BOOT_MAX_IMG_SECTORS=256

CONFIG_IMG_MANAGER=y
CONFIG_UPDATEABLE_IMAGE_NUMBER=1
CONFIG_SIZE_OPTIMIZATIONS=y

CONFIG_PM_EXTERNAL_FLASH_BASE=0x0
CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y

CONFIG_DEBUG_INFO=y

CONFIG_BOOT_SWAP_USING_MOVE=y

CONFIG_DFU_TARGET=y
CONFIG_DEBUG=y

CONFIG_LOG_OVERRIDE_LEVEL=4

  • I'm not sure if updating mcuboot on the 52840 is supported, see https://devzone.nordicsemi.com/f/nordic-q-a/84007/does-mcuboot-have-a-mechanisms-to-update-the-bootloader-itself/350956#350956 

    However, I found this ticket:  Update mcuboot with SMP. In that ticket, it seems like my colleague was able to update MCUboot. Test the sample he linked to and see if you're able to do it. He also gives some pointers to some samples that supports putting the update in external flash.

    If this didn't help, please let me know and I'll take a closer look at it.

    Best regards,

    Simon

  • First of all, thanks for the reply. I have looked at the sample projects, continued to read through various posts and now have wasted another week with more attempts.

    I just don't get it at all.

    In the meantime I have managed to update mcuboot, but not the way I would like.
    It seems that mcuboot can only be "updated" via the internal flash, which in the Immutable Bootloader can be done simply
    by booting the image with the largest version.
    If this is the case, then I can live with that. I just have to develop my own routine, which copies the image from the external flash to the internal flash.

    For now I would declare the topic "updateable bootloader" as finished for me. Unless someone has additional information.

    But now I would like to attempt the application firmware update: This simply does not work at all. Even with a minimal project from the internal flash mcuboot refuses to do anyhing.

    For testing I copied the following small project: https://github.com/hellesvik-nordic/samples_for_nrf_connect_sdk/tree/main/bootloader_samples/nsib_mcuboot_smp

    Since this project cannot be built with nRF Connect SDK v.2.0.0, see my changes:

    diff --git a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/CMakeLists.txt b/nsib_mcuboot_smp/CMakeLists.txt
    index ecb7d24..9010aa2 100644
    --- a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/CMakeLists.txt
    +++ b/nsib_mcuboot_smp/CMakeLists.txt
    @@ -2,6 +2,10 @@
    
     cmake_minimum_required(VERSION 3.20.0)
    
    +set(mcuboot_CONF_FILE
    +   ${CMAKE_CURRENT_SOURCE_DIR}/child_image/mcuboot.conf
    +)
    +
     find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
     project(hello_world)
     
    diff --git a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/prj.conf b/nsib_mcuboot_smp/prj.conf
    index 4d50428..3e8e5eb 100644
    --- a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/prj.conf
    +++ b/nsib_mcuboot_smp/prj.conf
    @@ -1,13 +1,11 @@
    -CONFIG_BOOTLOADER_MCUBOOT=y
     CONFIG_MCUMGR=y
    -CONFIG_MCUMGR_SMP_UART=y
    -CONFIG_MCUMGR_CMD_IMG_MGMT=y
    +CONFIG_BOOTLOADER_MCUBOOT=y
    
     CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
     CONFIG_FLASH=y
    
     CONFIG_SECURE_BOOT=y
    -CONFIG_SB_SIGNING_KEY_FILE="nsib_priv.pem"
    +CONFIG_SB_SIGNING_KEY_FILE="private.pem"
     CONFIG_BUILD_S1_VARIANT=y
     # Need to lower the number of counter slots to be able to update several times. Do not know the best number yet.
     CONFIG_SB_NUM_VER_COUNTER_SLOTS=120
     
    diff --git a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/src/main.c b/nsib_mcuboot_smp/src/main.c
    index 1d885f2..39c9e4d 100644
    --- a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/src/main.c
    +++ b/nsib_mcuboot_smp/src/main.c
    @@ -6,10 +6,9 @@
    
     #include <zephyr.h>
     #include <sys/printk.h>
    -#include "img_mgmt/img_mgmt.h"
    
     void main(void)
     {
    -    img_mgmt_register_group();
    -       printk("Change this to see change\n");
    +       printk("Hello World! %s\n", CONFIG_BOARD);
    +       printk("My Version is %s\n", CONFIG_MCUBOOT_IMAGE_VERSION);
     }
     
    diff --git a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/child_image/mcuboot.conf b/nsib_mcuboot_smp/child_image/mcuboot.conf
    index 24ccbac..4d4ea08 100644
    --- a/samples_for_nrf_connect_sdk-main/bootloader_samples/nsib_mcuboot_smp/child_image/mcuboot.conf
    +++ b/nsib_mcuboot_smp/child_image/mcuboot.conf
    @@ -2,3 +2,6 @@ CONFIG_LOG=y
     CONFIG_LOG_MODE_MINIMAL=y
    
     CONFIG_FW_INFO_FIRMWARE_VERSION=5
    +
    +CONFIG_FLASH=y
    +CONFIG_MAIN_STACK_SIZE=10240
    \ No newline at end of file

    With these changes the project can be built finally.

    As you can read in various guides, after the initial build I put the build/partitions.yml file as pm_static.yml in the root directory.

    I get the following partition report:

      flash_primary (0x100000 - 1024kB):
    +--------------------------------------------------+
    +---0x0: b0_container (0x9000 - 36kB)--------------+
    | 0x0: b0 (0x8000 - 32kB)                          |
    | 0x8000: provision (0x1000 - 4kB)                 |
    +---0x9000: s0 (0xc200 - 48kB)---------------------+
    | 0x9000: s0_pad (0x200 - 512B)                    |
    +---0x9200: s0_image (0xc000 - 48kB)---------------+
    | 0x9200: mcuboot (0xc000 - 48kB)                  |
    +--------------------------------------------------+
    | 0x15200: EMPTY_0 (0xe00 - 3kB)                   |
    +---0x16000: s1 (0xc200 - 48kB)--------------------+
    | 0x16000: s1_pad (0x200 - 512B)                   |
    | 0x16200: s1_image (0xc000 - 48kB)                |
    +--------------------------------------------------+
    | 0x22200: EMPTY_1 (0xe00 - 3kB)                   |
    +---0x23000: mcuboot_primary (0x6e000 - 440kB)-----+
    | 0x23000: mcuboot_pad (0x200 - 512B)              |
    +---0x23200: app_image (0x6de00 - 439kB)-----------+
    +---0x23200: mcuboot_primary_app (0x6de00 - 439kB)-+
    | 0x23200: app (0x6de00 - 439kB)                   |
    +--------------------------------------------------+
    | 0x91000: mcuboot_secondary (0x6e000 - 440kB)     |
    | 0xff000: EMPTY_2 (0x1000 - 4kB)                  |
    +--------------------------------------------------+
    
      sram_primary (0x40000 - 256kB):
    +--------------------------------------------+
    | 0x20000000: sram_primary (0x40000 - 256kB) |
    +--------------------------------------------+

    If I flash the merged.hex after the initial build and restart the mcu, I get the following output:

    *** Booting Zephyr OS build v3.0.99-ncs1  ***
    Attempting to boot slot 0.
    Attempting to boot from address 0x9200.
    Verifying signature against key 0.
    Hash: 0xea...6a
    Firmware signature verified.
    Firmware version 5
    *** Booting Zephyr OS build v3.0.99-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: 0x23000
    *** Booting Zephyr OS build v3.0.99-ncs1  ***
    Hello World! nrf52840dk_nrf52840
    My Version is 1.1.1

    And again the question, what is mcuboot doing here? Why do the lines "Primary image" and "Secondary image" appear twice? Why is magic always unset?
    If I change CONFIG_MCUBOOT_IMAGE_VERSION in prj.conf of my application and build again, I get the file app_update.bin. I have read often enough that this should be the binary of my application for the update process. A look into the paritition table tells me that mcuboot_secondary starts at 0x91000.
    So for me this is the start address where the firmware has to be written in.
    Using my own Python script, I convert the .bin file to Intel Hex format with address offset 0x91000.

    Example:

    :020000040009F1
    :101000003DB8F3960000000000020000EC62000012
    :1010100000000000010105000000000000000000C9
    :10102000FFFFFFFFFFFFFFFFFFFFFFFFFFD0
    :10103000FFFFFFFFFFFFFFFFFFFFFFFFC0
    ...

    I flash this file successfully with nrfjprog.
    If I now reset the mcu, I get the following output:

    *** Booting Zephyr OS build v3.0.99-ncs1  ***
    Attempting to boot slot 0.
    Attempting to boot from address 0x9200.
    Verifying signature against key 0.
    Hash: 0xea...6a
    Firmware signature verified.
    Firmware version 5
    *** Booting Zephyr OS build v3.0.99-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: Bootloader chainload address offset: 0x23000
    *** Booting Zephyr OS build v3.0.99-ncs1  ***
    Hello World! nrf52840dk_nrf52840
    My Version is 1.1.1

    Notice that the output "I: Swap type: none" before "I: Bootloader chainload address offset: 0x23000" is suddenly missing. But otherwise there are no changes.

    So what am I doing wrong? Or is mcuboot no longer functional by now?

  • Hello, I didn't get time to read detailed through this whole message, but I'll just answer quick before I leave work today.

    Talisca said:

    But now I would like to attempt the application firmware update: This simply does not work at all. Even with a minimal project from the internal flash mcuboot refuses to do anyhing.

    For testing I copied the following small project: https://github.com/hellesvik-nordic/samples_for_nrf_connect_sdk/tree/main/bootloader_samples/nsib_mcuboot_smp

    It does not seem like this project was made to update the main application, only mcuboot. To update the main application, check out Add DFU support to your application. It was made for NCS v1.8.0, but I think it should work with NCS v2.0.0 as well.

    Let me know if that guide is not suficcient, and I will assist you tomorrow.

  • Hello Simon,

    I followed the instructions for DFU over Bluetooth and that works fine.


    Only my use case is quite different, in that I write the firmware with my own method into the flash. mcumgr, smp etc. is not used at all in our case.

    The firmware is in the right place, I have already checked that. When I debug mcuboot, I also see that it reads the header information correctly and also checks if both image slots are compatible.
    At the end in the function "boot_prepare_image_for_update" in loader.c the swap type is set to none and that's it.
    The macro "BOOT_IS_UPGRADE" checks only for BOOT_SWAP_TYPE_TEST, BOOT_SWAP_TYPE_REVERT and BOOT_SWAP_TYPE_PERM. This apparently makes mcuboot think that there is no upgrade and simply ignores the firmware. It's almost like you have to set another flag somewhere so that mcuboot knows about the upgrade.
    I don't have time to debug this extensively, so far I've already lost too much time because of this Disappointed

  • I have found the solution by chance.
    As already written, I had debugged mcuboot and had the assumption that you still have to somehow tell the bootloader that it is an upgrade.
    I found the confirmation at developer.nordicsemi.com/.../design.html

    Then I remembered that I had read in some articles that the application itself can confirm the swap with "boot_write_img_confirmed()". Somehow I had the suspicion that there must be a function to set the swap type. And indeed. All I needed for the last two weeks was a call to the function "boot_request_upgrade()" with "BOOT_UPGRADE_PERMANENT or BOOT_UPGRADE_TEST".

    But now I would like to know if there is any setting for the build process, so that this is set directly in the image trailer of the firmware? That would not only be very convinient in my eyes, but also a necessity. What would be the point of uploading a firmware that is not recognized as an upgrade by the bootloader? An uploaded firmware is always an upgrade in my use case.

Related