Skip to content

Instantly share code, notes, and snippets.

@MZachmann
Last active November 30, 2020 15:13
Show Gist options
  • Save MZachmann/d221f979ea72b45d96358d58de330a48 to your computer and use it in GitHub Desktop.
Save MZachmann/d221f979ea72b45d96358d58de330a48 to your computer and use it in GitHub Desktop.
Simple qspi test code for littlefs implementation with nrf52840
/* test code for the qspi flash filesystem API with littlefs
* these were originally from zephyr sample apps
* so...
* Copyright (c) 2019 Peter Bigot Consulting, LLC
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <stdio.h>
#include <device.h>
#include <fs/fs.h>
#include <fs/littlefs.h>
#include <storage/flash_map.h>
#include <drivers/flash.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#if (CONFIG_SPI_NOR - 0) || DT_NODE_HAS_STATUS(DT_INST(0, jedec_spi_nor), okay)
#define FLASH_DEVICE DT_LABEL(DT_INST(0, jedec_spi_nor))
#define FLASH_NAME "JEDEC SPI-NOR"
#elif (CONFIG_NORDIC_QSPI_NOR - 0) || DT_NODE_HAS_STATUS(DT_INST(0, nordic_qspi_nor), okay)
#define FLASH_DEVICE DT_LABEL(DT_INST(0, nordic_qspi_nor))
#define FLASH_NAME "JEDEC QSPI-NOR"
#else
#error Unsupported flash driver
#endif
// used by the dump routine
#define FLASH_TEST_REGION_OFFSET 0x000
#define FLASH_TEST_REGION_SIZE 0x80000
/* Matches LFS_NAME_MAX */
#define MAX_PATH_LEN 255
/* FS_LITTLEFS_DECLARE_DEFAULT_CONFIG creates read, cache, and write buffers
* and an info structure:: static struct fs_littlefs name where name=the argument
*
* DT_FLASH_AREA_STORAGE_ID comes from the partition named 'storage'
* via the DT compiler.
* See: zephyr\include\generated\devicetree.conf in build folder
*/
FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(_LfsConfig);
static struct fs_mount_t lfs_storage_mnt = {
.type = FS_LITTLEFS,
.fs_data = &_LfsConfig,
.storage_dev = (void *)DT_FLASH_AREA_STORAGE_ID,
.mnt_point = "/lfs",
};
/*
Increment the value stored within a file.
If it doesn't exist create it and store 'start' in it
fname is a full path such as /lfs/test_file
*/
int increment_file_counter(char* fname, int start)
{
struct fs_file_t file;
int rc = fs_open(&file, fname);
if (rc < 0) {
printk("FAIL: open %s: %d\n", fname, rc);
return rc;
}
u32_t count = start;
if (rc >= 0) {
rc = fs_read(&file, &count, sizeof(count));
printk("%s read count %u: %d\n", fname, count, rc);
rc = fs_seek(&file, 0, FS_SEEK_SET);
printk("%s seek start: %d\n", fname, rc);
}
count += 1;
rc = fs_write(&file, &count, sizeof(count));
printk("%s write new boot count %u: %d\n", fname, count, rc);
rc = fs_close(&file);
printk("%s close: %d\n", fname, rc);
return rc;
}
/*
test the lfs file bindings by create/reading/writing three files
*/
void qspi_lfs_test(void)
{
char fname[MAX_PATH_LEN];
struct fs_statvfs sbuf;
const struct flash_area *pfa;
int rc;
struct fs_mount_t *mp = &lfs_storage_mnt;
unsigned int id = (uintptr_t)mp->storage_dev;
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.
This relies on Kconfig in the dts folder having 'config APP_WIPE_STORAGE' */
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); /* per doc this is currently nop, but w/e */
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);
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);
}
increment_file_counter(fname, 0);
snprintf(fname, sizeof(fname), "%s/randomA", mp->mnt_point);
increment_file_counter(fname, 23);
snprintf(fname, sizeof(fname), "%s/randomB", mp->mnt_point);
increment_file_counter(fname, 24);
struct fs_dir_t dir = { 0 };
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);
}
/* simple helper methods for dumping the flash contents
*/
int toint(u8_t* ptr)
{
return *(int*)ptr;
}
/* dump the entire flash memory
only displays areas that aren't all zero / ff
shows hex/ascii
*/
void qspi_dump_contents(void)
{
const size_t len = 32;
u8_t buf[len];
struct device *flash_dev;
int rc;
flash_dev = device_get_binding(FLASH_DEVICE);
if (!flash_dev)
{
printf("SPI flash driver %s was not found!\n", FLASH_DEVICE);
return;
}
const char* fname = flash_dev->config->name;
if(fname != NULL)
{
printf("\n %s flash testing\n", fname);
printf("==========================\n");
}
int ioff = FLASH_TEST_REGION_OFFSET;
int imax = FLASH_TEST_REGION_OFFSET + FLASH_TEST_REGION_SIZE;
for(; ioff < imax; ioff += len)
{
memset(buf, 0xff, len);
rc = flash_read(flash_dev, ioff, buf, len);
if (rc != 0)
{
printf("Flash read failed! %d\n", rc);
return;
}
bool bfound = false;
for(int j=0; j<len; j++)
{
if(buf[j] != 0xff && buf[j] != 0)
{
bfound = true;
break;
}
}
if(bfound)
{
char linout[200];
char ix[10];
linout[0] = '\0';
// print hex list
for(int k=0; k<len; k += 4)
{
sprintf(ix, "%08x,", toint(buf+k));
strcat(linout, ix);
}
strcat(linout, "::");
// print char list
ix[1] = '\0';
for(int k=0; k<len; k++)
{
if(32 <= buf[k] && buf[k] < 128)
{
ix[0] = (char)buf[k];
}
else
{
ix[0] = '.';
}
strcat(linout, ix);
}
printk("%d(%6x): %s\n", ioff, ioff, linout);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment