Last active
November 30, 2020 15:13
-
-
Save MZachmann/d221f979ea72b45d96358d58de330a48 to your computer and use it in GitHub Desktop.
Simple qspi test code for littlefs implementation with nrf52840
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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