Little FS mount issues

Hi,

We had the UICR used to store our persistent data relevant for a coap client. Recently I saw a hard fault occurring sometimes when we try to access UICR. Further research to this showed its not advisable to use UICR as accessing UICR will halt the processor and this can cause hard faults. It was suggested to use the Settings API to store persistent data.

So I looked at littleFS sample and trying to integrate that to our coap client code. First I added these to my prj.conf.

CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_FILE_SYSTEM=y
CONFIG_FILE_SYSTEM_LITTLEFS=y
CONFIG_SETTINGS_FS=y
CONFIG_SETTINGS_FS_FILE="/lfs"

Then I have the init code as follows.

#define STORAGE_PARTITION	storage_partition
#define STORAGE_PARTITION_ID	FIXED_PARTITION_ID(STORAGE_PARTITION)
#define PARTITION_NODE DT_NODELABEL(lfs1)

void littlefs_initialization(void)
{
	int rc;

#if IS_ENABLED(CONFIG_FILE_SYSTEM_LITTLEFS)
	FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);

	/* mounting info */
	static struct fs_mount_t littlefs_mnt = {
		.type = FS_LITTLEFS,
		.fs_data = &storage,
		.storage_dev = (void *)FLASH_AREA_ID (storage),
		.mnt_point = "/lfs"
	};

	rc = fs_mount(&littlefs_mnt);

	if (rc != 0) {
		LOG_ERR ("mounting littlefs error: [%d]\n", rc);
	} else {

		rc = fs_unlink(CONFIG_SETTINGS_FS_FILE);

		if ((rc != 0) && (rc != -ENOENT)) {
			LOG_ERR ("can't delete config file%d", rc);
		} else {
			LOG_INF ("FS initialized: OK");
		}
	}
#endif

	rc = settings_subsys_init();
	if (rc) {
		LOG_ERR ("settings subsys initialization: fail (err %d)", rc);
		return;
	}

	LOG_INF ("settings subsys initialization: OK");
}

I get the following from the console.

*** Booting Zephyr OS build v3.2.99-ncs2 ***
[00:00:00.099,731] <inf> coap_client: ------- Sensor Start --------
[00:00:00.100,158] <inf> littlefs: LittleFS version 2.5, disk version 2.0
[00:00:00.100,372] <inf> littlefs: FS at flash-controller@4001e000:0xf8000 is 8 0x1000-byte blocks with 512 cycle
[00:00:00.100,372] <inf> littlefs: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
[00:00:00.100,646] <inf> littlefs: /lfs mounted
[00:00:00.100,708] <err> fs: mount point not found!!
[00:00:00.100,738] <err> fs: mount point not found!!


uart:~$ [00:00:00.100,769] <err> coap_client_utils: settings subsys initialization: fail (err -2)
[00:00:00.101,043] <dbg> coap_utils: coap_init: CoAP socket receive thread started
[00:00:00.101,776] <inf> [N] Mle-----------: Mode 0x0c -> 0x04 [rx-on:no ftd:no full-net:no]
[00:00:00.101,898] <err> fs: file open error (-21)
[00:00:00.102,081] <err> fs: file open error (-21)
[00:00:00.102,233] <err> fs: file open error (-21)
[00:00:00.102,355] <err> fs: file open error (-21)
[00:00:00.102,508] <err> fs: file open error (-21)
[00:00:00.102,630] <err> fs: file open error (-21)
[00:00:00.102,783] <err> fs: file open error (-21)
[00:00:00.102,935] <err> fs: file open error (-21)
[00:00:00.103,149] <err> fs: file open error (-21)
[00:00:00.103,302] <err> fs: file open error (-21)
[00:00:00.104,644] <err> fs: file open error (-21)
[00:00:00.100,769] <err> coap_client_utils: settings subsys initialization: fail (err -2)

it says the "/lfs" is mounted, but then I get "mount point not found" and all the other errors. 

I am on a really tight time budget. So looking for some urgent help here.

Cheers,

