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.hlfs_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的readprogerasesync函数

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