I’m working on an nRF52832-based project using the Nordic SDK (v3.5.99-ncs1-1) and MCUboot for OTA updates. I have a 512KB internal flash and 4MB external SPI flash (P25Q32H) configured. Partition Manager is enabled, and I’m using both internal and external flash for primary and secondary image storage. However, upon booting, I consistently get the following error message:
*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
Attempting to boot slot 0.
No fw_info struct found.
Attempting to boot slot 1.
No fw_info struct found.
No bootable image found. Aborting boot.
It seems that MCUboot is unable to find a valid firmware image in either slot. Below are the details of my partition setup and configuration:
DTS File
// Copyright (c) 2024 Nordic Semiconductor ASA // SPDX-License-Identifier: Apache-2.0 /dts-v1/; #include <nordic/nrf52832_qfaa.dtsi> #include "fde_x2-pinctrl.dtsi" / { model = "FDE_x2"; compatible = "sollatek,fde-x2"; chosen { zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &boot_partition; zephyr,shell-uart = &uart0; zephyr,gpio = &gpio0; zephyr,console = &uart0; zephyr,uart-mcumgr = &uart0; nordic,pm-ext-flash = &dev_spi_flash; }; zephyr,user { modem_pwrkey-gpios = <&gpio0 12 0>; modem_pwr_en-gpios = <&gpio0 25 0>; modem_reset-gpios = <&gpio0 11 0>; acc_int1-gpios = <&gpio0 30 0>; acc_cs-gpios = <&gpio0 31 0>; uart0_wifi = <&uart0_wifi>; uart0_stm = <&uart0_stm>; uart0_gsm = <&uart0_gsm>; uart0_default = <&uart0_default>; io-channels = <&adc 5>; power_detect-gpios = <&gpio0 28 0>; wifi_pwr_en-gpios = <&gpio0 2 0>; }; aliases { spi0dev = &spi0; watchdog0 = &wdt; rtc2dev = &rtc2; spi-flash0 = &dev_spi_flash; }; }; &uart0 { compatible = "nordic,nrf-uarte"; status = "okay"; current-speed = <115200>; label = "UART_0"; pinctrl-0 = <&uart0_default>; pinctrl-names = "default"; }; &gpio0 { status = "okay"; gpiote-instance = <&gpiote>; }; &gpiote { status = "okay"; }; &spi0 { compatible = "nordic,nrf-spi"; status = "okay"; pinctrl-0 = <&spi0_default_alt>; pinctrl-1 = <&spi0_sleep_alt>; pinctrl-names = "default", "sleep"; cs-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>, <&gpio0 31 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; label = "DEV_SPI0"; dev_spi_flash: dev_spi_flash@0 { compatible = "jedec,spi-nor"; reg = <0>; label = "DEV_SPI_FLASH"; status = "okay"; jedec-id = [ 85 60 16 ]; //P25Q32H size = <(1048576 * 8 * 4)>;//4MB spi-max-frequency = <8000000>; }; }; &rtc2 { status = "okay"; }; &systick { status = "disabled"; }; &adc { status = "okay"; #address-cells = <1>; #size-cells = <0>; channel@5 { reg = <5>; zephyr,gain = "ADC_GAIN_1_6"; zephyr,reference = "ADC_REF_INTERNAL"; zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>; zephyr,input-positive = <NRF_SAADC_AIN5>; zephyr,resolution = <8>; zephyr,oversampling = <8>; }; }; &flash0 { partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; boot_partition: partition@8200 { label = "mcuboot"; reg = <0x8200 0x10000>; }; slot0_partition: partition@2a000 { label = "image-0"; reg = <0x2a000 0x56000>; }; }; }; &dev_spi_flash { partitions { compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; slot1_partition: partition@0 { label = "image-1"; reg = <0x00 0x56000>; }; }; };
pm_static.yml
EMPTY_0: address: 0x18200 end_address: 0x19000 placement: before: - s1_pad region: flash_primary size: 0xe00 EMPTY_1: address: 0x29200 end_address: 0x2a000 placement: before: - mcuboot_pad region: flash_primary size: 0xe00 app: address: 0x2a200 end_address: 0x80000 region: flash_primary size: 0x55e00 app_image: address: 0x2a200 end_address: 0x80000 orig_span: &id001 - app region: flash_primary size: 0x55e00 span: *id001 b0: address: 0x0 end_address: 0x7000 placement: after: - start region: flash_primary size: 0x7000 b0_container: address: 0x0 end_address: 0x8000 orig_span: &id002 - b0 - provision region: flash_primary size: 0x8000 span: *id002 external_flash_storage: address: 0x5E000 end_address: 0x400000 region: external_flash size: 0x3A2000 external_flash_params: address: 0x56000 end_address: 0x5E000 region: external_flash size: 0x8000 external_flash_ota: address: 0x00 end_address: 0x56000 region: external_flash size: 0x56000 mcuboot: address: 0x8200 end_address: 0x18200 placement: before: - mcuboot_primary region: flash_primary sharers: 0x1 size: 0x10000 mcuboot_pad: address: 0x2a000 end_address: 0x2a200 placement: align: start: 0x1000 before: - mcuboot_primary_app region: flash_primary sharers: 0x2 size: 0x200 mcuboot_primary: address: 0x2a000 end_address: 0x80000 orig_span: &id003 - mcuboot_pad - app region: flash_primary size: 0x56000 span: *id003 mcuboot_primary_app: address: 0x2a200 end_address: 0x80000 orig_span: &id004 - app region: flash_primary size: 0x55e00 span: *id004 mcuboot_secondary: address: 0x0 device: DT_CHOSEN(DEV_SPI_FLASH) end_address: 0x56000 placement: align: start: 0x4 region: external_flash share_size: - mcuboot_primary size: 0x56000 provision: address: 0x7000 end_address: 0x8000 placement: after: - b0 align: start: 0x1000 region: flash_primary size: 0x1000 s0: address: 0x8000 end_address: 0x18200 orig_span: &id005 - s0_pad - mcuboot region: flash_primary size: 0x10200 span: *id005 s0_image: address: 0x8200 end_address: 0x18200 orig_span: &id006 - mcuboot region: flash_primary size: 0x10000 span: *id006 s0_pad: address: 0x8000 end_address: 0x8200 placement: after: - b0_container align: start: 0x1000 region: flash_primary share_size: - mcuboot_pad size: 0x200 s1: address: 0x19000 end_address: 0x29200 orig_span: &id007 - s1_pad - s1_image region: flash_primary size: 0x10200 span: *id007 s1_image: address: 0x19200 end_address: 0x29200 placement: after: - s1_pad - s0 region: flash_primary share_size: - mcuboot size: 0x10000 s1_pad: address: 0x19000 end_address: 0x19200 placement: after: - s0 align: start: 0x1000 region: flash_primary share_size: - mcuboot_pad size: 0x200 sram_primary: address: 0x20000000 end_address: 0x20010000 region: sram_primary size: 0x10000
prj.conf
# Configure Cosnsole (Debug) CONFIG_CONSOLE=y CONFIG_UART_CONSOLE=n CONFIG_RTT_CONSOLE=y CONFIG_USE_SEGGER_RTT=y CONFIG_SEGGER_RTT_BUFFER_SIZE_DOWN=128 # Configure Internal Clock CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y # NFC pins as GPIOs CONFIG_NFCT_PINS_AS_GPIOS=y # MCUBOOT and DFU CONFIG_BOOTLOADER_MCUBOOT=y CONFIG_DFU_TARGET_MCUBOOT=y CONFIG_STREAM_FLASH=y CONFIG_STREAM_FLASH_ERASE=y CONFIG_DFU_TARGET=y CONFIG_DFU_TARGET_STREAM=y CONFIG_SECURE_BOOT=y CONFIG_IMG_MANAGER=y CONFIG_IMG_ERASE_PROGRESSIVELY=y CONFIG_MCUBOOT_IMG_MANAGER=y # Configure Watchdog CONFIG_WATCHDOG=y CONFIG_WDT_DISABLE_AT_BOOT=n # Configure UART CONFIG_SERIAL=y CONFIG_UART_USE_RUNTIME_CONFIGURE=y # Configure GPIO CONFIG_GPIO=y # Configure SPI CONFIG_SPI=y # Configure GPIO CONFIG_GPIO_AS_PINRESET=n CONFIG_PINCTRL=y CONFIG_PINCTRL_DYNAMIC=y # Configure RTC CONFIG_COUNTER=y # Configure ADC CONFIG_ADC=y # Main Thread Stack Size CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_MAIN_STACK_SIZE=8192 # Debug CONFIG_PARAM_SYSTEM_LOG=y CONFIG_PARAM_MODEM_LOG=n CONFIG_PARAM_GWC_LOG=n CONFIG_PARAM_STM_LOG=n # Enable HW INFO CONFIG_HWINFO=y # BLE CONFIG_BT=y # BLE Central CONFIG_BT_CENTRAL=y CONFIG_BT_SMP=y CONFIG_BT_GATT_CLIENT=y # Enable the BLE Central modules from NCS CONFIG_BT_SCAN=y CONFIG_BT_SCAN_FILTER_ENABLE=y CONFIG_BT_SCAN_ADDRESS_CNT=1 CONFIG_BT_GATT_DM=y # BLE Peripheral CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="FDE" CONFIG_BT_MAX_CONN=2 CONFIG_BT_MAX_PAIRED=2 CONFIG_BT_DEVICE_NAME_DYNAMIC=y CONFIG_BT_DEVICE_NAME_MAX=65 # SPI Flash CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_MPU_ALLOW_FLASH_WRITE=y CONFIG_SPI_ASYNC=y CONFIG_SPI_NOR=y CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 # Firmware Version CONFIG_APP_HW_VERSION_MAJOR=1 CONFIG_APP_FW_VERSION_MAJOR=6 CONFIG_FW_INFO=y
mcuboot.conf
# SPI and Flash CONFIG_SPI=y CONFIG_SPI_NOR=y CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 # Multithreading CONFIG_MULTITHREADING=y #MCU BOOT CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y CONFIG_BOOT_SIGNATURE_KEY_FILE="./certs/mcuboot_pkey.pem" CONFIG_BOOT_MAX_IMG_SECTORS=128 CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x10000 # Configure Internal Clock CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y # NFC pins as GPIOs CONFIG_NFCT_PINS_AS_GPIOS=y
What I’ve Tried So Far:
- I’ve ensured that the partition sizes between the internal and external flash for slot 0 and slot 1 are the same (448KB).
- The external SPI flash is properly configured and recognized in the device tree (
jedec,spi-nor
compatible). - Partition Manager seems to generate the correct memory map, and I have verified this by inspecting
build/zephyr/pm.yml
. - I am able to flash the primary image (
image_0_partition
) using thewest flash
command, but the bootloader still cannot detect any valid firmware in either slot.
My Questions:
- What could be causing the bootloader to not find the
fw_info
struct in either slot 0 or slot 1? - Is there any additional configuration required to ensure that the
fw_info
is properly embedded in the image so that MCUboot can detect it? - Do I need any specific settings in the
prj.conf
file to make sure the bootloader can correctly identify and boot from the internal or external flash? - Is there a recommended way to debug and confirm whether the firmware image is being properly written and contains the expected metadata?
Any help or guidance would be greatly appreciated!
Additional Info:
- Chip: nRF52832 (512KB internal flash, 64KB SRAM)
- SDK Version: 2.6.1
- External Flash: P25Q32H (4MB SPI NOR flash)
- MCUboot: Enabled via Partition Manager
- Toolchain: Zephyr with
west
build system
Thank you for your assistance!