I struggled to host MCUBoot's secondary image on the external Flash of the nRF5340DK. I hit so many obstacles along the way that I'm pretty sure I went off track early on and didn't do this properly. First I followed these guidelines and added a device tree overlay:
/ { chosen { nordic,pm-ext-flash = &mx25r64; }; };
and made sure it also applied to MCUBoot (cmake from application):
set(mcuboot_DTC_OVERLAY_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${BOARD}.overlay")
But at runtime, MCUBoot complained about BOOT_MAX_IMG_SECTORS:
W: Failed reading sectors; BOOT_MAX_IMG_SECTORS=128 - too small?
where I assume that 128 matches the number of sectors of the primary partition when the external Flash isn't use. So I doubled it :
set(mcuboot_CONFIG_BOOT_MAX_IMG_SECTORS 256)
even if I would have expected that CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY (defined in prj.conf) would take care of that. Next, MCUBoot complained about an incompatible amount of sectors. As a matter of fact, the generated static partitions (build/partitions.yml) defined the size of mcuboot_secondary as 0. So I also took care of that by redefining the static partitions and matching the size of the mcuboot_secondary to mcuboot_primary:
set(PM_STATIC_YML_FILE ${CMAKE_CURRENT_SOURCE_DIR}/partitions.yml )
app: address: 0xc200 end_address: 0xfe000 region: flash_primary size: 0xf1e00 external_flash: address: 0x0 end_address: 0x800000 region: external_flash size: 0x800000 mcuboot: address: 0x0 end_address: 0xc000 placement: before: - mcuboot_primary region: flash_primary size: 0xc000 mcuboot_pad: address: 0xc000 end_address: 0xc200 placement: align: start: 0x4000 before: - mcuboot_primary_app region: flash_primary size: 0x200 mcuboot_primary: address: 0xc000 end_address: 0xfe000 orig_span: &id001 - app - mcuboot_pad region: flash_primary size: 0xf2000 span: *id001 mcuboot_primary_app: address: 0xc200 end_address: 0xfe000 orig_span: &id002 - app region: flash_primary size: 0xf1e00 span: *id002 mcuboot_secondary: address: 0x0 device: MX25R64 end_address: 0xf2000 placement: align: start: 0x4 region: external_flash size: 0xf2000 otp: address: 0xff8100 end_address: 0xff83fc region: otp size: 0x2fc pcd_sram: address: 0x2007e000 end_address: 0x20080000 placement: before: - end region: sram_primary size: 0x2000 settings_storage: address: 0xfe000 end_address: 0x100000 placement: before: - end region: flash_primary size: 0x2000 sram_primary: address: 0x20000000 end_address: 0x2007e000 region: sram_primary size: 0x7e000
For there, things went smoothly up until the point where boot_request_upgrade is called (either directly or from DFU API). I dug a little deeper and found that it fails attempting to write the boot magic number. Unlike the chunks of firmware updates, the magic number is not hosted in RAM, but in the internal Flash program memory (variable defined as const) and write_from_nvmc instead of nrfx_qspi_write is called. Quite frankly I didn't bother to check why, but write_from_nvmc returns an error that translates to EINVAL (Invalid argument). I just went ahead and changed MCUBoot to :
int boot_write_magic(const struct flash_area *fap) { uint32_t off; int rc; static uint32_t lBootMagic[] = { 0xf395c277, 0x7fefd260, 0x0f505235, 0x8079b62c, }; off = boot_magic_off(fap); printk("writing magic; fa_id=%d off=0x%lx (0x%lx), size=%d, total size=%d vs %d\n\n", fap->fa_id, (unsigned long)off, (unsigned long)(fap->fa_off + off), BOOT_MAGIC_SZ, fap->fa_size,off+BOOT_MAGIC_SZ); rc = flash_area_write(fap, off, lBootMagic, BOOT_MAGIC_SZ); if (rc != 0) { printk("flash_area_write failed with error code %d\n\n", rc); return BOOT_EFLASH; } return 0; }
and I finally managed successfully upgrade the system using a secondary image hosted on the external Flash. But I had to change MCUBoot to do so. Is this a bug, or did I simply went off track somewhere? Thanks.