Set NVM Size

Hello,

  I need to persist ~200K of data on the internal flash of an NRF52832 chip.  I've run a memory report and I'm current taking up 185Kb and the chip has 512 Kb of flash so there is the space.  I've taken the code from teh sample nvm project to init that nvm filesystm as below:

int init_storage(){
    LOG_INF("Init storage");
    int rc = 0;
    	/* define the nvs file system by settings with:
	 *	sector_size equal to the pagesize,
	 *	3 sectors
	 *	starting at NVS_PARTITION_OFFSET
	 */
	fs.flash_device = NVS_PARTITION_DEVICE;
	if (!device_is_ready(fs.flash_device)) {
		LOG_ERR("Flash device %s is not ready\n", fs.flash_device->name);
		return -1;
	}

	fs.offset = NVS_PARTITION_OFFSET;
	rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
	if (rc) {
		LOG_ERR("Unable to get page info, rc=%d\n", rc);
		return -1;
	}
    LOG_INF("Storage initialized size is %" PRIu32 " index is %" PRIu32, info.size, info.index);
    

	fs.sector_size = info.size;
	fs.sector_count = 2U;
    
    rc = nvs_mount(&fs);
	if (rc) {
		LOG_ERR("Flash Init failed, rc=%d\n", rc);
		return 0;
	}

    return 0;
}

  This works fine but it only gives me 4K worth of memory space.  If I increase the sector count to more than 3 I get an invalid address: 0x00080ff8 error on runtime.  How can I set the nvm filesystem to be 200Kb in size?

Cheers,

Neil

