#include <limits.h>
#include "hardware/flash.h"
#include "hardware/regs/addressmap.h"
#include "hardware/sync.h"
#include "pico/mutex.h"
#include "pico/time.h"
#include "lfs.h"
lfs_t lfs;
#define FS_SIZE (256 * 1024)
// file system offset in flash
const char* FS_BASE = (char*)(PICO_FLASH_SIZE_BYTES - FS_SIZE);
int pico_hal_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size);
int pico_hal_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size);
int pico_hal_erase(const struct lfs_config *c, lfs_block_t block);
static int pico_sync(const struct lfs_config *c);
int pico_lock(void);
int pico_unlock(void);
// configuration of the filesystem is provided by this struct
// for Pico: prog size = 256, block size = 4096, so cache is 8K
// minimum cache = block size, must be multiple
struct lfs_config pico_cfg;
/*struct lfs_config pico_cfg = {
// block device operations
.read = pico_hal_read,
.prog = pico_hal_prog,
.erase = pico_hal_erase,
#if LIB_PICO_MULTICORE
.lock = pico_lock,
.unlock = pico_unlock,
#endif
// block device configuration
.read_size = 1,
.prog_size = FLASH_PAGE_SIZE,
.block_size = FLASH_SECTOR_SIZE,
.block_count = FS_SIZE / FLASH_SECTOR_SIZE,
.cache_size = FLASH_SECTOR_SIZE / 4,
.lookahead_size = 32,
.block_cycles = 500
}*/
void lfsInit() {
pico_cfg.read = pico_hal_read;
pico_cfg.prog = pico_hal_prog;
pico_cfg.erase = pico_hal_erase;
pico_cfg.sync = pico_sync;
#if LIB_PICO_MULTICORE
pico_cfg.lock = pico_lock;
pico_cfg.unlock = pico_unlock;
#endif
pico_cfg.read_size = 1;
pico_cfg.prog_size = FLASH_PAGE_SIZE;
pico_cfg.block_size = FLASH_SECTOR_SIZE;
pico_cfg.block_count = FS_SIZE / FLASH_SECTOR_SIZE;
pico_cfg.cache_size = FLASH_SECTOR_SIZE / 4;
pico_cfg.lookahead_size = 32;
pico_cfg.block_cycles = 500;
}
int pico_hal_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void* buffer, lfs_size_t size) {
assert(block < pico_cfg.block_count);
assert(off + size <= pico_cfg.block_size);
// read flash via XIP mapped space
memcpy(buffer, FS_BASE + XIP_NOCACHE_NOALLOC_BASE + (block * pico_cfg.block_size) + off, size);
return LFS_ERR_OK;
}
int pico_hal_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void* buffer, lfs_size_t size) {
//assert(block < pico_cfg.block_count);
// program with SDK
uint32_t p = (uint32_t)FS_BASE + (block * pico_cfg.block_size) + off;
uint32_t ints = save_and_disable_interrupts();
flash_range_program(p, (uint8_t*)buffer, size);
restore_interrupts(ints);
return LFS_ERR_OK;
}
int pico_hal_erase(const struct lfs_config *c, lfs_block_t block) {
assert(block < pico_cfg.block_count);
// erase with SDK
uint32_t p = (uint32_t)FS_BASE + block * pico_cfg.block_size;
uint32_t ints = save_and_disable_interrupts();
flash_range_erase(p, pico_cfg.block_size);
restore_interrupts(ints);
return LFS_ERR_OK;
}
static int pico_sync(const struct lfs_config *c) {
return 0;
}
#if LIB_PICO_MULTICORE
static recursive_mutex_t fs_mtx;
int pico_lock(void) {
recursive_mutex_enter_blocking(&fs_mtx);
return LFS_ERR_OK;
}
int pico_unlock(void) {
recursive_mutex_exit(&fs_mtx);
return LFS_ERR_OK;
}
#endif
void setup() {
Serial.begin(115200);
while (!Serial) {
delay(10); // wait for serial port to connect. Needed for native USB
}
lfsInit();
int res = -1;
res = llfs_mount(&lfs, &pico_cfg);
if (res) {
Serial.println("lfs mount fail");
Serial.println("Ok formatto e riprovo a montare");
llfs_format(&lfs, &pico_cfg);
res = llfs_mount(&lfs, &pico_cfg);
}
if (res == 0) {
Serial.println("Ok, lfs mounted.");
}
struct lfs_info lfsinfo;
res = llfs_stat(&lfs, "/", &lfsinfo);
if (res)
Serial.println("lfs_stat error");
else {
Serial.print("type: ");
Serial.println(lfsinfo.type);
Serial.print("size: ");
Serial.println(lfsinfo.size);
Serial.print("name: ");
Serial.println(lfsinfo.name);
}
// Now you can safely print message:
Serial.println("Hello, Serial Monitor!");
}
void loop() {
delay(10);
}