Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Updating numbered headings

...

This note describes how to use the SPI Flash with the Thingy-9151-Lite platform.

2. Hardware Implementation

...

There is a generic jedec,spi-nor driver in Zephyr that should be able is used to handle SPI flash Flash devices compatible with the JESD216 JEDEC standard. This driver operates as a middleware between an underlying driver for the SoC-specific SPI controller and the low-level flash Flash API. This

The driver is enabled available when the SPI_NOR configuration parameter is enabled in the build-configuration. The level of auto-configuration is selected with the SPI_NOR_SFDP parameter:

SPI_NOR_SFDP

SPI_NOR_SFDP_MINIMAL (default)

Synthesize Synthesise a minimal configuration assuming 256 By page size and
standard 4 KiBy and 64 KiBy erase instructions. Requires the size and
jedec-id properties in the devicetree device tree jedec,spi-nor node.

SPI_NOR_SFDP_DEVICETREE

The JESD216 Basic Flash Parameters table must be provided in the
sfdp-bfp property in devicetreedevice tree. The size and jedec-id properties are
also required.

SPI_NOR_SFDP_RUNTIME

Read all flash device characteristics from the device at runtime.
This option is the most flexible as it should provide functionality
for all supported JESD216-compatible devices.

For the full list of driver parameters available in the device tree, refer to https://docs.zephyrproject.org/latest/build/dts/api/bindings/mtd/jedec%2Cspi-nor.html#std-dtcompatible-jedec-spi-nor Note, that

3.2. Support for QSPI Flash

Note that the jedec,spi-nor driver runs on top of the SPI driver, so the DSPI and QSPI features are not supported by this solution. For some Nordic chips (nRF5340 in particular), there is a nordic,qspi-nor driver that supports operating in QSPI mode, with its own set of flash parameters. nordic,qspi-nor is not affected by SPI_NOR_SFDP, all required parameters need to be supplied in the device tree node.

3.

...

3. Software APIs

There are several API levels that allow access to SPI flashFlash.

3.

...

3.1. Low Level Flash Access

This level can be used to access the SPI Flash , as a raw Flash device.

The following calls are the core for the flash Flash API defined in zephyr/include/zephyr/drivers/flash.h:

Code Block
languagec
__syscall const struct flash_parameters *flash_get_parameters(const struct device *dev);
__syscall size_t flash_get_write_block_size(const struct device *dev);
/* access functions */
__syscall int flash_erase(const struct device *dev, off_t offset, size_t size);
__syscall int flash_write(const struct device *dev, off_t offset,
                          const void *data,
                          size_t len);
__syscall int flash_read(const struct device *dev, off_t offset, void *data,
                         size_t len);
/* specific to SPI flash, if supported by driver and enabled by CONFIG_FLASH_JESD216_API */
__syscall int flash_read_jedec_id(const struct device *dev, uint8_t *id);
__syscall int flash_sfdp_read(const struct device *dev, off_t offset,
                              void *data, size_t len);

There are more to flash APIthe Flash API’s, please refer to Zephyr documentation https://docs.zephyrproject.org/latest/hardware/peripherals/flash.html for details.

There are also the zephyr/samples/drivers/jesd216 and zephyr/samples/drivers/spi_flash demos that demonstrate using use of low-level API.

3.

...

3.2. Flash Partitioning

Zephyr additionally has API’s that can be used to partition SPI Flash. The goal is to provide a facility to split a single chip Flash device into several named areas to be used independently and preventing out-of-bounds access.

There is a predefined flash Flash map that is created from the “fixed-partition” compatible entries in the DTS file. Internally, each flash Flash area is described with a descriptor, providing: offset, length, underlying flash driver. This Those descriptors are identified by globally unique ID numbers. To obtain the ID from the device tree label for “fixed-partition” use the FIXED_PARTITION_ID() macro.

It is also possible to create flash partition during Flash partitions at the runtime.

