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.

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!

  • Hello,

    How did you flash your device? Does the output from this action indicate that there were any issues?

    Can you please try to read back the flash from the nRF52832 using the nRF Command Line Tools command:

    nrfjprog --readcode my_flash_readout.hex

    And compare this to what you program. Feel free to upload your build folder (or at least the .hex files from it) and the readback hex file if you want me to have a look. 

    Also, can you try to add some lines to ncs\nrf\samples\bootloader\src:

        uint32_t s0_addr = s0_address_read();
    	uint32_t s1_addr = s1_address_read();
    	
    	printk("s0_addr: %08x\n", s0_addr);
    	printk("s1_addr: %08x\n", s1_addr);
    	
    	const struct fw_info *s0_info = fw_info_find(s0_addr);
    	const struct fw_info *s1_info = fw_info_find(s1_addr);
    
    	if (!s1_info || (s0_info->version >= s1_info->version)) {
    		validate_and_boot(s0_info, BOOT_SLOT_0);
    		validate_and_boot(s1_info, BOOT_SLOT_1);
    	} else {
    		validate_and_boot(s1_info, BOOT_SLOT_1);
    		validate_and_boot(s0_info, BOOT_SLOT_0);
    	}

    What address does it print for s0_addr and s1_addr?

    Best regards,

    Edvin

  • Also, can you provide the full build log?

    Best regards,

    Edvin

  • Hi Edvin,

    thanks for your answer. I managed to find the solution by debugging the bootload and understanding the memory addresses it tries to load. I have rebuild my partitions and its working fine now.

    Edvin, can you please validate if my settings are correct? What about the CONFIG_SECURE_BOOT=n, is it safe to leave it disabled? 


    Here are the working files in case someone else want to use a similar setup (NRF52832 + 32Mbit External SPI Flash + NCS 2.6.1)

    DTS File partitions

    &flash0 {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		boot_partition: partition@0 {
    			label = "mcuboot";
    			reg = <0x0000 0x10000>;
    		};
    
    		slot0_partition: partition@10000 {
    			label = "image-0";
    			reg = <0x10000 0x70000>;
    		};
    	};
    };
    
    &dev_spi_flash {
    	partitions {
    		compatible = "fixed-partitions";
    		#address-cells = <1>;
    		#size-cells = <1>;
    
    		slot1_partition: partition@0 {
    			label = "image-1";
    			reg = <0x0000 0x70000>;
    		};
    
    	
    	};
    };

    pm_static.yml

    app:
      address: 0x10200
      end_address: 0x80000
      region: flash_primary
      size: 0x6FE00
    
    mcuboot:
      address: 0x00
      end_address: 0x10000
      placement:
        before:
        - mcuboot_primary
      region: flash_primary
      size: 0x10000
    
    mcuboot_pad:
      address: 0x10000
      end_address: 0x10200
      placement:
        align:
          start: 0x1000
        before:
        - mcuboot_primary_app
      region: flash_primary
      size: 0x200
    
    mcuboot_primary:
      address: 0x10000
      end_address: 0x80000
      orig_span: &id001
      - app
      - mcuboot_pad
      region: flash_primary
      sharers: 0x1
      size: 0x70000
      span: *id001
    
    mcuboot_primary_app:
      address: 0x10200
      end_address: 0x80000
      orig_span: &id002
      - app
      region: flash_primary
      size: 0x6FE00
      span: *id002
    
    mcuboot_secondary:
      address: 0x0
      end_address: 0x70000
      device: DEV_SPI_FLASH
      region: external_flash
      size: 0x70000
    
    external_flash_ota:
      address: 0x0
      end_address: 0x70000
      region: external_flash
      size: 0x70000
    
    external_flash_params:
      address: 0x70000
      end_address: 0x78000
      region: external_flash
      size: 0x8000
    
    external_flash_storage:
      address: 0x78000
      end_address: 0x400000
      region: external_flash
      size: 0x388000
    
    sram_primary:
      address: 0x20000000
      region: sram_primary
      size: 0x10000
    

    Relative part on prj.conf

    # 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=n
    CONFIG_DFU_TARGET_LOG_LEVEL_INF=y
    CONFIG_IMG_MANAGER=y
    CONFIG_IMG_ERASE_PROGRESSIVELY=y
    CONFIG_MCUBOOT_IMG_MANAGER=y
    
    CONFIG_SETTINGS=y
    CONFIG_REBOOT=y

  • Hello,

    CONFIG_SECURE_BOOT=n means that you do not enable the first stage bootloader. Please see:
    https://docs.nordicsemi.com/bundle/ncs-latest/page/kconfig/index.html#CONFIG_SECURE_BOOT

    As you probably know, the normal bootloader, the MCUBOOT bootloader is in charge of updating the application (actually just to perform the swapping of the application. The transfer of the new application image happens in the application itself). The MCUBOOT bootloader can not, however, update itself. For this, we use the first stage bootloader, which is enabled by setting CONFIG_SECURE_BOOT=y. This is a small bootloader intended to update the MCUBOOT bootloader (but again, can not update itself).

    So the error message that you posted in the initial post was coming from the first stage bootloader, often referred to as NSIB. A colleague of mine, Sigurd, has a few demo samples showing the different parts of the bootloader(s):

    https://github.com/hellesvik-nordic/samples_for_nrf_connect_sdk/tree/main/bootloader_samples

    The "updateable bootloader" shows the first stage bootloader. The readme.MD file contains a few links to some documentation.

    It is absolutely possible to not use the first stage bootloader in a product, but should you at some time wish to for example change the bootloader keys, the you need to update the MCUBOOT bootloader, and for this, you need the first stage bootloader/NSIB.

    Best regards,

    Edvin

Related