This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Writing/reading data to external flash on the nRF9160DK

Hello Nordic!

I have connected a sensor to the DK via SPI. It outputs a lot of data, a lot... for 1 second of data I get 4096 entries. Each entry is 10 bytes in length.


I want to store 20 seconds of sensor data on the flash memory, that is a total of about 0,8 MB if my calculations are correct.

The sensor has a FIFO-queue so if the write operation is quick enough there shouldn't be any data loss.
Once 20 seconds worth of data is recorded I then want to send this via LTE to server, I'm guessing in chunks.

Questions:
* How do I go about this? Is there a binary write example available?

* What size should the chunks be for this example?

* Once a file is written and done, before going in to the LTE-part of the design, is there any way to extract the bin file for data validation from the DK?


Thank you!

Parents
  • Hi Sebastiaan! Thank you for answering, truly appreciate it! I was to understand that the nRF9160DK has a 64 Mb external flash memory described here:
    https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrf91_dk%2FUG%2Fnrf91_DK%2Fexternal_memory.html

    This is indeed done via SPI.

    I'm thinking http communication but that is mostly because it's the one I know and have used, does it make much of a difference?

    That's a clever solution for getting the data, I will look into that solution.

    Many thanks!

  • Since you mention using the nRF9160DK's external flash, it is important that you switch in the lines for the external flash. That is done by re-programming the board controller, with the sequence explained here:

    https://devzone.nordicsemi.com/f/nordic-q-a/80836/extend-flash-size-of-nrf9160---single-slot-application/335345#335345

     

    create the file my_project/pm_static.yml, which holds something like this (alter sizes to your needs):

    settings_storage:
      address: 0x0
      region: external_flash
      size: 0x40000

     

    Kind regards,

    Håkon

  • Hi nWre!

     

    nWre said:
    Hi again Håkon! Hoppas allt är bra med dig!

    All good here, thanks! Hope you had a wonderful trip!

     

    nWre said:
    I've flashed the sequence you linked earlier with the prog/debug-switch on nrf52:
    nWre said:
    I've also added the SPI-code that you linked:

     

    The "board-control" is setting a pin on the nRF52840 on the DK to route the ext-flash to the nRF91, while the next is a direct setting of which nRF9160 GPIO on the is connected to the /CS pin on the external-flash itself.

     

    They should match the hardware layout of the nRF9160-DK, which they do by default.

     

    nWre said:
    Now that this config is done, should I be able to use say, LittleFS to write to the external memory by pointing it towards the MX25R64 in the device tree? Is there any other config I should do?

    Define it in your pm_static.yml, here from addr offset 0, size 256kB in region "external_flash":

    littlefs_storage:
      address: 0x0
      device: MX25R64
      end_address: 0x40000
      region: external_flash
      size: 0x40000

     

    Remember to re-generate your build after altering the pm_static.yml!

     

    Kind regards,

    Håkon

  • Seems like the namespace littlefs_storage is not accepted when I try to build the project. I get this:

    'PM_littlefs_storage_ID' undeclared here (not in a function); did you mean 'littlefs_storage'?

    I'm trying to use the example from Zephyr

    /* Matches LFS_NAME_MAX */
    #define MAX_PATH_LEN 255
    
    #define PARTITION_NODE DT_NODELABEL(mx25r6435f)
    
    #if DT_NODE_EXISTS(PARTITION_NODE)
    FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);
    #else  /* PARTITION_NODE */
    FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
    static struct fs_mount_t lfs_storage_mnt = {
    	.type = FS_LITTLEFS,
    	.fs_data = &storage,
    	.storage_dev = (void *)FLASH_AREA_ID(storage),
    	.mnt_point = "/lfs",
    };
    #endif /* PARTITION_NODE */
    
    void memtest(void)
    {
    	struct fs_mount_t *mp =
    #if DT_NODE_EXISTS(PARTITION_NODE)
    		&FS_FSTAB_ENTRY(PARTITION_NODE)
    #else
    		&lfs_storage_mnt
    #endif
    		;
    	unsigned int id = (uintptr_t)mp->storage_dev;
    	char fname[MAX_PATH_LEN];
    	struct fs_statvfs sbuf;
    	const struct flash_area *pfa;
    	int rc;
    
    	snprintf(fname, sizeof(fname), "%s/boot_count", mp->mnt_point);
    
    	rc = flash_area_open(id, &pfa);
    	if (rc < 0)
    	{
    		printk("FAIL: unable to find flash area %u: %d\n",
    			   id, rc);
    		return;
    	}
    
    	printk("Area %u at 0x%x on %s for %u bytes\n",
    		   id, (unsigned int)pfa->fa_off, pfa->fa_dev_name,
    		   (unsigned int)pfa->fa_size);
    
    	/* Optional wipe flash contents */
    	if (IS_ENABLED(CONFIG_APP_WIPE_STORAGE))
    	{
    		printk("Erasing flash area ... ");
    		rc = flash_area_erase(pfa, 0, pfa->fa_size);
    		printk("%d\n", rc);
    	}
    
    	flash_area_close(pfa);
    
    	/* Do not mount if auto-mount has been enabled */
    #if !DT_NODE_EXISTS(PARTITION_NODE) || \
    	!(FSTAB_ENTRY_DT_MOUNT_FLAGS(PARTITION_NODE) & FS_MOUNT_FLAG_AUTOMOUNT)
    	rc = fs_mount(mp);
    	if (rc < 0)
    	{
    		printk("FAIL: mount id %u at %s: %d\n",
    			   (unsigned int)mp->storage_dev, mp->mnt_point,
    			   rc);
    		return;
    	}
    	printk("%s mount: %d\n", mp->mnt_point, rc);
    #else
    	printk("%s automounted\n", mp->mnt_point);
    #endif
    
    	rc = fs_statvfs(mp->mnt_point, &sbuf);
    	if (rc < 0)
    	{
    		printk("FAIL: statvfs: %d\n", rc);
    		goto out;
    	}
    
    	printk("%s: bsize = %lu ; frsize = %lu ;"
    		   " blocks = %lu ; bfree = %lu\n",
    		   mp->mnt_point,
    		   sbuf.f_bsize, sbuf.f_frsize,
    		   sbuf.f_blocks, sbuf.f_bfree);
    
    	struct fs_dirent dirent;
    
    	rc = fs_stat(fname, &dirent);
    	printk("%s stat: %d\n", fname, rc);
    	if (rc >= 0)
    	{
    		printk("\tfn '%s' siz %u\n", dirent.name, dirent.size);
    	}
    
    	struct fs_file_t file;
    
    	fs_file_t_init(&file);
    
    	rc = fs_open(&file, fname, FS_O_CREATE | FS_O_RDWR);
    	if (rc < 0)
    	{
    		printk("FAIL: open %s: %d\n", fname, rc);
    		goto out;
    	}
    
    	uint32_t boot_count = 0;
    
    	if (rc >= 0)
    	{
    		rc = fs_read(&file, &boot_count, sizeof(boot_count));
    		printk("%s read count %u: %d\n", fname, boot_count, rc);
    		rc = fs_seek(&file, 0, FS_SEEK_SET);
    		printk("%s seek start: %d\n", fname, rc);
    	}
    
    	boot_count += 1;
    	rc = fs_write(&file, &boot_count, sizeof(boot_count));
    	printk("%s write new boot count %u: %d\n", fname,
    		   boot_count, rc);
    
    	rc = fs_close(&file);
    	printk("%s close: %d\n", fname, rc);
    
    	struct fs_dir_t dir;
    
    	fs_dir_t_init(&dir);
    
    	rc = fs_opendir(&dir, mp->mnt_point);
    	printk("%s opendir: %d\n", mp->mnt_point, rc);
    
    	while (rc >= 0)
    	{
    		struct fs_dirent ent = {0};
    
    		rc = fs_readdir(&dir, &ent);
    		if (rc < 0)
    		{
    			break;
    		}
    		if (ent.name[0] == 0)
    		{
    			printk("End of files\n");
    			break;
    		}
    		printk("  %c %u %s\n",
    			   (ent.type == FS_DIR_ENTRY_FILE) ? 'F' : 'D',
    			   ent.size,
    			   ent.name);
    	}
    
    	(void)fs_closedir(&dir);
    
    out:
    	rc = fs_unmount(mp);
    	printk("%s unmount: %d\n", mp->mnt_point, rc);
    }


    Önsker deg en nydelig helg!

  • Hi,

     

    Here's a modified littlefs sample, with nrf9160dk ext flash support:

    ncs1_7_nrf9160dk_ext_flash_littlefs.zip

     

    Kind regards,

    Håkon

  • Thanks Håkon, I tried the sample but having trouble with the SPI-bus. "Node should only occur on the spi bus", I'm guessing that occurs because the sample you sent does not have a

    compatible = "nordic,nrf-spim";


    If I do include that, I instead get these errors:



    Thank you for all the help, you are my Gandalf in Moria.


  • Hi,

     

    The "compatible" member shall be inherited from the board itself, ie. this line:

    https://github.com/nrfconnect/sdk-zephyr/blob/main/boards/arm/nrf9160dk_nrf9160/nrf9160dk_nrf9160_common.dts#L197

     

    Which board are you configuring for? It should be the "nrf9160dk_nrf9160_ns" board.

     

    PS: remember to delete any ancient build folders, especially when editing static partition layout.

     

    Kind regards,

    Håkon

Reply Children
  • Yes, building for the "nrf9160dk_nrf9160_ns" board. Using the sample with the correct board setup I still get the same errors I posted above. Are you able to run the sample without any mods on nrf9160dk? If that's the case I might need to do a reset. Thanks again, appreciate it.

    Edit: The reset helped, I must have written something goofy somewhere. Thanks Håkon, you the man. I'll buy you a beer if you ever come to Gothenburg.

Related