The following functions are the core of flash Flash area API defined in zephyr/include/zephyr/storage/flash_map.h

...

Refer to Zephyr documentations https://docs.zephyrproject.org/latest/services/storage/flash_map/flash_map.html for details. Note , that when using multi-image builds, the Nordic SDK overrides the partitions defined in the device tree with Partition Manager .

The zephyr/samples/subsys/fs/littlefs sample illustrate using illustrates use of a fixed partition to create a file system over it. mcuboot is another useful example.

3.

...

3.3. High-

...

Level Non-

...

Volatile API

There are several high-level storage API API’s provided by Zephyr that can be used over flashFlash (or flash a Flash area):

  1. https://docs.zephyrproject.org/latest/services/storage/nvs/nvs.html can be used to store elements, represented as id-data pairs.

  2. https://docs.zephyrproject.org/latest/services/storage/fcb/fcb.html provides an abstraction through which you can treat flash Flash like a FIFO.

  3. https://docs.zephyrproject.org/latest/services/storage/stream/stream_flash.html module takes contiguous fragments of a stream of data (e.g. from radio packets), aggregates them into a user-provided buffer, then when the buffer fills (or stream ends), writes it to a raw flash Flash partition.

  4. https://docs.zephyrproject.org/latest/services/file_system/index.html allow to have several independent file systems.

See samples/fs/littlefs, samples/subsys/usb/mass for an example of how to use filesystem over SPI flashFlash.

In the nrf-app application use the CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL, CONFIG_PM_PARTITION_REGION_SETTINGS_STORAGE_EXTERNAL, and CONFIG_PM_PARTITION_REGION_NVS_STORAGE_EXTERNAL to relocate corresponding partition to SPI flashFlash.

3.

...

4. Zephyr Shell Commands

The nrf-app application comes preconfigured to use SPI flashFlash, and with support for the relevant Zephyr shell commands enabled. The following shell commands are supportedavailable:

Code Block
erase [<device>] <page address> [<size>]
read [<device>] <address> [<Dword count>]
test [<device>] <address> <size> <repeat count>
write [<device>] <address> <dword> [<dword>...]
load [<device>] <address> <size>
page_info [<device>] <address>
read_test [<device>] <address> <size> <repeat count>
write_test [<device>] <address> <size> <repeat count>
erase_test [<device>] <address> <size> <repeat count>
erase_write_test [<device>] <address> <size> <repeat count>

In the above, [<device>] is an optional flash Flash device name (as given in the device tree). If not present, value of zephyr,flash in the choosen node will be used.

When specifying the <address> and <size> values, use an 0x prefix for the hexadecimal values. <size> for test operations is limited by the CONFIG_FLASH_SHELL_BUFFER_SIZE parameter and defaults to 0x4000.

The following procedures can be used to verify raw Flash access. Note, that the low-level API is used and in the example, which can destroy any available partition data can be destroyed by this test:

  1. Run a generic erase/write/read/compare test:

    Code Block
    uart:~$ flash test gd25wb256e3ir@1 0 0x4000 1
    Erase OK.
    Write OK.
    Verified OK.
    Erase-Write-Verify test done.
  2. Run read and write measurements:

    Code Block
    uart:~$ flash erase gd25wb256e3ir@1 0 0x4000
    Erase success.
    uart:~$ flash write_test gd25wb256e3ir@1 0 0x4000 1
    Loop #1 done in 53 ticks.
    Total: 53ms, Per loop: ~53ms, Speed: ~301.9KiBps
    uart:~$ flash read_test gd25wb256e3ir@1 0 0x4000 1
    Loop #1 done in 16ms.
    Total: 16ms, Per loop: ~16ms, Speed: ~1000.0KiBps

...

4. Configuring for

...

a Different SPI Flash Device

This chapter explains how to configure a different flash device using GD25WB256E different Flash device in the Zephyr BSP. Specifically, the GD25WB256E Flash device installed on the Thingy-9151-Lite platform is used as an example.

