基于STM32+CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试(下篇
发布时间: 2023-07-11

四、移植FATFS文件系统

前面第3章,完成了SD NAND的驱动代码编写,这一章节实现FATFS文件的移植。

4.1 FATFS文件系统介绍

(1)介绍

FatFs 是一种完全免费开源的 FAT 文件系统模块,专门为小型的嵌入式系统而设计。它完全用标准C 语言编写,所以具有良好的硬件平台独立性,可以移植到 8051、 PIC、 AVR、 SH、 Z80、 H8、 ARM 等系列单片机上而只需做简单的修改。它支持 FATl2、 FATl6 和 FAT32,支持多个存储媒介;有独立的缓冲区,可以对多个文件进行读/写,并特别对 8 位单片机和 16 位单片机做了优化。

(2)特点

【1】Windows兼容的FAT文件系统

【2】不依赖于平台,易于移植

【3】代码和工作区占用空间非常小

【4】多种配置选项

【5】多卷(物理驱动器和分区)

【6】多ANSI/OEM代码页,包括DBCS

【7】在ANSI/OEM或Unicode中长文件名的支持

【8】RTOS的支持

【9】多扇区大小的支持

【10】只读,最少API,I/O缓冲区等等

(3)移植性

fatfs模块是ANSI C(C89)编写的。 没有平台的依赖, 编译器只要符合ANSI C标准就可以编译。

fatf模块假设大小的字符/短/长8/16/32位和int是16或32位。 这些数据类型在integer.h文件中定义。这些数据类型在大多数的编译器中定义都符合要求。 如果现有的定义与编译器有任何冲突发生时,需要自己解决。

4.2 下载源码

下载地址:

展开全文

FATFS有两个版本,一个大版本,一个小版本。小版本主要用于8位机(内存小)使用。

下载图:

4.3 源码结构介绍

将下载的源码解压后可以得到两个文件夹: doc 和 src。 doc 里面主要是对 FATFS 的介绍(离线文档—英文和日文),而 src 里面才是我们需要的源码。

其中,与平台无关的是:

与平台相关的代码:

FATFS 模块在移植的时候,我们一般只需要修改 2 个文件,即 ffconf.h 和 diskio.c。

FATFS模块的所有配置项都是存放在 ffconf.h 里面,我们可以通过配置里面的一些选项,来满足自己的需求。

最顶层是应用层,使用者无需理会 FATFS 的内部结构和复杂的 FAT 协议,只需要调用FATFS 模块提供给用户的一系列应用接口函数,如 f_open, f_read, f_write 和 f_close 等,就可以像在 PC 上读写文件那样简单。

中间层 FATFS 模块, 实现了 FAT 文件读/写协议。 FATFS 模块提供的是 ff.c 和 ff.h。除非有必要,使用者一般不用修改,使用时将头文件直接包含进去即可。

需要我们编写移植代码的是 FATFS 模块提供的底层接口,它包括存储媒介读/写接口 ( disk、I/O) 和供给文件创建修改时间的实时时钟。

4.4 下载源码并加入到工程

先准备好一个有SD NAND驱动代码的STM32工程(代码前面第3章已经贴了),接着就完成下面的步骤。

打开KEIL工程,添加FATFS文件源码:

加入.h文件主要是方便配。cc936.c 用于支持中文。

4.5 修改代码进行移植

(1)修改diskio.c文件

注释掉现在不需要的用到的文件,因为我们现在用的是SD卡,与USB,ATA,MMC卡没关系。

并加入一个新的宏 :

#define SD 0

定义SD卡的物理驱动器号为0。

修改 disk_status函数,该函数主要是用来获取磁盘状态。现在未用到,可以直接函数体内代码删除。

修改截图:

代码示例:

#include "diskio.h" /* fatf底层API */

#include "sd.h" /* SD卡驱动头文件 */

/* 定义每个驱动器的物理驱动器号*/

#define SD 0

/* 获取设备(磁盘)状态 */

DSTATUS disk_status (

BYTE pdrv /* 物理驱动识别 */

return 0; //该函数现在无需用到,直接返回0

修改disk_initialize函数,添加SD卡的初始化,其他不用到的代码直接删掉,该函数成功返回0,失败返回1。

修改截图:

代码示例:

/* 初始化磁盘驱动 */

DSTATUS disk_initialize (

BYTE pdrv /* 物理驱动识别 */

DSTATUS stat;

int result;

switch (pdrv) {

case SD : //选择SD卡

stat=SD_Init(); //初始化SD卡-用户自己提供

if(stat)return STA_NOINIT; //磁盘未初始化

return 0; //初始化成功

修改disk_read函数,加入SD卡读任意扇区的函数(需要用户自己提供),其他不用到的选项可以删掉。

修改代码如下:

/* 读扇区 */

DRESULT disk_read (

BYTE pdrv, /* 物理驱动编号 - 范围0-9*/

BYTE *buff, /* 数据缓冲区存储读取数据 */

DWORD sector, /* 扇区地址*/

UINT count /* 需要读取的扇区数*/

DRESULT res;

int result;

switch (pdrv) {

case SD:

res=SD_Read_Data((u8*)buff,sector,count); //读SD扇区函数--用户提供

return res; //在此处可以判错误

return RES_PARERR; //无效参数

修改disk_write 函数,添加写扇区函数:

代码:

/* 写扇区 */

#if _USE_WRITE

DRESULT disk_write (

BYTE pdrv, /* 物理驱动号*/

const BYTE *buff, /* 要写入数据的首地址 */

DWORD sector, /* 扇区地址 */

UINT count /* 扇区数量*/

DRESULT res;

int result;

switch (pdrv) {

case SD:

res=SD_Write_Data((u8*)buff,sector,count); //写入扇区

return res;

return RES_PARERR; //无效参数

#endif

修改disk_ioctl 函数,填充ioctl命令功能。这些功能是标准的命令,在diskio.h有定义。

代码如下:

/* 其他函数 */

#if _USE_IOCTL

DRESULT disk_ioctl (

BYTE pdrv, /* 物理驱动号 */

BYTE cmd, /* 控制码 */

void *buff /* 发送/接收数据缓冲区地址 */

DRESULT res;

int result;

switch (pdrv) {

case SD:

switch(cmd)

case CTRL_SYNC: //等待写过程

SD_CS(0); //选中SD卡

if(SD_Wait_Ready())result = RES_ERROR;/*等待卡准备好*/

else res = RES_OK; //成功

SD_CS(1); //释放SD卡

break;

case GET_SECTOR_SIZE://获取扇区大小

*(DWORD*)buff = 512;

res = RES_OK; //成功

brea

微信