nRF5340 DK: QSPI falsh erase and write

Hi Support Team,

I want to store sensor-monitored data per minute into the QSPI flash(mx25r6435f) on the nRF5340 DK, and send these data over LTE/mqtt per day. Could you help me with the below questions?

1 At first I used low-level APIs like flash_erase, flash_write, etc.
(1) For the QSPI flash operation, must I erase the sector first, then write the data to flash?
(2) Must the size of the flash_erase be 4096 bytes(the flash sector size)? Can I erase 1024 bytes, and then write the sensor data record by order?

2 My data will be stored in a circular overwritten way. When no free space in Flash, the latest data will overwrite the oldest data, and CRC is needed. I found there are several subsystems like Non-Volatile Storage (NVS), Flash map and Flash Circular Buffer (FCB) in Zephyr. Could you help give some guidance for my scenario, is FCB the best solution for my purpose? Is there a sample for FCB?

Thank you very much.

Best regards,
Yanpeng Wu

  • Hi

    1. If the QSPI flash sector you're about to write to is already used, you should indeed erase the sector before writing to it.

    2. The QSPI driver in NCS supports erasing one memory block, so 4kB, 64kB or the whole chip, so no. You can't erase just 1024 bytes.

    3. Please check out this thread where using a circular buffer with external QSPI flash is already discussed in detail. Let me know if you have any other questions or follow ups to these questions.

    Best regards,

    Simon

  • Hi Simonr,

    Thank you for the reply. I checked the thread you suggested, which is different from my case. (I used the external flash with QSPI, that thread used SPI driver and needed to disable CONFIG_NORDIC_QSPI_NOR, if my understanding is correct).

    To use the FCB, I need to create partitions first.  I tried on nRF5340 DK and tried to create two partitions on my external flash and the overlay is:

    &qspi {
        mx25r6435f@0 {
            partitions {
                compatible = "fixed-partitions";
                #address-cells = <1>;
                #size-cells = <1>;
    
                stats_partition: partition@0 {
                    label = "log_stats_parti";
                    reg = <0x00000000 0x00001000>; /* Start at 0, size 4KB */
                };
                log_partition: partition@1000 {
                    label = "log_data_parti";
                    reg = <0x00001000 0x001FF000>; /* Start at 4KB, size just under 2MB */
                };
            };
        };
    };

    But when I try to open the flash_area with the below way, compiling always failed:

    #define STATS_PARTITION   					log_stats_parti
    #define LOG_PARTITION     					log_data_parti
    
    int init_flash_area()
    {
    	int rc;
    	const struct flash_area *stats_fa;
    	const struct flash_area *log_fa;
    
        rc = flash_area_open(FLASH_AREA_ID(log_stats_parti), &stats_fa);
        if (rc) {
            printk("Failed to open stats partition: %d\n", rc);
            return -EINVAL;
        }
    /*
        rc = flash_area_open(FLASH_AREA_ID(log_data_parti), &log_fa);
        if (rc) {
            printk("Failed to open log partition: %d\n", rc);
            return -EINVAL;
        }
    */
    	return 0;
    }

    Error info:

    In file included from C:/ncs/v2.5.2/zephyr/include/zephyr/storage/flash_map.h:275,
                     from ../include/IoTDL_flash.h:11,
                     from ../src/IoTDL_flash.c:6:
    ../src/IoTDL_flash.c: In function 'init_flash_area':
    C:/ncs/v2.5.2/nrf/include/flash_map_pm.h:43:22: error: 'PM_log_stats_parti_ID' undeclared (first use in this function)
       43 | #define PM_ID(label) PM_##label##_ID
          |                      ^~~
    C:/ncs/v2.5.2/nrf/include/flash_map_pm.h:48:35: note: in expansion of macro 'PM_ID'
       48 | #define FIXED_PARTITION_ID(label) PM_ID(label)
          |                                   ^~~~~
    C:/ncs/v2.5.2/nrf/include/flash_map_pm.h:49:30: note: in expansion of macro 'FIXED_PARTITION_ID'
       49 | #define FLASH_AREA_ID(label) FIXED_PARTITION_ID(label)
          |                              ^~~~~~~~~~~~~~~~~~
    ../src/IoTDL_flash.c:28:26: note: in expansion of macro 'FLASH_AREA_ID'
       28 |     rc = flash_area_open(FLASH_AREA_ID(log_stats_parti), &stats_fa);
          |                          ^~~~~~~~~~~~~
    C:/ncs/v2.5.2/nrf/include/flash_map_pm.h:43:22: note: each undeclared identifier is reported only once for each function it appears in
       43 | #define PM_ID(label) PM_##label##_ID
          |                      ^~~
    C:/ncs/v2.5.2/nrf/include/flash_map_pm.h:48:35: note: in expansion of macro 'PM_ID'
       48 | #define FIXED_PARTITION_ID(label) PM_ID(label)
          |                                   ^~~~~
    C:/ncs/v2.5.2/nrf/include/flash_map_pm.h:49:30: note: in expansion of macro 'FIXED_PARTITION_ID'
       49 | #define FLASH_AREA_ID(label) FIXED_PARTITION_ID(label)
          |                              ^~~~~~~~~~~~~~~~~~
    ../src/IoTDL_flash.c:28:26: note: in expansion of macro 'FLASH_AREA_ID'
       28 |     rc = flash_area_open(FLASH_AREA_ID(log_stats_parti), &stats_fa);
          |                          ^~~~~~~~~~~~~
    ../src/IoTDL_flash.c:26:34: warning: unused variable 'log_fa' [-Wunused-variable]
       26 |         const struct flash_area *log_fa;
          |                                  ^~~~~~
    ninja: build stopped: subcommand failed.
    FATAL ERROR: command exited with status 1: 'C:\ncs\toolchains\c57af46cb7\opt\bin\cmake.EXE' --build 'c:\02_dataLogger\IOTDL\build'

    I double-checked and can't find the cause. Could you help give some guidance? The flash setting in prj.conf is:

    CONFIG_SPI=y
    CONFIG_NORDIC_QSPI_NOR=y
    CONFIG_PARTITION_MANAGER_ENABLED=y

    Thank you very much.

    Best regards,
    Yanpeng Wu

  • Update:
    I followed External flash memory partitions and added the below to my overlay:

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

    After that, I can see the external_flash region was created in \build\regions.yml:

    external_flash:
      base_address: 0x0
      default_driver_kconfig: CONFIG_PM_EXTERNAL_FLASH_HAS_DRIVER
      device: DT_CHOSEN(nordic_pm_ext_flash)
      dynamic_partition: null
      name: external_flash
      placement_strategy: start_to_end
      size: 0x800000

    But in \build\partitions.yml, these two partitions were not created:

    external_flash:
      address: 0x0
      end_address: 0x800000
      region: external_flash
      size: 0x800000

    And In the \build\zephyr\.config, I can see 'CONFIG_PM_EXTERNAL_FLASH_HAS_DRIVER=y'.

    Maybe something missed in the prj.conf? I attached my prj.conf and overlay here.

    50625.prj.conf,     8037.nrf5340dk_nrf5340_cpuapp.overlay

  • Hello again,
    In Partition Manager mentioned "When you build a multi-image application using the Partition Manager, the devicetree source flash partitions are ignored.".

    In my application, the mult-image was used and had the below cmake arguments:
    -Dhci_rpmsg_OVERLAY_CONFIG="../child_image/hci_rpmsg.conf; /ncs/v2.5.2/nrf/subsys/partition_manager/partition_manager_enabled.conf"

    Maybe the reason of the partitions defined in overlay failed is this?

    If the partition_manager was enabled, how to create partitions on the external QSPI flash? Seems need define it in pm.yml, but I can't find this file in my prject and don't know how to define it. Could you help give some guidance? Thank you very much.

  • Hi Yanpeng

    An external flash would be set up in a .yml file like the following for example:

    external_flash:
      address: 0x120000
      size: 0x6e0000
      device: MX25R64
      region: external_flash

    Where the address and size is something you configure not to overlap with the flash of the nRF5340. It seems to me like the base_address in your external_flash is incorrect and that's likely what you're having trouble with. What errors/issues are you currently having on your side?

    Best regards,

    Simon

Related