diff --git a/.gitmodules b/.gitmodules index fadcbf1..1c859c8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "pico-playground"] path = pico-playground url = git@github.com:raspberrypi/pico-playground.git +[submodule "lib/littlefs/littlefs"] + path = lib/littlefs/littlefs + url = https://github.com/littlefs-project/littlefs.git diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 797324d..79ee983 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -2,4 +2,5 @@ add_subdirectory(iperf_server) add_subdirectory(tcp_server) add_subdirectory(adc_dma_chain) add_subdirectory(piccolosdr) -add_subdirectory(barometer) \ No newline at end of file +add_subdirectory(barometer) +add_subdirectory(filesystem) \ No newline at end of file diff --git a/apps/filesystem/CMakeLists.txt b/apps/filesystem/CMakeLists.txt new file mode 100644 index 0000000..3582ba1 --- /dev/null +++ b/apps/filesystem/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.12) + +project(pico-filesystem) + +add_executable(filesystem test.c) + +target_link_libraries(filesystem LINK_PUBLIC littlefs) + +pico_add_extra_outputs(filesystem) + +pico_enable_stdio_usb(filesystem 1) +pico_enable_stdio_uart(filesystem 0) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) \ No newline at end of file diff --git a/apps/filesystem/test.c b/apps/filesystem/test.c new file mode 100644 index 0000000..4547bd3 --- /dev/null +++ b/apps/filesystem/test.c @@ -0,0 +1,59 @@ +#include +#include + +#include "pico/stdio.h" +#include "pico/stdlib.h" + +#include + +// variables used by the filesystem +lfs_t lfs; +lfs_file_t file; + +// entry point +int main(void) { + stdio_init_all(); + + while (getchar_timeout_us(0) != 'X') { + sleep_ms(10); + } + + 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); + + // reformat if we can't mount the filesystem + // this should only happen on the first boot + if (err) { + lfs_format(&lfs, &cfg); + lfs_mount(&lfs, &cfg); + } + + // read current count + uint32_t boot_count = 0; + lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT); + lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count)); + + // update boot count + boot_count += 1; + lfs_file_rewind(&lfs, &file); + lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count)); + + // remember the storage is not updated until the file is closed successfully + lfs_file_close(&lfs, &file); + + // release any resources we were using + lfs_unmount(&lfs); + + // print the boot count + printf("boot_count: %d\n", boot_count); + + while(true) { + sleep_ms(1000); + } +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index cf23198..f9cce72 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(bmp180) add_subdirectory(bmp390) add_subdirectory(usb_network_stack) +add_subdirectory(littlefs) diff --git a/lib/littlefs/CMakeLists.txt b/lib/littlefs/CMakeLists.txt new file mode 100644 index 0000000..b1eb67f --- /dev/null +++ b/lib/littlefs/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.12) + +add_library(littlefs ./lfs_rp2040.c + ./littlefs/lfs.c + ./littlefs/lfs_util.c) + +target_link_libraries(littlefs + pico_stdlib + pico_stdio + hardware_flash + hardware_sync +) + +target_include_directories(littlefs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/littlefs) \ No newline at end of file diff --git a/lib/littlefs/lfs_rp2040.c b/lib/littlefs/lfs_rp2040.c new file mode 100644 index 0000000..2e30227 --- /dev/null +++ b/lib/littlefs/lfs_rp2040.c @@ -0,0 +1,128 @@ +#include "lfs_rp2040.h" + +#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) { +#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; +} + +int lfs_rp2040_prog(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size) { +#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; +} + +int lfs_rp2040_erase(const struct lfs_config *c, lfs_block_t block) { +#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; +} + +int lfs_rp2040_sync(const struct lfs_config *c) { +#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 new file mode 100644 index 0000000..34cf667 --- /dev/null +++ b/lib/littlefs/lfs_rp2040.h @@ -0,0 +1,27 @@ +#ifndef LFS_RP2040_H +#define LFS_RP2040_H + +#include +#include + +#include +#include + +#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); + +int lfs_rp2040_prog(const struct lfs_config *c, lfs_block_t block, + lfs_off_t off, const void *buffer, lfs_size_t size); + +int lfs_rp2040_erase(const struct lfs_config *c, lfs_block_t block); + +int lfs_rp2040_sync(const struct lfs_config *c); + +#endif \ No newline at end of file diff --git a/lib/littlefs/littlefs b/lib/littlefs/littlefs new file mode 160000 index 0000000..6a53d76 --- /dev/null +++ b/lib/littlefs/littlefs @@ -0,0 +1 @@ +Subproject commit 6a53d76e90af33f0656333c1db09bd337fa75d23