Parents
  • Hi Neil, 
    Could you send us your partitions.yml file in build folder ? 
    Note that the NVS system is allocated inside nvs_storage partition and by default this partition has the size of 0x6000 (24kB = 6 sectors)
    I don't know what you configured in your partition manager, but you may want to manually increase the size of the nvs_storage partition. You may need to adjust the size of other partition to make room for the nvs_storage partition. 

    This is what looks like in the nvs sample built for nRF52840: 

    app:
      address: 0x0
      end_address: 0xfa000
      region: flash_primary
      size: 0xfa000
    nvs_storage:
      address: 0xfa000
      end_address: 0x100000
      placement:
        before:
        - end
      region: flash_primary
      size: 0x6000
    sram_primary:
      address: 0x20000000
      end_address: 0x20040000
      region: sram_primary
      size: 0x40000
    

  • Thanks for your help, please see blow:

    app:
      address: 0x0
      end_address: 0x7a000
      region: flash_primary
      size: 0x7a000
    nvs_storage:
      address: 0x7a000
      end_address: 0x80000
      placement:
        before:
        - end
      region: flash_primary
      size: 0x6000
    sram_primary:
      address: 0x20000000
      end_address: 0x20010000
      region: sram_primary
      size: 0x10000
    

    Regards,

    Neil

  • Hi Neil, 
    Could you show how you set up  the nvs_fs in the code ? 
    Which flash partition you assign it to ? 
    For example here is the code in the nvs sample: 

    #define NVS_PARTITION		storage_partition
    #define NVS_PARTITION_DEVICE	FIXED_PARTITION_DEVICE(NVS_PARTITION)
    #define NVS_PARTITION_OFFSET	FIXED_PARTITION_OFFSET(NVS_PARTITION)
    
    ...
    fs.flash_device = NVS_PARTITION_DEVICE;
    	if (!device_is_ready(fs.flash_device)) {
    		printk("Flash device %s is not ready\n", fs.flash_device->name);
    		return 0;
    	}
    	fs.offset = NVS_PARTITION_OFFSET;
    	rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
    	if (rc) {
    		printk("Unable to get page info, rc=%d\n", rc);
    		return 0;
    	}
    	fs.sector_size = info.size;
    	fs.sector_count = 5U;
    
    	rc = nvs_mount(&fs);

  • Hello,

     I actually took it straight from that example, please see below:

    #include "include/bw_storage.h"
    #include <zephyr/logging/log.h>
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <string.h>
    #include <errno.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/drivers/flash.h>
    #include <zephyr/storage/flash_map.h>
    #include <zephyr/fs/nvs.h>
    
    #define LOG_MODULE_NAME brikwiz_storage
    LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);
    
    static struct nvs_fs fs;
    
    #define NVS_PARTITION		storage_partition
    #define NVS_PARTITION_DEVICE	FIXED_PARTITION_DEVICE(NVS_PARTITION)
    #define NVS_PARTITION_OFFSET	FIXED_PARTITION_OFFSET(NVS_PARTITION)
    #define NVS_PARTITION_SIZE	FIXED_PARTITION_SIZE(NVS_PARTITION)
    
    struct flash_pages_info info;
    
    uint16_t vid_file_id;
    
    int init_storage(){
        LOG_INF("Init storage");
        int rc = 0;
        	/* define the nvs file system by settings with:
    	 *	sector_size equal to the pagesize,
    	 *	3 sectors
    	 *	starting at NVS_PARTITION_OFFSET
    	 */
    	fs.flash_device = NVS_PARTITION_DEVICE;
    	if (!device_is_ready(fs.flash_device)) {
    		LOG_ERR("Flash device %s is not ready\n", fs.flash_device->name);
    		return -1;
    	}
    
    	fs.offset = NVS_PARTITION_OFFSET;
    	rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
    	if (rc) {
    		LOG_ERR("Unable to get page info, rc=%d\n", rc);
    		return -1;
    	}
        LOG_INF("Storage size is %" PRIu32 " index is %" PRIu32, info.size, info.index);
        
        LOG_INF("Partition size is %" PRIu32 " offset is %" PRIu32, NVS_PARTITION_SIZE, NVS_PARTITION_OFFSET);
    	fs.sector_size = info.size;
    	fs.sector_count = 2U;
        
        rc = nvs_mount(&fs);
    	if (rc) {
    		LOG_ERR("Flash Init failed, rc=%d\n", rc);
    		return 0;
    	}
    
        return 0;
    }

      However that is the only thing I took directly; I also copied over the CONFIG options from the prj.conf file in the nvs example to my project's prj.conf file.

    Cheers,

    Neil

  • Hi Neil, 
    It seems that SETTINGS and your own nvs flash is sharing the same partition settings_storage. You may want to define your own partition for your nvs flash storage. 
    I would suggest to take a look at this sample from Sigurd: 
    RE: Setting and using NVS and BT Settings with Static Partition Manager

    To have your own dedicated partition for nvs, you can create a file named pm_static.yml and put the custom_nvs_storage there. 

  • Hello,

      Thanks for that; I followed the example and included the pm_static.yml file as follows:

    custom_nvs_storage:
      address: 0x80000
      end_address: 0x88000
      region: flash_primary
      size: 0x8000
    

    The code to initalise the storage is as follows:

    #include "include/bw_storage.h"
    #include <zephyr/logging/log.h>
    #include <zephyr/types.h>
    #include <stddef.h>
    #include <string.h>
    #include <errno.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/drivers/flash.h>
    #include <zephyr/storage/flash_map.h>
    #include <zephyr/fs/nvs.h>
    
    #define LOG_MODULE_NAME brikwiz_storage
    LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);
    
    static struct nvs_fs fs;
    
    #define NVS_PARTITION		custom_nvs_storage
    #define NVS_PARTITION_DEVICE	FIXED_PARTITION_DEVICE(NVS_PARTITION)
    #define NVS_PARTITION_OFFSET	FIXED_PARTITION_OFFSET(NVS_PARTITION)
    #define NVS_PARTITION_SIZE	FIXED_PARTITION_SIZE(NVS_PARTITION)
    
    struct flash_pages_info info;
    
    uint16_t vid_file_id;
    
    int init_storage(){
        LOG_INF("Init storage");
        int rc = 0;
        	/* define the nvs file system by settings with:
    	 *	sector_size equal to the pagesize,
    	 *	3 sectors
    	 *	starting at NVS_PARTITION_OFFSET
    	 */
    	fs.flash_device = NVS_PARTITION_DEVICE;
    	if (!device_is_ready(fs.flash_device)) {
    		LOG_ERR("Flash device %s is not ready\n", fs.flash_device->name);
    		return -1;
    	}
    
    	fs.offset = NVS_PARTITION_OFFSET;
    	rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
    	if (rc) {
    		LOG_ERR("Unable to get page info, rc=%d\n", rc);
    		return -1;
    	}
        LOG_INF("Storage size is %" PRIu32 " index is %" PRIu32, info.size, info.index);
        
        LOG_INF("Partition size is %" PRIu32 " offset is %" PRIu32, NVS_PARTITION_SIZE, NVS_PARTITION_OFFSET);
    	fs.sector_size = info.size;
    	fs.sector_count = 2U;
        
        rc = nvs_mount(&fs);
    	if (rc) {
    		LOG_ERR("Flash Init failed, rc=%d\n", rc);
    		return 0;
    	}
    
        return 0;
    }

     Upon compiling the storage seems correctly allocated:

    app:
      address: 0x0
      end_address: 0x7e000
      region: flash_primary
      size: 0x7e000
    custom_nvs_storage:
      address: 0x80000
      end_address: 0x88000
      region: flash_primary
      size: 0x8000
    settings_storage:
      address: 0x7e000
      end_address: 0x80000
      placement:
        align:
          start: 0x1000
        before:
        - end
      region: flash_primary
      size: 0x2000
    sram_primary:
      address: 0x20000000
      end_address: 0x20010000
      region: sram_primary
      size: 0x10000
    

      However when the code executes I get the following error:

    *** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
    *** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
    [00:00:00.008,850] <inf> brikwiz_base: Starting BrikWiz Base Peripheral
    
    [00:00:00.008,850] <inf> brikwiz_storage: Init storage
    [00:00:00.008,850] <err> brikwiz_storage: Unable to get page info, rc=-22
    
    [00:00:00.008,880] <err> brikwiz_base: Failed to initialize storage
    

      There seems to be something going wrong on the line

    rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);

      I'm not sure what I can do to find more information on the error?

    Cheers,

    Neil

  • Hi Neil, 
    I think you are defining something outside of the flash area. The chip has only 512kB meaning 0x80000 is the last address of it. 
    You need to define custom_nvs_storage behind settings_storage and after app. 
    Try to squeeze the custom_nvs_storage between them (make app partition 0x8000 smaller and put custom_nvs_storage  in there)

