STM32F1与STM32CubeIDE编程实例-W25Q-SPI-Flash与FatFs移植

W25Q-SPI-Flash与FatFs移植

FatFs 是用于小型嵌入式系统的通用 FAT/exFAT 文件系统模块。 FatFs 模块是按照 ANSI C (C89) 编写的,与磁盘 I/O 层完全分离。 因此,它独立于平台。 它可以集成到资源有限的小型微控制器中,例如8051、PIC、AVR、ARM、Z80、RX等。

本文将在W25Q SPI Flash驱动的基础上,实现FatFs移植。W25Q SPI Flash的驱动在前面的文章中做了详细的介绍,请参考:

FatFs的官网地址为:http://elm-chan.org/fsw/ff/00index\_e.html

1、FatFs配置

关于STM32CubeIDE工程创建、配置请参考前面文章:

在前面文章中,对FatFs在STM32CubeIDE中的配置做了详细的介绍,请参考:

本次的FatFs配置如下:

在这里插入图片描述

基本配置保持默认即可。

2、FatFs移植

在STM32CubeIDE中,适配FatFs的步骤非常简单,只需要实现uer_diskio.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
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
115
116
117
118
119
#include "w25qxx/w25qxx.h"
#include "main.h"
#include "spi.h"

/\* Private define ------------------------------------------------------------\*/
w25qxx\_t w25qxx;
/\* Private variables ---------------------------------------------------------\*/

/\* Private functions ---------------------------------------------------------\*/

/\*\*
\* @brief Initializes a Drive
\* @param pdrv: Physical drive number (0..)
\* @retval DSTATUS: Operation status
\*/
DSTATUS USER\_initialize(BYTE pdrv /\* Physical drive nmuber to identify the drive \*/
) {
/\* USER CODE BEGIN INIT \*/
Stat = STA_NOINIT;

w25qxx.SPI_CS_Pin = W25QXX_CHIP_SELECT_Pin;
w25qxx.SPI_CS_Port = W25QXX_CHIP_SELECT_GPIO_Port;
w25qxx.SPI_Handle = &hspi1;

if (w25qxx\_init(&w25qxx)) { // 初始化W25Q
Stat = RES_OK;
w25qxx\_display\_info(&w25qxx);
} else {
Stat = RES_ERROR;
}

return Stat;
/\* USER CODE END INIT \*/
}

/\*\*
\* @brief Reads Sector(s)
\* @param pdrv: Physical drive number (0..)
\* @param \*buff: Data buffer to store read data
\* @param sector: Sector address (LBA)
\* @param count: Number of sectors to read (1..128)
\* @retval DRESULT: Operation result
\*/
DRESULT USER\_read(BYTE pdrv, /\* Physical drive nmuber to identify the drive \*/
BYTE \*buff, /\* Data buffer to store read data \*/
DWORD sector, /\* Sector address in LBA \*/
UINT count /\* Number of sectors to read \*/
) {
/\* USER CODE BEGIN READ \*/
DRESULT status = RES_OK;

// 读扇区内容
w25qxx\_read\_sector(&w25qxx, sector, buff, count);

return status;
/\* USER CODE END READ \*/
}

/\*\*
\* @brief Writes Sector(s)
\* @param pdrv: Physical drive number (0..)
\* @param \*buff: Data to be written
\* @param sector: Sector address (LBA)
\* @param count: Number of sectors to write (1..128)
\* @retval DRESULT: Operation result
\*/
#if \_USE\_WRITE == 1
DRESULT USER\_write(BYTE pdrv, /\* Physical drive nmuber to identify the drive \*/
const BYTE \*buff, /\* Data to be written \*/
DWORD sector, /\* Sector address in LBA \*/
UINT count /\* Number of sectors to write \*/
) {
/\* USER CODE BEGIN WRITE \*/
/\* USER CODE HERE \*/
DRESULT status = RES_OK;
// 写扇区
w25qxx\_write\_sector(&w25qxx, buff, sector, count);
return status;
/\* USER CODE END WRITE \*/
}
#endif /\* \_USE\_WRITE == 1 \*/

/\*\*
\* @brief I/O control operation
\* @param pdrv: Physical drive number (0..)
\* @param cmd: Control code
\* @param \*buff: Buffer to send/receive control data
\* @retval DRESULT: Operation result
\*/
#if \_USE\_IOCTL == 1
DRESULT USER\_ioctl(BYTE pdrv, /\* Physical drive nmuber (0..) \*/
BYTE cmd, /\* Control code \*/
void \*buff /\* Buffer to send/receive control data \*/
) {
/\* USER CODE BEGIN IOCTL \*/
DRESULT res = RES_ERROR;
switch (cmd) {
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_COUNT:
\*(uint32\_t\*) buff = w25qxx.sector_count;
res = RES_OK;
break;
case GET_SECTOR_SIZE:
\*(uint16\_t\*) buff = w25qxx.sector_size;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
\*(uint32\_t\*) buff = w25qxx.block_size;
res = RES_OK;
break;

}
return res;
/\* USER CODE END IOCTL \*/
}
#endif /\* \_USE\_IOCTL == 1 \*/

