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.