STM32F1与STM32CubeIDE编程实例-W25Q-SPI-Flash与LittleFS移植 W25Q-SPI-Flash与LittleFS移植 LittleFS是为微控制器设计的一个小故障安全文件系统。LittleFS具有如下特性:
电恢复能力 - littlefs 旨在处理随机电源故障。 所有文件操作都有强大的写时复制保证,如果断电,文件系统将回退到最后一个已知的良好状态。
动态磨损均衡 - littlefs 在设计时考虑了闪存,并提供动态块的磨损均衡。 此外,littlefs 可以检测坏块并解决它们。
有界 RAM/ROM - littlefs 旨在使用少量内存。 RAM 使用量是严格限制的,这意味着 RAM 消耗量不会随着文件系统的增长而改变。 文件系统不包含无限递归,动态内存仅限于可以静态提供的可配置缓冲区。
本文将详细介绍如何在W25Q驱动的基础上,移植LittleFS。在前面的文章中,详细介绍了如何驱动W25Q SPI Flash,请参考:
1、LittleFS移植 关于STM32CubeIDE工程创建、配置请参考前面文章:
第一步,下载LittleFS:https://github.com/littlefs-project/littlefs
第二步,将LittleFS的源码复制到STM32CubeIDE工程中
第三步,在littlefs目录中,添加lfs_port.h和lfs_port.c文件,分别添加如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /\* \* lfs\_port.h \* \* Created on: Jun 14, 2022 \* Author: jenson \*/ #ifndef LITTLEFS\_LFS\_PORT\_H\_ #define LITTLEFS\_LFS\_PORT\_H\_ #include "w25qxx/w25qxx.h" int w25qxx\_littlefs\_init(void); #endif /\* LITTLEFS\_LFS\_PORT\_H\_ \*/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 #include "lfs.h" #include "w25qxx/w25qxx.h" #include "main.h" #include "spi.h" //#include "w25qxx/w25qxx.h" // lfs句柄 lfs\_t littlefs; w25qxx\_t\* __w25qxx = NULL; w25qxx\_t w25qxx; /\*\* \* lfs与底层flash读数据接口 \* @param c \* @param block 块编号 \* @param off 块内偏移地址 \* @param buffer 用于存储读取到的数据 \* @param size 要读取的字节数 \* @return \*/ static int lfs\_deskio\_read(const struct lfs\_config \*c, lfs\_block\_t block, lfs\_off\_t off, void \*buffer, lfs\_size\_t size) { uint32\_t page_addr = (block \* w25qxx.block_size) / w25qxx.page_size + off; w25qxx\_read(__w25qxx,(uint8\_t\*)buffer,page_addr,size); return LFS_ERR_OK; } /\*\* \* lfs与底层flash写数据接口 \* @param c \* @param block 块编号 \* @param off 块内偏移地址 \* @param buffer 待写入的数据 \* @param size 待写入数据的大小 \* @return \*/ static int lfs\_deskio\_prog(const struct lfs\_config \*c, lfs\_block\_t block, lfs\_off\_t off, const void \*buffer, lfs\_size\_t size) { uint32\_t page_addr = (block \* w25qxx.block_size) / w25qxx.page_size + off; w25qxx\_write(__w25qxx,(uint8\_t\*)buffer,page_addr,size); return LFS_ERR_OK; } /\*\* \* lfs与底层flash擦除接口 \* @param c \* @param block 块编号 \* @return \*/ static int lfs\_deskio\_erase(const struct lfs\_config \*c, lfs\_block\_t block) { w25qxx\_sector\_erase(__w25qxx, block); return LFS_ERR_OK; } static int lfs\_deskio\_sync(const struct lfs\_config \*c) { return LFS_ERR_OK; } /// /// 静态内存使用方式必须设定这四个缓存 /// static uint8\_t read_buffer[64]; static uint8\_t prog_buffer[64]; static uint8\_t lookahead_buffer[64]; struct lfs\_config cfg = { // block device operations .read = lfs_deskio_read, .prog = lfs_deskio_prog, .erase =lfs_deskio_erase, .sync = lfs_deskio_sync, .read_size = 64, .prog_size = 64, .cache_size = 64, .lookahead_size = 64, .block_cycles = 500, // // 使用静态内存必须设置这几个缓存 // .read_buffer = read_buffer, .prog_buffer = prog_buffer, .lookahead_buffer = lookahead_buffer, }; int w25qxx\_littlefs\_init(void) { // lwmem\_init(); w25qxx.SPI_CS_Pin = FLASH_CS_Pin; w25qxx.SPI_CS_Port = FLASH_CS_GPIO_Port; w25qxx.SPI_Handle = &hspi1; __w25qxx = &w25qxx; if (w25qxx\_init(&w25qxx)) { w25qxx\_display\_info(&w25qxx); } else { printf("init w25qxx failed\r\n"); return -1; } // cfg.block_count = w25qxx.block_count; cfg.block_size = w25qxx.block_size; int err = lfs\_mount(&littlefs, &cfg); // reformat if we can't mount the filesystem // this should only happen on the first boot if (err) { w25qxx\_erase\_chip(&w25qxx); err = lfs\_format(&littlefs, &cfg); err = lfs\_mount(&littlefs, &cfg); } return err; }
实现LittleFS的关键是实现LittleFS的read、prog、erase、sync函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 struct lfs\_config cfg = { // block device operations .read = lfs_deskio_read, .prog = lfs_deskio_prog, .erase =lfs_deskio_erase, .sync = lfs_deskio_sync, .read_size = 64, .prog_size = 64, .cache_size = 64, .lookahead_size = 64, .block_cycles = 500, // // 使用静态内存必须设置这几个缓存 // .read_buffer = read_buffer, .prog_buffer = prog_buffer, .lookahead_buffer = lookahead_buffer, };
最后,初始化W25Q驱动,注册并挂载LittleFS文件系统。
2、LittleFS调用实现 在STM32CubeIDE工程中的Application目录中分别添加如下文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /\* \* littlefs\_demo.h \* \* Created on: Jul 12, 2022 \* Author: jenson \*/ #ifndef LITTLEFS\_DEMO\_H\_ #define LITTLEFS\_DEMO\_H\_ #include "littlefs/lfs\_port.h" #include "littlefs/lfs.h" void littlefs\_demo(void); #endif /\* LITTLEFS\_DEMO\_H\_ \*/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 /\* \* littlefs\_demo.c \* \* Created on: Jul 12, 2022 \* Author: jenson \*/ #include "littlefs\_demo.h" #define LFS\_SIZE 1024 #define FILE\_NAME "hello.txt" uint8\_t lfs_tx_buffer[1024]; uint8\_t lfs_rx_buffer[1024]; extern lfs\_t littlefs; void lfs\_read\_test(void) { printf("read testing...\r\n"); lfs\_file\_t file; int res = lfs\_file\_open(&littlefs, &file, FILE_NAME, LFS_O_RDONLY); if (res == 0) { printf("open file for read %s success\r\n", FILE_NAME); lfs\_file\_read(&littlefs, &file, lfs_tx_buffer, LFS_SIZE); printf("read %s,size:%d\r\n%s\r\n", FILE_NAME, LFS_SIZE, lfs_tx_buffer); lfs\_file\_close(&littlefs, &file); } else { printf("open file %s failed\r\n", FILE_NAME); } } void lfs\_write\_test(void) { printf("write testing...\r\n"); lfs\_file\_t file; memset(lfs_tx_buffer,'A',LFS_SIZE); int res = lfs\_file\_open(&littlefs, &file, FILE_NAME, LFS_O_WRONLY | LFS_O_CREAT); if (res == 0) { lfs\_file\_write(&littlefs, &file, lfs_tx_buffer, LFS_SIZE); lfs\_file\_close(&littlefs, &file); } else { printf("open file %s failed\r\n", FILE_NAME); } } void littlefs\_demo(void) { int ret = w25qxx\_littlefs\_init(); if ( ret != 0){ printf("littlefs init failed(%d)\r\n",ret); while(1); } lfs\_write\_test(); lfs\_read\_test(); }
在main.c文件中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /\* USER CODE BEGIN Includes \*/ #include<stdio.h> #include "w25qxx/w25qxx.h" #include "littlefs\_demo.h" /\* USER CODE END Includes \*/ int main(void) { /\* USER CODE BEGIN 1 \*/ /\* USER CODE END 1 \*/ /\* MCU Configuration--------------------------------------------------------\*/ /\* Reset of all peripherals, Initializes the Flash interface and the Systick. \*/ HAL\_Init(); /\* USER CODE BEGIN Init \*/ /\* USER CODE END Init \*/ /\* Configure the system clock \*/ SystemClock\_Config(); /\* USER CODE BEGIN SysInit \*/ /\* USER CODE END SysInit \*/ /\* Initialize all configured peripherals \*/ MX\_GPIO\_Init(); MX\_USART1\_UART\_Init(); MX\_SPI1\_Init(); /\* USER CODE BEGIN 2 \*/ littlefs\_demo(); /\* USER CODE END 2 \*/ /\* Infinite loop \*/ /\* USER CODE BEGIN WHILE \*/ while (1) { /\* USER CODE END WHILE \*/ /\* USER CODE BEGIN 3 \*/ } /\* USER CODE END 3 \*/ }
运行结果如下:
文章来源: https://iotsmart.blog.csdn.net/article/details/125822969
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!