3、FatFs使用

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
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/\* Private includes ----------------------------------------------------------\*/
/\* USER CODE BEGIN Includes \*/
#include <stdio.h>
#include "w25qxx/w25qxx.h"
/\* USER CODE END Includes \*/

/\* Private variables ---------------------------------------------------------\*/

/\* USER CODE BEGIN PV \*/
extern w25qxx\_t w25qxx;
/\* USER CODE END PV \*/

/\* Private user code ---------------------------------------------------------\*/
/\* USER CODE BEGIN 0 \*/
bool w25qxx\_fatfs\_init(void) {
// 挂载FatFs文件系统
FRESULT res = f\_mount(&USERFatFS, (TCHAR const\*) USERPath, 1);
if (res != FR_OK) {
printf("mount fs failed!%d\r\n", res);
} else {
printf("mount fs success!\r\n");
}
// 没有文件系统,则需要擦除W25Q、格式化文件系统
if (res == FR_NO_FILESYSTEM) {
printf("no file system erase chip...");
// w25qxx\_chip\_erase(&w25qxx);
printf("start to erase chip...\r\n");
w25qxx\_erase\_chip(&w25qxx); // 擦除W25Q
printf("chip erase done\r\n");
printf("format file system\r\n");
res = f\_mkfs(USERPath, 0, 0); // 格式文件系统
if (res == FR_OK) {
res = f\_mount(NULL, USERPath, 1); // 卸载文件系统
res = f\_mount(&USERFatFS, USERPath, 1); // 重新挂载文件系统
if (res == FR_OK) {
printf("flash file system mounted\r\n");
} else {
printf("flash file system mount failed(%d)\r\n", res);
return false;
}
} else {
printf("format file system failed\r\n");
return false;
}

} else if (res != FR_OK) {
printf("fetal error.\r\n");
return false;
}
return true;
}
/\* USER CODE END 0 \*/

int main(void) {
/\* USER CODE BEGIN 1 \*/
UINT fnum; /\* 文件成功读写数量 \*/
BYTE ReadBuffer[32] = { 0 }; /\* 读缓冲区 \*/
BYTE WriteBuffer[] = "0123456789\n";
// uint32\_t flash\_id;
// int ret;
/\* 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\_SPI1\_Init();
MX\_USART1\_UART\_Init();
MX\_FATFS\_Init();
/\* USER CODE BEGIN 2 \*/

if (!w25qxx\_fatfs\_init()) {
printf("fatfs init failed\r\n");
while (1)
;
}

printf("\r\n\*\*\*\*\*\* file writting ... \*\*\*\*\*\*\r\n");
int res = f\_open(&USERFile, "test.txt", FA_CREATE_ALWAYS | FA_WRITE);
if (res == FR_OK) {
printf("openned test.txt,writting data\r\n");
/\* 将指定存储区内容写入到文件内 \*/
retUSER = f\_write(&USERFile, WriteBuffer, 10, &fnum);
if (retUSER == FR_OK) {
printf("write data to file data len:%d\n", fnum);
} else {
printf("write file failed(%d)\n", res);
}
/\* 不再读写,关闭文件 \*/
f\_close(&USERFile);
} else {
printf("open file failed for writting\r\n");
}

/\*------------------- 文件系统测试:读测试 --------------------------\*/
printf("\*\*\*\*\*\* file reading... \*\*\*\*\*\*\r\n");
res = f\_open(&USERFile, "test.txt", FA_OPEN_EXISTING | FA_READ);
if (retUSER == FR_OK) {
printf("openned test.txt\r\n");
retUSER = f\_read(&USERFile, ReadBuffer, 10, &fnum);
if (retUSER == FR_OK) {
printf("read data length:%d\r\n", fnum);
printf("read data content:\r\n%s \r\n", ReadBuffer);
} else {
printf("file read failed:(%d)\n", res);
}
} else {
printf("open file failed for reading(%d)\r\n", res);
}
/\* 不再读写,关闭文文件 \*/
f\_close(&USERFile);

/\* 不再使用文件系统,取消挂载文件系 \*/
f\_mount(NULL, "1:", 1);

/\* 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/125823031