No Bootable Image Found: "No fw_info struct found" Error on nRF52832 with Partition Manager and MCUboot

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 the west flash command, but the bootloader still cannot detect any valid firmware in either slot.

Here’s a detailed question that you can post on the Nordic DevZone forum. It includes the necessary context and details about your setup and the issue you're facing:


Title:

No Bootable Image Found: "No fw_info struct found" Error on nRF52832 with Partition Manager and MCUboot


Question:

Description of the Issue:

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:

arduino
Copy code
*** 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:


Partition Manager Configuration (pm_static.yml):

yaml
Copy code
# Internal Flash Partitions mcuboot_partition: address: 0x00000000 size: 0x8000 # 32KB for mcuboot image_0_partition: address: 0x00008000 size: 0x70000 # 448KB for primary image in internal flash scratch_partition: address: 0x00078000 size: 0x8000 # 32KB for scratch in internal flash # External Flash Partitions mcuboot_secondary: address: 0x0000 # External flash size: 0x70000 # 448KB for secondary image storage (slot 1) external_flash_ota: address: 0x70000 # External flash size: 0xb0000 # 704KB for OTA update storage external_flash_params: address: 0x120000 # External flash size: 0x8000 # 32KB for non-volatile parameter storage external_flash_storage: address: 0x128000 # External flash size: 0x2d8000 # ~2.9MB for storage/logging # SRAM Region sram_primary: address: 0x20000000 size: 0x10000 # 64KB for SRAM

Device Tree (.dts) Setup for SPI Flash:

dts
Copy code
&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 = <0x400000>; // 4MB external flash spi-max-frequency = <8000000>; }; };

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 the west flash command, but the bootloader still cannot detect any valid firmware in either slot.

My Questions:

  1. What could be causing the bootloader to not find the fw_info struct in either slot 0 or slot 1?
  2. Is there any additional configuration required to ensure that the fw_info is properly embedded in the image so that MCUboot can detect it?
  3. 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?
  4. 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!

Related