FOTA on nRF54LM20A DK using external flash + sQSPI

Hello,

I am currently trying to make an application that can do FOTA and store the secondary firmware image on an external flash using sQSPI. The project I started is based on the smp_svr sample using v3.2.3 of the SDK and v0.3.4 of the nRF54LM20A. I was able to get the default configuration of the project working as well as configuring it to use the external flash on the development kit, but I have been running into issues trying to configure it to use sQSPI.

The issue I have been facing is, after booting into the main app and connecting to the nRF DeviceManager app, when I try to upload a firmware package, it hangs on `__CSB(p_qspi->p_reg);` in `nrfxlib/softperipheral/sQSPI/src/nrf_sqspi.c`. This makes me think that the sQSPI/VPR isn't configured properly even though it initializes without errors

I have changed both the MCUBoot and the main application to use the following devicetree overlay configuration:

/*
 * Copyright (c) 2025 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */


/ {
	chosen {
		zephyr,code-partition = &slot0_partition;
		nordic,pm-ext-flash = &mx25r64;
	};
};

&pinctrl {
	sqspi_default: sqspi_default {
		group1 {
			psels = <NRF_PSEL(SDP_MSPI_SCK, 2, 1)>,
				<NRF_PSEL(SDP_MSPI_CS0, 2, 5)>,
				<NRF_PSEL(SDP_MSPI_DQ0, 2, 2)>;
			nordic,drive-mode = <NRF_DRIVE_E0E1>;
		};
		group2 {
			psels = <NRF_PSEL(SDP_MSPI_DQ1, 2, 4)>,
				<NRF_PSEL(SDP_MSPI_DQ2, 2, 3)>,
				<NRF_PSEL(SDP_MSPI_DQ3, 2, 0)>;
			nordic,drive-mode = <NRF_DRIVE_E0E1>;
			bias-pull-up;
		};
	};

	sqspi_sleep: sqspi_sleep {
		group1 {
			low-power-enable;
			psels = <NRF_PSEL(SDP_MSPI_SCK, 2, 1)>,
				<NRF_PSEL(SDP_MSPI_CS0, 2, 5)>,
				<NRF_PSEL(SDP_MSPI_DQ0, 2, 2)>,
				<NRF_PSEL(SDP_MSPI_DQ1, 2, 4)>,
				<NRF_PSEL(SDP_MSPI_DQ2, 2, 3)>,
				<NRF_PSEL(SDP_MSPI_DQ3, 2, 0)>;
		};
	};
};

&cpuflpr_vpr {
	pinctrl-0 = <&sqspi_default>;
	pinctrl-1 = <&sqspi_sleep>;
	pinctrl-names = "default", "sleep";
	interrupts = <76 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "okay";
};

/ {
	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		softperipheral_ram: memory@2007c000 {
			reg = <0x2007c000 0x4000>;
			ranges = <0 0x2007c000 0x4000>;
			#address-cells = <1>;
			#size-cells = <1>;

			sqspi: sqspi@3b40 {
				compatible = "nordic,nrf-sqspi";
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <0x3b40 0x200>;
				status = "okay";
				zephyr,pm-device-runtime-auto;
			};
		};
	};
};

/delete-node/ &mx25r64;

&sqspi {
	mx25r64: mx25r6435f@0 {
		compatible = "mxicy,mx25r", "jedec,mspi-nor";
		status = "okay";
		reg = <0>;
		jedec-id = [c2 28 17];
		quad-enable-requirements = "S1B6";
		sfdp-bfp = [
			e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb
			ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
			10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44
			30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff
		];
		size = <67108864>;
		has-dpd;
		t-enter-dpd = <10000>;
		t-exit-dpd = <35000>;
		t-reset-pulse = <10000>;
		t-reset-recovery = <35000>;

		mspi-max-frequency = <DT_FREQ_M(8)>;
		mspi-io-mode = "MSPI_IO_MODE_QUAD_1_4_4";
		mspi-data-rate = "MSPI_DATA_RATE_SINGLE";
		mspi-hardware-ce-num = <1>;
		mspi-cpp-mode = "MSPI_CPP_MODE_0";
		mspi-endian = "MSPI_BIG_ENDIAN";
		mspi-ce-polarity = "MSPI_CE_ACTIVE_LOW";
	};
};

I also ran into same issue that was decribed in this ticket so I added the following code in order to get the the sQSPI to initialize without error. The changes outlined in this ticket did not work for me. I'm curious if this is reasonable alternative to what is outlined in the second ticket I mentioned, or if there is a better solution I could be using