Kay

  • Hi, 

    I think I managed to fix it by dropping the liitleFS mount and just using settings subsystem.

    My current prj.conf is as follows. (just the part relevant for Settings subsystem)

    CONFIG_NVS=y
    CONFIG_SETTINGS_NVS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    
    CONFIG_SETTINGS=y
    CONFIG_SETTINGS_RUNTIME=y
    
    # CONFIG_FLASH=y
    # CONFIG_FLASH_PAGE_LAYOUT=y
    # CONFIG_FLASH_MAP=y
    # CONFIG_FILE_SYSTEM=y
    # CONFIG_FILE_SYSTEM_LITTLEFS=y
    # CONFIG_SETTINGS_FS=y
    # CONFIG_SETTINGS_FS_FILE="/lfs/settings"

    Then I added the following code for direct access (without a handler as I am not 100% clear about it)
    struct direct_immediate_value {
    	size_t len;
    	void *dest;
    	uint8_t fetched;
    };
    
    static int direct_loader_immediate_value(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg, void *param) {
    	const char *next;
    	size_t name_len;
    	int rc;
    	struct direct_immediate_value *one_value = (struct direct_immediate_value *)param;
    
    	name_len = settings_name_next(name, &next);
    
    	if (name_len == 0) {
    		if (len == one_value->len) {
    			rc = read_cb(cb_arg, one_value->dest, len);
    			if (rc >= 0) {
    				one_value->fetched = 1;
    				return 0;
    			}
    
    			LOG_ERR("load fail %d", rc);
    			return rc;
    		}
    		return -EINVAL;
    	}
    
    	/* other keys aren't served by the callback
    	 * Return success in order to skip them
    	 * and keep storage processing.
    	 */
    	return 0;
    }
    
    int load_immediate_value(const char *name, void *dest, size_t len)
    {
    	int rc;
    	struct direct_immediate_value dov;
    
    	dov.fetched = 0;
    	dov.len = len;
    	dov.dest = dest;
    
    	rc = settings_load_subtree_direct(name, direct_loader_immediate_value, (void *)&dov);
    	if (rc == 0) {
    		if (!dov.fetched) {
    			rc = -ENOENT;
    		}
    	}
    
    	return rc;
    }
    
    void settings_initiallization (void) {
    	int rc;
    
    #if IS_ENABLED(CONFIG_FILE_SYSTEM_LITTLEFS)
    	FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
    
    	/* mounting info */
    	static struct fs_mount_t littlefs_mnt = {
    		.type = FS_LITTLEFS,
    		.fs_data = &storage,
    		.storage_dev = (void *)FLASH_AREA_ID (storage),
    		.mnt_point = "/lfs"
    	};
    
    	rc = fs_mount(&littlefs_mnt);
    
    	if (rc != 0) {
    		LOG_ERR ("mounting littlefs error: [%d]\n", rc);
    	} else {
    
    		rc = fs_unlink(CONFIG_SETTINGS_FS_FILE);
    
    		if ((rc != 0) && (rc != -ENOENT)) {
    			LOG_ERR ("can't delete config file%d", rc);
    		} else {
    			LOG_INF ("FS initialized: OK");
    		}
    	}
    #endif
    
    	rc = settings_subsys_init();
    	if (rc) {
    		LOG_ERR ("settings subsys initialization: fail (err %d)", rc);
    		return;
    	}
    
    	LOG_INF ("settings subsys initialization: OK");
    }

    Then the read / write code is as follows.

    int eraseIPV6inFlash () {
    	int rc;
    	uint32_t flag = 0x00000000;
    	uint32_t hostIP = 0x00000000;
    	uint16_t hostFWver = 0x0000;
    
    	rc = settings_save_one ("flag", (const void *)&flag, sizeof(flag));	// erase flag
    	if (rc != 0) {
    		LOG_ERR ("unexpected error eraseing flag", rc);
    	}
    	rc = settings_save_one ("hostIP", (const void *)&hostIP, sizeof(hostIP));	// erase host IP
    	if (rc != 0) {
    		LOG_ERR ("unexpected error erasing host IP", rc);
    	}
    	rc = settings_save_one ("hostFWver", (const void *)&hostFWver, sizeof(hostFWver));	// erase host fw ver
    	if (rc != 0) {
    		LOG_ERR ("unexpected error host FW ver", rc);
    	}
    	
    	return rc;
    }
    
    void restoreIPV6fromFlash (uint32_t *myExtAddr) {
    	int rc;
    	uint32_t hostIP[4];
    
    	rc = load_immediate_value("hostIP", &hostIP, sizeof(hostIP));
    	if (rc == -ENOENT) {
    		LOG_ERR ("host IP value not found!!");
    	} 
    	else if (rc == 0) {		// valid host IP value read
    		LOG_INF ("Restore host IP %x", *myExtAddr);
    
    	} else 
    		LOG_ERR ("unexpected error %d", rc);
    
    	*myExtAddr = hostIP [0];
    	*(myExtAddr+1) = hostIP [1];
    	*(myExtAddr+2) = hostIP [2];
    	*(myExtAddr+3) = hostIP [3];
    }
    

    Please let me know what I have done is correct.

    Cheers,

    Kaushalya

  • Hi Kaushalya

    I've had a very quick look at the code and I can't see any issues with it. However I recommend that you run tests and set up some routine to catch edge cases so you can verify in your own environment that the code works as you've designed it to do

    We also have the settings sample that you can base your application on and have a look at: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/samples/subsys/settings/README.html 

    Kind regards,
    Andreas

Related