Reply Children
  • Hello,

      Aha, that makes sense - I'm thinking I could use the non-static partition manager file to define this while I'm in dev mode.  However, I was (possibly falsly) assuming that the app would not take up too much space - is there a way of determining how much space the app is taking up?  I can't imagine it is ~500K for a simple app with a BLE stack, GPIO and NVS.

    Cheers,

    Neil

  • Hi Neil, 
    You can see how much flash is used by looking at the zephyr.map file (search for Memory Configuration in the .map file)
    Or look at this when you build: 


    Be noted that if you plan to have DFU update supported, you may have to reserve 50% of the flash space for receiving the image. 

  • Hello,

      Thanks, is that 50% of the total flash space available on the chip or just 50% that the app takes up?

    Cheers,

    Neil

  • Hi Neil, 


    It's 50% of the total flash space. The swap/secondary space should be as big as the partition configured for the app (primary partition). 

  • Hello,

      Apologies for the delay in replying - been ill.  I can define a  static_pm.yml but unless I put the nvs storage at address 0x00000 I will have gaps in the storage which causes problem.  I currently have:

    custom_nvs_storage:
      address: 0x00000
      end_address: 0x08000
      region: flash_primary
      size: 0x8000
    

    This gives me a partitions.yml file of:

    app:
      address: 0x8000
      end_address: 0x7e000
      region: flash_primary
      size: 0x76000
    custom_nvs_storage:
      address: 0x0
      end_address: 0x8000
      region: flash_primary
      size: 0x8000
    settings_storage:
      address: 0x7e000
      end_address: 0x80000
      placement:
        align:
          start: 0x1000
        before:
        - end
      region: flash_primary
      size: 0x2000
    sram_primary:
      address: 0x20000000
      end_address: 0x20010000
      region: sram_primary
      size: 0x10000
    

    If I put the nvs storage at 0x00000 nothing starts (I assume the bootloader expects the app to tb eat 0x00000).  At the moment; I've just calculated this manually but that'll eb difficult as time goes on.   I can solve this by using the dynamic bootloader and having a pm.yml file but I can't work out how to configure the dynamical pm.yml file to work.  So far I've make a pm.yml.nvs.video file which is:

    custom_nvs_storage:
      placement:
        after: app
      size: 0x8000

    and changed the CMakeLists.txt file the following:

    #
    # Copyright (c) 2018 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    cmake_minimum_required(VERSION 3.20.0)
    
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(brikwiz_base)
    
    ncs_add_partition_manager_config(pm.yml.nvs.video)
    
    # NORDIC SDK APP START
    target_sources(app PRIVATE
      src/bw_base.c
      src/bw_storage.c
    )
    
    target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/fs/nvs)
    
    # NORDIC SDK APP END
    zephyr_library_include_directories(.)
    

      Sorry this is so long and thanks for your help.

    Cheers,

    Neil

Related