#include <zephyr/init.h>
#include <zephyr/kernel.h>

#if defined(CONFIG_SOC_SERIES_NRF54LX)

#include <hal/nrf_vpr.h>
#include <../../nrfxlib/softperipheral/include/softperipheral_regif.h>


static int sqspi_vpr_stop_init(void)
{
	/* Stop VPR*/
	nrf_vpr_cpurun_set(NRF_VPR, false);

	// Reset VPR.
	nrf_vpr_debugif_dmcontrol_mask_set(NRF_VPR,
		(VPR_DEBUGIF_DMCONTROL_NDMRESET_Active
			<< VPR_DEBUGIF_DMCONTROL_NDMRESET_Pos |
			VPR_DEBUGIF_DMCONTROL_DMACTIVE_Enabled
			<< VPR_DEBUGIF_DMCONTROL_DMACTIVE_Pos));
	nrf_vpr_debugif_dmcontrol_mask_set(NRF_VPR,
				(VPR_DEBUGIF_DMCONTROL_NDMRESET_Inactive
				<< VPR_DEBUGIF_DMCONTROL_NDMRESET_Pos |
				VPR_DEBUGIF_DMCONTROL_DMACTIVE_Disabled
				<< VPR_DEBUGIF_DMCONTROL_DMACTIVE_Pos));

	return 0;
}

SYS_INIT(sqspi_vpr_stop_init, POST_KERNEL, 0);

#endif /* CONFIG_SOC_SERIES_NRF54LX */

Additional config files:

prj.conf

# Enable MCUmgr and dependencies.
CONFIG_NET_BUF=y
CONFIG_ZCBOR=y
CONFIG_CRC=y
CONFIG_MCUMGR=y
CONFIG_STREAM_FLASH=y
CONFIG_FLASH_MAP=y

# Some command handlers require a large stack.
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
CONFIG_MAIN_STACK_SIZE=2176

# Ensure an MCUboot-compatible binary is generated.
CONFIG_BOOTLOADER_MCUBOOT=y

# Enable flash operations.
CONFIG_FLASH=y

# Required by the `taskstat` command.
CONFIG_THREAD_MONITOR=y

# Support for taskstat command
CONFIG_MCUMGR_GRP_OS_TASKSTAT=y

# Enable statistics and statistic names.
CONFIG_STATS=y
CONFIG_STATS_NAMES=y

# Enable most core commands.
CONFIG_FLASH=y
CONFIG_IMG_MANAGER=y
CONFIG_MCUMGR_GRP_IMG=y
CONFIG_MCUMGR_GRP_OS=y
CONFIG_MCUMGR_GRP_STAT=y

# Enable logging
CONFIG_LOG=y
CONFIG_MCUBOOT_UTIL_LOG_LEVEL_WRN=y

# Disable debug logging
CONFIG_LOG_MAX_LEVEL=3

CONFIG_MCUBOOT_IMGTOOL_UUID_VID=y
CONFIG_MCUBOOT_IMGTOOL_UUID_VID_NAME="nordicsemi.com"
CONFIG_MCUBOOT_IMGTOOL_UUID_CID=y
CONFIG_MCUBOOT_IMGTOOL_UUID_CID_NAME="nRF54H20_sample_app"

sysbuild.conf

SB_CONFIG_BOOTLOADER_MCUBOOT=y
SB_CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
SB_CONFIG_PM_OVERRIDE_EXTERNAL_DRIVER_CHECK=y

nrf54lm20dk_nrf54lm20a_cpuapp_ext_flash_sqspi.conf

# Enable flash operations
CONFIG_FLASH=y

CONFIG_MCUBOOT_LOG_LEVEL_OFF=y

CONFIG_BOOT_MAX_IMG_SECTORS=512
CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x14000

CONFIG_MULTITHREADING=y

CONFIG_LOG=y
CONFIG_LOG_MODE_MINIMAL=y
CONFIG_LOG_DEFAULT_LEVEL=0
CONFIG_CBPRINTF_NANO=y
CONFIG_MINIMAL_LIBC=y

CONFIG_FW_INFO_FIRMWARE_VERSION=2

CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y
CONFIG_SPI=n
CONFIG_SPI_NOR=n
CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE=4096

CONFIG_PM_PARTITION_SIZE_MCUBOOT=0x14000

CONFIG_FPROTECT=n
CONFIG_MAIN_STACK_SIZE=16384

If anyone could point me in the right direction that would be greatly appreciated.

Related