External flash with LittleFS & FOTA

Hi support team,

I'm currently developing a project for a custom board with a nRF9160 chip and with nRF Connect SDK 2.9.0 and Zephyr 3.7.99 using VS code with nRF connect extension as IDE.
My board collects samples from a sensor and then uploads it to the cloud. However, since I cannot lose any data I need to save it somewhere while there's no connection to the cloud, so I've added an external flash (MX25R6435F). To test the connection to my flash I used the jesd216 sample, building it to my custom board. I also included it in my device tree like this:

&spi3 {
	compatible = "nordic,nrf-spim";
	status = "okay";
	cs-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
	pinctrl-0 = <&spi3_default>;
	pinctrl-1 = <&spi3_sleep>;
	pinctrl-names = "default", "sleep";
	mx25r64: mx25r6435f@0  {
		compatible = "jedec,spi-nor";
		reg = <0>;
		spi-max-frequency = <8000000>;
		jedec-id = [c2 28 17];
		size = <67108864>;
		wp-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>;
		hold-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
	};
};

This seems to work fine, the sample output:

*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
mx25r6435f@0: SFDP v 1.6 AP ff with 3 PH
PH0: ff00 rev 1.6: 16 DW @ 30
Summary of BFP content:
DTR Clocking not supported
Addressing: 3-Byte only
4-KiBy erase: uniform
Support QSPI XIP
Support 1-1-1
Support 1-1-2: instr 3Bh, 0 mode clocks, 8 waits
Support 1-1-4: instr 6Bh, 0 mode clocks, 8 waits
Support 1-2-2: instr BBh, 0 mode clocks, 4 waits
Support 1-4-4: instr EBh, 2 mode clocks, 4 waits
Flash density: 8388608 bytes
ET1: instr 20h for 4096 By; typ 48 ms, max 384 ms
ET2: instr 52h for 32768 By; typ 240 ms, max 1920 ms
ET3: instr D8h for 65536 By; typ 480 ms, max 3840 ms
Chip erase: typ 52000 ms, max 312000 ms
Byte program: type 32 + 1 * B us, max 192 + 6 * B us
Page program: typ 896 us, max 5376 us
Page program size: 256 By
Suspend: B0h ; Resume: 30h
DPD: Enter B9h, exit ABh ; delay 40000 ns ; poll 0x3d
HOLD or RESET Disable: unsupported
QER: 2
0-4-4 Mode methods: entry 0x9 ; exit 0x2f
4-4-4 Mode sequences: en

Now I want to include LittleFS to the project so I have a file system where I can store the sensor data.

I updated my prj.conf to include the following:

# Enable SPI NOR flash support
CONFIG_SPI=y
CONFIG_SPI_NOR=y
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096

# Enable flash operations
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_FLASH_PAGE_LAYOUT=y

# Enable file system
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y

# Cpp
CONFIG_CPP=y
CONFIG_STD_CPP20=y
CONFIG_MINIMAL_LIBCPP=y
CONFIG_GLIBCXX_LIBCPP=y

CONFIG_SETTINGS=y
CONFIG_SETTINGS_FILE=y
CONFIG_SETTINGS_FILE_PATH="/lfs/settings"

I also added this to the device tree, to tell the partition manager to include my external flash.

    chosen {
		nordic,pm-ext-flash = &mx25r64;
	};

Finally, I added a pm_static.yml file to define my external flash partitions:

littlefs_storage:
  address: 0x00000000  # Start of the combined storage area in external flash
  region: external_flash
  size: 0x00800000  # Total size covering all three partitions
  placement:
    before: end

sensordata_partition:
  address: 0x00000000
  region: external_flash
  size: 0x00400000
  placement:
    within: littlefs_storage  # Explicitly part of littlefs_storage

log_partition:
  address: 0x00400000
  region: external_flash
  size: 0x00400000
  placement:
    after: sensordata_partition
    within: littlefs_storage

When building the project I can see that my external flash partition is indeed being included, but addresses seems wrong?

app:
  address: 0x8000
  end_address: 0x0
  region: flash_primary
  size: -0x8000
external_flash:
  address: 0x1000000
  end_address: 0x800000
  region: external_flash
  size: -0x800000
littlefs_storage:
  address: 0x0
  end_address: 0x800000
  placement:
    before: end
  region: external_flash
  size: 0x800000
log_partition:
  address: 0x400000
  end_address: 0x800000
  placement:
    after: sensordata_partition
    within: littlefs_storage
  region: external_flash
  size: 0x400000
nrf_modem_lib_ctrl:
  address: 0x20008000
  end_address: 0x200084e8
  inside:
  - sram_nonsecure
  placement:
    after:
    - tfm_sram
    - start
  region: sram_primary
  size: 0x4e8
nrf_modem_lib_rx:
  address: 0x2000a568
  end_address: 0x2000c568
  inside:
  - sram_nonsecure
  placement:
    after:
    - nrf_modem_lib_tx
  region: sram_primary
  size: 0x2000
nrf_modem_lib_sram:
  address: 0x20008000
  end_address: 0x2000c568
  orig_span: &id001
  - nrf_modem_lib_ctrl
  - nrf_modem_lib_tx
  - nrf_modem_lib_rx
  region: sram_primary
  size: 0x4568
  span: *id001
nrf_modem_lib_tx:
  address: 0x200084e8
  end_address: 0x2000a568
  inside:
  - sram_nonsecure
  placement:
    after:
    - nrf_modem_lib_ctrl
  region: sram_primary
  size: 0x2080
otp:
  address: 0xff8108
  end_address: 0xff83fc
  region: otp
  size: 0x2f4
sensordata_partition:
  address: 0x0
  end_address: 0x400000
  placement:
    within: littlefs_storage
  region: external_flash
  size: 0x400000
sram_nonsecure:
  address: 0x20008000
  end_address: 0x20040000
  orig_span: &id002
  - sram_primary
  - nrf_modem_lib_ctrl
  - nrf_modem_lib_tx
  - nrf_modem_lib_rx
  region: sram_primary
  size: 0x38000
  span: *id002
sram_primary:
  address: 0x2000c568
  end_address: 0x20040000
  region: sram_primary
  size: 0x33a98
sram_secure:
  address: 0x20000000
  end_address: 0x20008000
  orig_span: &id003
  - tfm_sram
  region: sram_primary
  size: 0x8000
  span: *id003
tfm:
  address: 0x0
  end_address: 0x8000
  placement:
    before:
    - app
  region: flash_primary
  size: 0x8000
tfm_nonsecure:
  address: 0x8000
  end_address: 0x0
  orig_span: &id004
  - app
  region: flash_primary
  size: -0x8000
  span: *id004
tfm_secure:
  address: 0x0
  end_address: 0x8000
  orig_span: &id005
  - tfm
  region: flash_primary
  size: 0x8000
  span: *id005
tfm_sram:
  address: 0x20000000
  end_address: 0x20008000
  inside:
  - sram_secure
  placement:
    after:
    - start
  region: sram_primary
  size: 0x8000

Also when running the code I instantly get a hardfault.

I just upgraded my SDK from version 2.4.0 to 2.9.0 and I can see that something called sysbuild have been introduced, maybe I'm missing a link there?

Also when this is working, I would like to configure the external flash to also have a partition for the FOTA image to free up some space on the internal flash, is this possible?

Related