一、简介
本节主要分析一个SD卡读写程序。程序简单的完成FATFS文件系统对SD卡进行写入和读出校验。
二、程序设计
使用PS端SD卡首先要在VIVADO软件中根据板卡实际情况选中SD卡外设如下图:

导出硬件设置到VITIS,在BSP中选中xilff:

程序全文如下:
cs
#include "xparameters.h"
#include "xil_printf.h"
#include "ff.h"
#include "xdevcfg.h"
TCHAR *Path = "0:/";
int main()
{
FATFS fs0; /* Work area (filesystem object) for logical drives */
FIL fdst; /* File objects */
BYTE wbuffer[]="this is a write operation test. \r\n"; /* File copy buffer */
BYTE wbuffer2[]="hello world! \r\n";
BYTE rbuffer[1000];
FRESULT fr; /* FatFs function common result code */
UINT br,bw; /* File read/write count */
BYTE work[FF_MAX_SS];
/* Give work areas to each logical drive */
fr = f_mount(&fs0, "0:", 0);
if(fr != FR_OK){
fr = f_mkfs(Path, 0, 0,work, sizeof work);
if(fr != FR_OK)xil_printf("SD mount NOT found!\r\n!");
else{
fr = f_mount(&fs0, "0:", 0);
if(fr != FR_OK){
xil_printf("SD initial done but mount failed!\r\n!");
}
else
xil_printf("SD mount successes\r\n!");
}
}
else xil_printf("SD mount successed\r\n!");
fr = f_open(&fdst, "test.txt", FA_WRITE | FA_CREATE_ALWAYS);
if ((fr != FR_OK)) xil_printf("SD open failed\r\n!");
else xil_printf("SD open file successes\r\n!");
br = strlen(wbuffer);
fr = f_write(&fdst, wbuffer, br, &bw); /* Write it to the destination file */
f_lseek(&fdst,100);
br = strlen(wbuffer2);
fr = f_write(&fdst, wbuffer2, br, &bw);
f_close(&fdst); //必须要有close操作
f_open(&fdst,"test.txt",FA_READ);
fr = f_read(&fdst, rbuffer, br, &bw);
f_close(&fdst);
f_unmount(Path);
for (;;) ;
}
三、程序分析
由于SD卡读写程序采用了FATFS 文件系统,其包含的API函数因为比较复杂,做深度分析困难。从使用角度来看,实际上只需要知道API函数实现的功能是什么,怎么使用即可,不知道这个功能怎么一步一步实现的并不影响调用,为了避免盲目分析浪费时间,本文只分析函数的使用方式,不再进一步分析函数如何实现。
3.1、程序流程分析
和其他外设类似,SD卡先挂载,然后写入,最后读出。首先函数通过f_mount函数挂载SD卡。挂载程序执行后程序会检查挂在是否成功,如果不成功会尝试通过f_mkfs函数对SD卡进行格式化,格式化之后再尝试挂载。挂载结束后,执行f_open函数打开txt文件,如果没有找到txt文件系统会创建该文件。完成打开文件操作后利用f_write写入像写入的字符串,由于f_write函数需要写入长度的变量所以先调用strlen库函数检测写入字符串的长度。本次要分两次写入所以还调用了f_lseek调整写入的位置。然后故技重施再次测量长度,和写入新的字符串。把第二行字符串写入之后关闭文件(注意必须要有此操作,否则字符串写不进去)。关闭后再次打开文件,打开文件后调用f_read函数读出字符串,然后再次调用f_close函数关闭文件,最后用f_unmount函数进行注销操作。
3.2、相关函数分析
- f_mount函数
f_mount 函数用于挂载SD卡,为 FatFs 模块提供工作区。函数原型如下:
cpp
FRESULT f_mount (
FATFS* fs, /* [IN] Filesystem object */
const TCHAR* path, /* [IN] Logical drive number */
BYTE opt /* [IN] Initialization option */
);
挂载的作用就是用来注册工作区。其具有三个形参:
fs:工作区地址,类似于其他外设的设备句柄,保存FAT 表信息,当前目录信息,锁状态,其他文件系统运行状态等信息。
path:逻辑驱动器,一般SD卡是0:
opt:挂载类型。0:延迟挂载。只登记,不真正检查物理盘。1:强制立即挂载。现在就检查物理盘、找 FAT 文件系统。
- f_mkfs函数
f_mkfs用于格式化SD卡,函数原型如下:
cpp
FRESULT f_mkfs (
const TCHAR* path, /* [IN] Logical drive number */
const MKFS_PARM* opt,/* [IN] Format options */
void* work, /* [-] Working buffer */
UINT len /* [IN] Size of working buffer */
);
path :逻辑驱动器,比如 "0:"、"0:/"。不写驱动器号则用默认盘。
opt :格式化选项,BYTE 类型。常用值:FM_FAT、FM_FAT32、FM_EXFAT、FM_ANY、 FM_SFD。传 0 一般表示默认。
au :簇大小,单位字节。传 0 表示让函数根据卷大小自动选择。
Work: 工作缓冲区指针。格式化过程中会用它做临时数据缓冲。
len :工作缓冲区大小,单位字节。至少需要 FF_MAX_SS(通常是 512 或 4096)。越大格式化越快
- f_open函数
f_open 是 FatFs 中用于打开或创建文件的核心函数。原型如下:
cpp
FRESULT f_open (
FIL* fp, /* 指向空白文件对象的指针 */
const TCHAR* path, /* 文件路径 */
BYTE mode /* 打开模式标志 */
);
返回值:FRESULT 类型,FR_OK 表示成功,其他值表示各种错误。
mode 标志详解
mode 分为两类:访问模式 和打开模式 。必须至少指定一个访问模式(FA_READ 或 FA_WRITE)。
访问模式
-
fp:必须是一个已分配的FIL结构体变量。打开成功后,它代表被打开的文件,后续f_read、f_write、f_close等都要用它。 -
path:文件路径,可包含驱动器号和目录,例如"0:/dir/file.txt"。如果不写驱动器号,则使用默认驱动器。 -
mode:指定访问模式和打开方式,由多个标志按位或组成。
| 标志 | 含义 |
|---|---|
FA_READ |
允许读 |
FA_WRITE |
允许写 |
打开模式
| 标志 | 含义 |
|---|---|
FA_OPEN_EXISTING |
打开已存在文件,若不存在则失败(默认,通常不显式写) |
FA_CREATE_NEW |
创建新文件,若已存在则返回 FR_EXIST |
FA_CREATE_ALWAYS |
创建新文件,若已存在则覆盖(截断为 0 字节) |
FA_OPEN_ALWAYS |
打开文件,若不存在则创建 |
FA_OPEN_APPEND |
打开文件,若不存在则创建,并将文件指针移到末尾(用于追加) |
常用组合
只读打开:FA_READ
只写打开并覆盖:FA_WRITE | FA_CREATE_ALWAYS
读写打开,不存在则创建:FA_READ | FA_WRITE | FA_OPEN_ALWAYS
创建新文件,存在则失败:FA_WRITE | FA_CREATE_NEW
追加写入:FA_WRITE | FA_OPEN_APPEND
f_write函数
f_write 是 FatFs 中用于向已打开文件写入数据的核心函数。函数原型如下
cpp
FRESULT f_write (
FIL* fp, /* 指向已打开文件对象的指针 */
const void* buff, /* 指向要写入的数据缓冲区 */
UINT btw, /* 要写入的字节数 */
UINT* bw /* 输出:实际写入的字节数 */
);
fp :必须是通过 f_open 成功打开、且以 FA_WRITE 模式打开的文件对象。
buff:要写入的数据缓冲区首地址。
btw:希望写入的字节数。
bw :指向 UINT 变量的指针,函数返回后,该变量保存实际写入的字节数
- f_read 函数函数
f_read 是 FatFs 中用于从已打开文件读取数据的核心函数,原型如下
cpp
FRESULT f_read (
FIL* fp, /* 指向已打开文件对象的指针 */
void* buff, /* 指向接收数据的缓冲区 */
UINT btr, /* 请求读取的字节数 */
UINT* br /* 输出:实际读取的字节数 */
);
-
fp:必须是通过f_open成功打开、且以FA_READ模式打开的文件对象。 -
buff:用于存放读取数据的缓冲区首地址。 -
btr:希望读取的字节数。 -
br:指向UINT变量的指针,函数返回后保存实际读取的字节数。
返回值:FRESULT,FR_OK 表示成功(但不一定读满 btr 字节,需检查 *br)
常见返回值
| 返回值 | 含义 |
|---|---|
FR_OK |
成功,实际读取字节数看 *br |
FR_DENIED |
文件未以读模式打开 |
FR_INVALID_OBJECT |
文件对象无效或未打开 |
FR_DISK_ERR |
底层磁盘读错误 |
FR_INT_ERR |
内部错误(如 FAT 损坏、簇链异常) |
FR_NOT_ENOUGH_CORE |
内存不足(较少见) |
函数运行结果如下
