From 2ddd9e14704e35a8914b7d68ac1dba79c7390a8a Mon Sep 17 00:00:00 2001 From: "Luigi F. Cruz" Date: Sat, 28 Jan 2023 19:11:59 -0800 Subject: [PATCH] Add littlefs logic. --- apps/filesystem/test.c | 38 ++--------- lib/littlefs/CMakeLists.txt | 1 + lib/littlefs/lfs_rp2040.c | 128 +++++++++++++++++++++++++++++++----- lib/littlefs/lfs_rp2040.h | 21 +++--- 4 files changed, 130 insertions(+), 58 deletions(-) diff --git a/apps/filesystem/test.c b/apps/filesystem/test.c index 26cbea1..4547bd3 100644 --- a/apps/filesystem/test.c +++ b/apps/filesystem/test.c @@ -1,43 +1,15 @@ #include #include -#include "hardware/flash.h" #include "pico/stdio.h" #include "pico/stdlib.h" -#include #include // variables used by the filesystem lfs_t lfs; lfs_file_t file; -// configuration of the filesystem is provided by this struct -const struct lfs_config cfg = { - // block device operations - .read = lfs_rp2040_read, - .prog = lfs_rp2040_prog, - .erase = lfs_rp2040_erase, - .sync = lfs_rp2040_sync, - - // block device configuration - .read_size = FLASH_PAGE_SIZE, - .prog_size = FLASH_PAGE_SIZE, - .block_size = FLASH_SECTOR_SIZE, - .block_count = 128, - .cache_size = FLASH_PAGE_SIZE, - - .lookahead_size = 16, - .block_cycles = 500, -}; - -uint storage_get_flash_capacity() { - uint8_t rxbuf[4]; - uint8_t txbuf[] = {0x9f}; - flash_do_cmd(txbuf, rxbuf, 4); - return 1 << rxbuf[3]; -} - // entry point int main(void) { stdio_init_all(); @@ -46,17 +18,15 @@ int main(void) { sleep_ms(10); } - printf("%d\n", storage_get_flash_capacity()); - printf("Hello from Pi Pico!\n"); + const struct lfs_config cfg = lfs_rp2040_init(); + // mount the filesystem int err = lfs_mount(&lfs, &cfg); printf("%d\n\n", err); - return 0; - // reformat if we can't mount the filesystem // this should only happen on the first boot if (err) { @@ -82,4 +52,8 @@ int main(void) { // print the boot count printf("boot_count: %d\n", boot_count); + + while(true) { + sleep_ms(1000); + } } diff --git a/lib/littlefs/CMakeLists.txt b/lib/littlefs/CMakeLists.txt index 35d4758..b1eb67f 100644 --- a/lib/littlefs/CMakeLists.txt +++ b/lib/littlefs/CMakeLists.txt @@ -8,6 +8,7 @@ target_link_libraries(littlefs pico_stdlib pico_stdio hardware_flash + hardware_sync ) target_include_directories(littlefs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/lib/littlefs/lfs_rp2040.c b/lib/littlefs/lfs_rp2040.c index 7eedf1e..2e30227 100644 --- a/lib/littlefs/lfs_rp2040.c +++ b/lib/littlefs/lfs_rp2040.c @@ -1,30 +1,128 @@ #include "lfs_rp2040.h" -// Read a region in a block. Negative error codes are propagated -// to the user. +#define DEBUG 1 + +extern char __flash_binary_end; + +static uint storage_get_flash_capacity() { + uint8_t rxbuf[4]; + uint8_t txbuf[4] = {0x9f}; + flash_do_cmd(txbuf, rxbuf, 4); + return 1 << rxbuf[3]; +} + +static struct { + uintptr_t lfs_start_pos; + uintptr_t lfs_end_pos; + uintptr_t lfs_start_addr; + uintptr_t lfs_end_addr; + uint lfs_block_size; + uint lfs_read_size; + uint lfs_write_size; +} _lfs_rp2040_state; + +const struct lfs_config lfs_rp2040_init() { + const uintptr_t flash_capacity = storage_get_flash_capacity(); + const uintptr_t bin_start = (uintptr_t)XIP_BASE; + const uintptr_t bin_end = (uintptr_t)&__flash_binary_end; + + _lfs_rp2040_state.lfs_read_size = FLASH_PAGE_SIZE; + _lfs_rp2040_state.lfs_write_size = FLASH_PAGE_SIZE; + + _lfs_rp2040_state.lfs_block_size = FLASH_SECTOR_SIZE; + _lfs_rp2040_state.lfs_start_addr = (bin_end - 1u + _lfs_rp2040_state.lfs_block_size) & + -_lfs_rp2040_state.lfs_block_size ; + _lfs_rp2040_state.lfs_end_addr = bin_start + flash_capacity; + + _lfs_rp2040_state.lfs_start_pos = _lfs_rp2040_state.lfs_start_addr - bin_start; + _lfs_rp2040_state.lfs_end_pos = _lfs_rp2040_state.lfs_end_addr - bin_start; + + const uint lfs_block_count = (_lfs_rp2040_state.lfs_end_addr - + _lfs_rp2040_state.lfs_start_addr) / + _lfs_rp2040_state.lfs_block_size ; + +#ifdef DEBUG + printf("Flash capacity : 0x%08x\n", flash_capacity); + printf("Binary start : 0x%08x\n", bin_start); + printf("Binary end : 0x%08x\n", bin_end); + printf("LFS start address : 0x%08x\n", _lfs_rp2040_state.lfs_start_addr); + printf("LFS end address : 0x%08x\n", _lfs_rp2040_state.lfs_end_addr); + printf("LFS start pos : 0x%08x\n", _lfs_rp2040_state.lfs_start_pos); + printf("LFS end pos : 0x%08x\n", _lfs_rp2040_state.lfs_end_pos); + printf("LFS block count : 0x%08x\n", lfs_block_count); +#endif + + const struct lfs_config cfg = { + .read = lfs_rp2040_read, + .prog = lfs_rp2040_prog, + .erase = lfs_rp2040_erase, + .sync = lfs_rp2040_sync, + + .read_size = _lfs_rp2040_state.lfs_read_size, + .prog_size = _lfs_rp2040_state.lfs_write_size, + .block_size = _lfs_rp2040_state.lfs_block_size, + .block_count = lfs_block_count, + .cache_size = _lfs_rp2040_state.lfs_write_size, + .lookahead_size = 16, + .block_cycles = 500, + }; + + return cfg; +} + int lfs_rp2040_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size) { - return 0; +#ifdef DEBUG + printf("[LFS I/O] - READ - B: 0x%08x | O: 0x%08x | S: 0x%08x\n", block, off, size); +#endif + + const uintptr_t base_addr = _lfs_rp2040_state.lfs_start_addr; + const uintptr_t block_offset = _lfs_rp2040_state.lfs_block_size * block; + + memcpy(buffer, (void*)(base_addr + block_offset + off), size); + + return LFS_ERR_OK; } -// Program a region in a block. The block must have previously -// been erased. Negative error codes are propagated to the user. -// May return LFS_ERR_CORRUPT if the block should be considered bad. int lfs_rp2040_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size) { - return 0; +#ifdef DEBUG + printf("[LFS I/O] - PROG - B: 0x%08x | O: 0x%08x | S: 0x%08x\n", block, off, size); +#endif + + uint32_t ints = save_and_disable_interrupts(); + + const uintptr_t base_pos = _lfs_rp2040_state.lfs_start_pos; + const uintptr_t block_offset = _lfs_rp2040_state.lfs_block_size * block; + + flash_range_program(base_pos + block_offset + off, buffer, size); + + restore_interrupts(ints); + + return LFS_ERR_OK; } -// Erase a block. A block must be erased before being programmed. -// The state of an erased block is undefined. Negative error codes -// are propagated to the user. -// May return LFS_ERR_CORRUPT if the block should be considered bad. int lfs_rp2040_erase(const struct lfs_config *c, lfs_block_t block) { - return 0; +#ifdef DEBUG + printf("[LFS I/O] - ERASE - B: 0x%08x\n", block); +#endif + + uint32_t ints = save_and_disable_interrupts(); + + const uintptr_t block_size = _lfs_rp2040_state.lfs_block_size; + const uintptr_t base_pos = _lfs_rp2040_state.lfs_start_pos; + const uintptr_t block_offset = _lfs_rp2040_state.lfs_block_size * block; + + flash_range_erase(base_pos + block_offset, block_size); + + restore_interrupts(ints); + + return LFS_ERR_OK; } -// Sync the state of the underlying block device. Negative error codes -// are propagated to the user. int lfs_rp2040_sync(const struct lfs_config *c) { - return 0; +#ifdef DEBUG + printf("[LFS I/O] - SYNC\n"); +#endif + return LFS_ERR_OK; } \ No newline at end of file diff --git a/lib/littlefs/lfs_rp2040.h b/lib/littlefs/lfs_rp2040.h index 6aa4c29..34cf667 100644 --- a/lib/littlefs/lfs_rp2040.h +++ b/lib/littlefs/lfs_rp2040.h @@ -1,28 +1,27 @@ #ifndef LFS_RP2040_H #define LFS_RP2040_H +#include +#include + #include #include -// Read a region in a block. Negative error codes are propagated -// to the user. +#include "hardware/flash.h" +#include "hardware/sync.h" +#include "pico/stdio.h" +#include "pico/stdlib.h" + +const struct lfs_config lfs_rp2040_init(); + int lfs_rp2040_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size); -// Program a region in a block. The block must have previously -// been erased. Negative error codes are propagated to the user. -// May return LFS_ERR_CORRUPT if the block should be considered bad. int lfs_rp2040_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size); -// Erase a block. A block must be erased before being programmed. -// The state of an erased block is undefined. Negative error codes -// are propagated to the user. -// May return LFS_ERR_CORRUPT if the block should be considered bad. int lfs_rp2040_erase(const struct lfs_config *c, lfs_block_t block); -// Sync the state of the underlying block device. Negative error codes -// are propagated to the user. int lfs_rp2040_sync(const struct lfs_config *c); #endif \ No newline at end of file