...

4.1.

...

Obtaining JEDEC

...

Info

First step when setting a new SPI flash Flash is to obtain information about it. To do so, we need to create minimal a minimally required description of the flashFlash. Let’s start with the following overlay:

Code Block
&arduino_spi {

        newspi: newdevice@1 {
                compatible = "jedec,spi-nor";
                status = "ok";
                reg = <1>;
                spi-max-frequency = <8000000>;
                jedec-id = [c8 65 19];
                size = <0x400000>;
        };
};

/ {
        aliases {
                spi-flash0 = &newspi;
        };
};

We’re adding In the above, we are adding a new device newdevice@1 at address 1 (match matching the CS used for the chip) and create creating a label to refer to it as newspi. The compatibleand status fields select the driver and mark the device as present. The reg field specifies the CS for our SPI device. spi-max-frequency, jedec-id and size (in bits!) can easily need to be obtained from the SPI flash datasheetFlash data sheet. spi-max-frequency may be lower than the maximum value specified in datasheet and the data sheet. size does not have to be correct at this point, just to be correctly aligned, so the driver does not refuse the configuration.

Now As a next step, go to zephyr/samples/drivers/jesd216, put the fragment above into boards/nrf9161dk_nrf9161.overlay and build the sample using west:

Code Block
$ cd zephyr/samples/drivers/jesd216
$ cat >boards/nrf9161dk_nrf9161.overlay <<EOF
&arduino_spi {

        newspi: newdevice@1 {
                compatible = "jedec,spi-nor";
                status = "ok";
                reg = <1>;
                spi-max-frequency = <8000000>;
                jedec-id = [c8 65 19];
                size = <0x400000>;
        };
};

/ {
        aliases {
                spi-flash0 = &newspi;
        };
};
EOF
$ west build -b nrf9161dk_nrf9161 -d build_an -p

If the build finish finishes successfully, there will be a build_an/zephyr/zephyr.hex file that can be installed and run on the target. Here’s Here is some example output after when running this demo:

Code Block
*** Booting nRF Connect SDK v2.5.1-7-g76a2a1188200 ***
newdevice@1: 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- or 4-Byte
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, 2 mode clocks, 2 waits
Support 1-4-4: instr EBh, 2 mode clocks, 4 waits
Flash density: 33554432 bytes
ET1: instr 20h for 4096 By; typ 80 ms, max 800 ms
ET2: instr 52h for 32768 By; typ 256 ms, max 2560 ms
ET3: instr D8h for 65536 By; typ 304 ms, max 3040 ms
Chip erase: typ 60928 ms, max 487424 ms
Byte program: type 80 + 5 * B us, max 640 + 40 * B us
Page program: typ 512 us, max 4096 us
Page size: 256 By
Suspend: 75h ; Resume: 7Ah
DPD: Enter B9h, exit ABh ; delay 40000 ns ; poll 0x01
HOLD or RESET Disable: unsupported
QER: 7
0-4-4 Mode methods: entry 0x4 ; exit 0x01
4-4-4 Mode sequences: enable 0x00 ; disable 0x0
4-byte addressing support: enter 0x01, exit 0x001
Soft Reset and Rescue Sequence support: 0x10
Status Register 1 support: 0x08
size = <268435456>;
sfdp-bfp = [
	e5 20 f3 ff  ff ff ff 0f  44 eb 08 6b  08 3b 42 bb
	ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
	10 d8 00 ff  44 7a c9 fe  83 67 26 62  ec 82 18 44
	7a 75 7a 75  04 c4 d5 5c  00 06 74 00  08 50 00 01
	];
PH1: ffc8 rev 1.0: 3 DW @ 90
sfdp-ffc8 = [
	00 36 50 16  9d f9 77 64  fc cb ff ff
	];
PH2: ff84 rev 1.0: 2 DW @ c0
sfdp-ff84 = [
	ff 0e f0 ff  21 5c dc ff
	];
jedec-id = [c8 65 19];

Now, we can replace the size line in our flash Flash descriptor in the overlay with the value obtained from the SFDP by this sample. We can also copy the sfdp-bfp value from the output: it may be needed if SPI_NOR_SFDP_DEVICETREE is used in the configuration. As the line starting with DPD: indicates, the hardware supports DPD using the B9h and ABh commands and the time to wake up is 40000 ns. Unfortunately The time to enter DPD can only be obtained from datasheet the data sheet (usually tDP, it is referred to as tDP). Add has-dpd, t-enter-dpd and t-exit-dpd. Now, we can finalize flash finalise the Flash description in the overlay:

Code Block
/* Deactivate predefined flash node for SPI flash installed on DK */
&gd25wb256 {
        status = "disable";
};

&arduino_spi {
/* Insert node for new device */
        newspi: newdevice@1 {
                compatible = "jedec,spi-nor";
                status = "ok";
                reg = <1>;
                spi-max-frequency = <8000000>;
                jedec-id = [c8 65 19];
                size = <268435456>;
                has-dpd;
                t-enter-dpd = <3000>;
                t-exit-dpd = <40000>;
                sfdp-bfp = [ 
                        e5 20 f3 ff  ff ff ff 0f  44 eb 08 6b  08 3b 42 bb
                        ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52
                        10 d8 00 ff  44 7a c9 fe  83 67 26 62  ec 82 18 44
                        7a 75 7a 75  04 c4 d5 5c  00 06 74 00  08 50 00 01
                        ]; 
        };
};

/* Use new device in choosen and aliases */
/ {
       chosen {
                nordic,pm-ext-flash = &newspi;
       };

       aliases {
                spi-flash0 = &newspi;
                ext-flash = &newspi;
       };
};

...

4.2. Configuring for

...

Different SPI

...

Flash Device with QSPI support on nRF5340

...

The nRF5340 MCU includes a QSPI controller that allows to use faster flash Flash devices in dual and quad SPI mode.

Following the similar procedure to for an SPI flash Flash discussed above, jedec216 provides the following output:

...

spi-max-frequency, jedec-id, sfdp-bfp, size, has-dpd, t-enter-dpd and t-exit-dpd are determined similarly to the SPI case. However nordic,qspi-nor requires additional parameters to enable the quad mode:

  • quad-enable-requirements defines a method to enable the quad mode and can be determined from the line starting with QER: in the output

QER:

quad-enable-requirements

0

'NONE'

1

'S2B1v1'

2

'S1B6'

3

'S2B7'

4

'S2B1v4'

5

'S2B1v5'

6

'S2B1v6'

  • readoc and writeoc define the command and the mode used during for the quad access:

Mode

Write instruction

Read Instruction

writeoc

readoc

1-1-1

0x02

0x0B

'pp'

'fastread'

1-1-2

0xA2

0x3B

'pp2o'

'read2o'

1-2-2

0xBB

'read2io'

1-1-4

0x32

0x6B

'pp4o'

'read4o'

1-4-4

0x38

0xEB

'pp4io'

'read4io'

For the both parameters above, the yellow lines indicate the values not supported by nordic,qspi-nor.

For the device used in this test, both the 1-1-4 and 1-4-4 modes are available, but with 1-4-4 is being slightly faster, so it will be selected. Final The final device tree entry is as follows:

Code Block
                                mx25r64: mx25r6435f@0 {
                                        compatible = "nordic,qspi-nor";
                                        reg = < 0x0 >;
                                        writeoc = "pp4io";
                                        readoc = "read4io";
                                        quad-enable-requirements = "S1B6";
                                        sck-frequency = < 8000000 >;
                                        jedec-id = [ C2 28 17 ];
                                        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 = < 0x4000000 >;
                                        has-dpd;
                                        t-enter-dpd = < 10000 >;
                                        t-exit-dpd = < 35000 >;
                                };

...