一、FatFs简介

FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统。它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质。因此它可以很容易地不加修改地移植到其他的处理器当中,如 8051、PIC、AVR、SH、Z80、H8、ARM 等。FatFs 支持 FAT12、FAT16、FAT32 等格式,所以我们利用前面写好的 SPI Flash 芯片驱动,把 FatFs 文件系统代码移植到工程之中,就可以利用文件系统的各种函数,对 SPI Flash 芯片以“文件”格式进行读写操作了。

FatFs 文件系统的源码可以从 fatfs 官网下载:
http://elm-chan.org/fsw/ff/00index_e.html

1.1 FatFs文件系统布局

簇是文件存储的最小单元,FAT32分区大小与对应簇空间大小关系如下表示:

分区空间大小 簇空间大小 每个簇包含的扇区数
< 8GB 4KB 8
[ 8GB, 16GB ) 8KB 16
[ 16GB, 32GB ) 16KB 32
>= 32GB 32KB 64

例如:创建一个50字节的test.txt文件,文件大小是50字节,但是占用磁盘空间为4096字节(一个簇)

1.2 FatFs层次结构

  • 最顶层是应用层:使用者只需要调用FATFS模块提供给用户的一系列应用接口函数(如f_open, f_read, f_write和f_close等),就可以像在PC上读写文件那样简单

  • 中间层FATFS模块:实现了FAT文件读写协议;它提供了ff.c和ff.h文件,一般情况下不用修改,使用时将头文件包含进去即可

  • 最底层是FATFS模块的底层接口:包括存储媒介读写接口和供给文件创建修改时间的实时时钟,需要在移植时编写对应的代码

FATFS源码相关文件介绍如下表示;移植FATFS模块时,一般只需要修改2个文件(即ffconf.hdiskio.c

与平台无关:

文件 说明
ffconf.h FATFS模块配置文件
ff.h FATFS和应用模块公用的包含文件
ff.c FATFS模块
diskio.h FATFS和disk I/O模块公用的包含文件
interger.h 数据类型定义
option 可选的外部功能(比如支持中文)

与平台相关:

文件 说明
diskio.c FATFS和disk I/O模块接口层文件

1.3 FatFs API

1.3.1 f_mount

功能 在FatFs模块上注册、注销一个工作区(文件系统对象)
函数定义 FRESULT f_mount(FATFS* fs, const TCHAR* path, BYTE opt)
参数 fs:工作区(文件系统对象)指针
path:注册/注销工作区的逻辑驱动器号
opt:注册或注销选项
返回 操作结果

1.3.2 f_open

功能 创建/打开一个文件对象
函数定义 FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode)
参数 fp:将被创建的文件对象结构的指针
path:文件名指针,指定将创建或打开的文件名
mode:访问类型和打开方法,由一下标准的一个组合指定的
返回 操作结果
模式 描述
FA_READ 指定读访问对象。可以从文件中读取数据。 与FA_WRITE 结 合可以进行读写访问。
FA_WRITE 指定写访问对象。可以向文件中写入数据。与FA_READ 结合 可以进行读写访问。
FA_OPEN_EXISTING 打开文件。如果文件不存在,则打开失败。(默认)
FA_OPEN_ALWAYS 如果文件存在,则打开;否则,创建一个新文件。
FA_CREATE_NEW 创建一个新文件。如果文件已存在,则创建失败。
FA_CREATE_ALWAYS 创建一个新文件。如果文件已存在,则它将被截断并覆盖。

1.3.3 f_close

功能 关闭一个打开的文件
函数定义 FRESULT f_close(FIL* fp)
参数 fp:指向将被关闭的已打开的文件对象结构的指针
返回 操作结果

1.3.4 f_read

功能 从一个打开的文件中读取数据
函数定义 FRESULT f_read(FIL* fp, void* buff, UINT btr, UINT* br)
参数 fp:指向将被读取的已打开的文件对象结构的指针
buff:指向存储读取数据的缓冲区的指针
btr:要读取的字节数
br:指向返回已读取字节数的UINT变量的指针,返回为实际读取的字节数
返回 操作结果

1.3.5 f_write

功能 写入数据到一个已打开的文件
函数定义 FRESULT f_write(FIL* fp, void* buff, UINT btw, UINT* bw)
参数 fp:指向将被写入的已打开的文件对象结构的指针
buff:指向存储写入数据的缓冲区的指针
btw:要写入的字节数
bw:指向返回已写入字节数的UINT变量的指针,返回为实际写入的字节数
返回 操作结果

另外FatFs还有很多API操作函数,在这里不再作详细的介绍,详细信息请查看FatFs文件系统官网。

二、新建工程

1. 打开 STM32CubeMX 软件,点击“新建工程”

2. 选择 MCU 和封装

3. 配置时钟
RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)

选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置

4. 配置调试模式
非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
SYS 设置,选择 Debug 为 Serial Wire

三、SDIO

STM32 控制器可以控制使用单线或 4 线传输,本开发板设计使用 4 线传输。

3.1 参数配置

Connetivity 中选择 SDIO 设置,并选择 SD 4 bits Wide bus 四线SD模式

此时 SDIO 对应的管脚也被选中。

Parameter Settings 进行具体参数配置。

Clock transition on which the bit capture is made: Rising transition。主时钟 SDIOCLK 产生 CLK 引脚时钟有效沿选择,可选上升沿或下降沿,它设定 SDIO 时钟控制寄存器(SDIO_CLKCR)的 NEGEDGE 位的值,一般选择设置为上升沿

SDIO Clock divider bypass: Disable。时钟分频旁路使用,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 BYPASS 位。如果使能旁路,SDIOCLK 直接驱动 CLK 线输出时钟;如果禁用,使用 SDIO_CLKCR 寄存器的 CLKDIV 位值分频 SDIOCLK,然后输出到 CLK 线。一般选择禁用时钟分频旁路

SDIO Clock output enable when the bus is idle: Disable the power save for the clock。节能模式选择,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 PWRSAV 位的值。如果使能节能模式,CLK 线只有在总线激活时才有时钟输出;如果禁用节能模式,始终使能 CLK 线输出时钟。

SDIO hardware flow control: The hardware control flow is disabled。硬件流控制选择,可选使能或禁用,它设定 SDIO_CLKCR 寄存器的 HWFC_EN 位的值。硬件流控制功能可以避免 FIFO 发送上溢和下溢错误。

SDIOCLK clock divide factor: 6。时钟分频系数,它设定 SDIO_CLKCR 寄存器的 CLKDIV 位的值,设置 SDIOCLK 与 CLK 线输出时钟分频系数:CLK 线时钟频率=SDIOCLK/([CLKDIV+2])。

SDIO_CK 引脚的时钟信号在卡识别模式时要求不超过 400KHz,而在识别后的数据传输模式时则希望有更高的速度(最大不超过 25MHz),所以会针对这两种模式配置 SDIOCLK 的时钟。

这里参数描述建议将SDIOCLK clock divede factor 参数使用默认值为0,SDIOCLK为72MHz,可以得到最大频率36MHz,但请注意,有些型号的SD卡可能不支持36MHz这么高的频率,所以还是要以实际情况而定。

3.2 配置DMA

SDIO 外设支持生成 DMA 请求,使用 DMA 传输可以提高数据传输效率,因此在 SDIO 的控制代码中,可以把它设置为 DMA 传输模式或轮询模式,ST 标准库提供 SDIO 示例中针对这两个模式做了区分处理。应用中一般都使用DMA 传输模式。

点击 DMA Settings 添加 SDIO 对应 DMA2 的通道4。DMA模式选择循环模式,方向选为内存到外设。

  • Priority
    当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理 DMA 通道请求分为两个阶段。第一阶段属于软件阶段,可以在 DMA_CCRx 寄存器中设置,有 4 个等级:非常高、高、中和低四个优先级。第二阶段属于硬件阶段,如果两个或以上的 DMA 通道请求设置的优先级一样,则他们优先级取决于通 道编号,编号越低优先权越高,比如通道 0 高于通道 1。在大容量产品和互联型产品中,DMA1 控制器拥有高于 DMA2 控制器的优先级。
  • Mode
    Normal 表示单次传输,传输一次后终止传输。
    Circular 表示循环传输,传输完成后又重新开始继续传输,不断循环永不停止。
  • Increment Address
    Peripheral 表示外设地址自增。
    Memory 表示内存地址自增。
  • Data Width
    Byte 一个字节。
    Half Word 半个字,等于两字节。
    Word 一个字,等于四字节。

3.3 配置NVIC

DMA及SDIO中断设置,原则是全局中断优先级高于DMA中断

四、FATFS

4.1 参数配置

Middleware 中选择 FATFS 设置,并勾选 SD Card 配置为SD卡

  • Function Parameters 跳过

  • Locale and Namespace Parameters:

    • CODE_PAGE(Code page on target): Simplified Chinese GBK(DBCS,OEM,Windows) 支持简体中文编码
    • USE_LFN(Use Long Filename): Enabled with dynamic working buffer on the STACK 支持长文件名,并指定使用栈空间为缓冲区

缓存工作区为什么放在栈?其实fatfs提供了三个选项:BSS,STACK , HEAP,根据个人情况选一个。
在BSS上启用带有静态工作缓冲区的LFN,不能动态分配。
如果选择了HEAP(堆)且自己有属于自己的malloc就去重写ff_memalloc  ff_memfree函数。如果是库的malloc就不需要。
一般都选择使用STACK(栈),能动态分配。
当使用堆栈作为工作缓冲区时,请注意堆栈溢出。

  • Physical Drive Parameters:

    • VOLUMES(Logical drivers): 2 指定物理设备数量,这里设置为 2,包括预留 SD 卡和 SPI Flash 芯片
    • MAX_SS(Maximum Sector Size): 512 指定扇区大小的最大值。SD 卡扇区大小一般都为 512 字节,SPI Flash 芯片扇区大小一般设置为 4096 字节,所以需要把 _MAX_SS 改为 512
    • MIN_SS(Minimum Sector Size): 512 指定扇区大小的最小值

4.2 配置SD卡检测引脚

SD卡插入检测引脚,如果不配置一个引脚生成文件时会报错,所以这里即使没有硬件连接,也可以任意设置一引脚使用,生成工程后注释代码。

4.3 增大栈空间

将最小栈空间改到 0x1000

注意:由于刚才设置长文件名动态缓存存储在堆中,故需要增大堆大小,如果不修改则程序运行时堆会生成溢出,程序进入硬件错误中断(HardFault),死循环。

4.4 生成代码

输入项目名和项目路径

选择应用的 IDE 开发环境 MDK-ARM V5

每个外设生成独立的 ’.c/.h’ 文件
不勾:所有初始化代码都生成在 main.c
勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。

点击 GENERATE CODE 生成代码

五、屏蔽SD卡插入检测代码

由于没有检测SD卡插入的硬件引脚,打开 bsp_driver_sd.c 文件,修改 BSP_SD_IsDetected() 函数,始终返回SD_PRESENT:

六、修改main函数

定义相关变量:

FATFS fs;                       /* FatFs 文件系统对象 */
FIL file;                       /* 文件对象 */
FRESULT f_res;                  /* 文件操作结果 */
UINT fnum;                      /* 文件成功读写数量 */
BYTE ReadBuffer[1024] = {0};    /* 读缓冲区 */
BYTE WriteBuffer[] =            /* 写缓冲区 */"This is STM32 working with FatFs\r\n";

修改main函数:

/*** @brief  The application entry point.* @retval int*/
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_DMA_Init();MX_USART1_UART_Init();MX_SDIO_SD_Init();MX_FATFS_Init();/* USER CODE BEGIN 2 */printf("\r\n****** FatFs Example ******\r\n\r\n");//在外部 SD 卡挂载文件系统,文件系统挂载时会对 SD 卡初始化f_res = f_mount(&fs, "0:", 1);/*----------------------- 格式化测试 ---------------------------*/printf("\r\n****** Register the file system object to the FatFs module ******\r\n");/* 如果没有文件系统就格式化创建创建文件系统 */if(f_res == FR_NO_FILESYSTEM){printf("The SD card does not yet have a file system and is about to be formatted...\r\n");/* 格式化 */f_res = f_mkfs("0:", 0, 0);if(f_res == FR_OK){printf("The SD card successfully formatted the file system\r\n");/* 格式化后,先取消挂载 */f_res = f_mount(NULL, "0:", 1);/* 重新挂载 */f_res = f_mount(&fs, "0:", 1);}else{printf("The format failed\r\n");while(1);}       }else if(f_res != FR_OK){printf(" mount error : %d \r\n", f_res);while(1);}else{printf(" mount sucess!!! \r\n");}/*----------------------- 文件系统测试:写测试 -----------------------------*//* 打开文件,如果文件不存在则创建它 */printf("\r\n****** Create and Open new text file objects with write access ******\r\n");f_res = f_open(&file, "0:FatFs STM32cube.txt", FA_CREATE_ALWAYS | FA_WRITE);if(f_res == FR_OK){printf(" open file sucess!!! \r\n");/* 将指定存储区内容写入到文件内 */printf("\r\n****** Write data to the text files ******\r\n");f_res = f_write(&file, WriteBuffer, sizeof(WriteBuffer), &fnum);if(f_res == FR_OK){printf(" write file sucess!!! (%d)\n", fnum);printf(" write Data : %s\r\n", WriteBuffer);}else{printf(" write file error : %d\r\n", f_res);}/* 不再读写,关闭文件 */f_close(&file);}else{printf(" open file error : %d\r\n", f_res);}/*------------------- 文件系统测试:读测试 ------------------------------------*/printf("\r\n****** Read data from the text files ******\r\n");f_res = f_open(&file, "0:FatFs STM32cube.txt", FA_OPEN_EXISTING | FA_READ);if(f_res == FR_OK){printf(" open file sucess!!! \r\n");f_res = f_read(&file, ReadBuffer, sizeof(ReadBuffer), &fnum);if(f_res == FR_OK){printf("read sucess!!! (%d)\n", fnum);printf("read Data : %s\r\n", ReadBuffer);}else{printf(" read error!!! %d\r\n", f_res);}}else{printf(" open file error : %d\r\n", f_res);}/* 不再读写,关闭文件 */f_close(&file);/* 不再使用文件系统,取消挂载文件系统 */f_mount(NULL, "0:", 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 */
}

七、查看打印

串口打印功能查看 STM32CubeMX学习笔记(6)——USART串口使用

八、工程代码

链接:https://pan.baidu.com/s/1kgJ7AmbnW89yHcrgBzD_1w 提取码:kg5a

九、注意事项

f_open、f_write、f_read如果偶尔有问题;f_mkfs报错 FS_DISK_ERR,可以加上了SDIO硬件流使能试试。

用户代码要加在 USER CODE BEGIN NUSER CODE END N 之间,否则下次使用 STM32CubeMX 重新生成代码后,会被删除。


• 由 Leung 写于 2021 年 12 月 7 日

• 参考:STM32CubeMX系列教程18:文件系统FATFS
    STM32CubeMX系列|FATFS文件系统
    1.6 Cubemx_STM32F103_NOOS SDIO_DMA_FATFS基于SD卡的FATFS测试(一)
    【STM32Cube_20】在SD卡上移植FATFS文件系统
    STM32CubeMX之SD卡+FatFs

STM32CubeMX学习笔记(27)——FatFs文件系统使用(操作SD卡)相关推荐

  1. 利用fatfs文件系统实现了SD卡追加…

    原帖地址:http://www.amobbs.com/thread-5537678-1-1.html 在fatfs文件系统下,实现SD卡的读取追加内容,实现方法是:读取文件.偏移指针.填写内容.追加内 ...

  2. STM32CubeMX学习笔记(25)——FatFs文件系统使用(操作SPI Flash)

    一.FatFs简介 FatFs 是面向小型嵌入式系统的一种通用的 FAT 文件系统.它完全是由 ANSI C 语言编写并且完全独立于底层的 I/O 介质.因此它可以很容易地不加修改地移植到其他的处理器 ...

  3. STM32CubeMX学习笔记(24)——通用定时器接口使用(电容按键检测)

    一.电容按键简介 电容器(简称为电容)就是可以容纳电荷的器件,两个金属块中间隔一层绝缘体就可以构成一个最简单的电容.如图 32-1(俯视图),有两个金属片,之间有一个绝缘介质,这样就构成了一个电容.这 ...

  4. STM32CubeMX学习笔记(38)——FSMC接口使用(TFT-LCD屏显示)

    一.TFT-LCD简介 TFT-LCD(Thin Film Transistor-Liquid Crystal Display) 即薄膜晶体管液晶显示器.TFT-LCD 与无源 TN-LCD. STN ...

  5. STM32CubeMX学习笔记(9)——I2C接口使用(读写EEPROM AT24C02)

    一.I2C简介 I2C(Inter-Integrated Circuit ,内部集成电路) 总线是一种由飞利浦 Philip 公司开发的串行总线.是两条串行的总线,它由一根数据线(SDA)和一根 时钟 ...

  6. STM32CubeMX学习笔记(22)——CRC接口使用

    一.CRC简介 CRC(Cyclic Redundancy Check),即循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者 ...

  7. STM32CubeMX学习笔记——STM32H743_硬件I2C

    STM32CubeMX学习笔记--STM32H743_硬件I2C Github STM32CubeMX配置 Pinout配置 GPIO Clock Configuration配置 代码部分 main. ...

  8. STM32CubeMX学习笔记(28)——FreeRTOS实时操作系统使用(任务管理)

    一.FreeRTOS简介 FreeRTOS 是一个可裁剪.可剥夺型的多任务内核,而且没有任务数限制.FreeRTOS 提供了实时操作系统所需的所有功能,包括资源管理.同步.任务通信等. FreeRTO ...

  9. STM32CubeMX学习笔记(49)——USB接口使用(MSC基于SD卡模拟U盘)

    一.USB简介 USB(Universal Serial BUS)通用串行总线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯.是应用在 PC 领域的接口技术.USB 接口支持设备的即插即用和 ...

最新文章

  1. 车联网,挖掘数据价值
  2. JAVA里tokens意思_Java TokenMetadata.sortedTokens方法代码示例
  3. Java如何让小球随机运动_用java模拟两球的随机运动及碰撞
  4. 动态库与静态库优缺点比较(转 侵删)
  5. 固定速率与固定延迟– RxJava常见问题解答
  6. 70 个常见 Spring 面试题,Java 晋升必会
  7. kali linux学习入门- Chrome浏览器安装,可以正常打开
  8. 服务器主板点不亮排查
  9. WPF Popup 相关内容
  10. python制作二维码
  11. poj 1681 Painter's Problem (高斯消元 )
  12. L2-004. 这是二叉搜索树吗?-PAT团体程序设计天梯赛GPLT
  13. 华为OSPF多区域+路由重发布/路由引入
  14. 手机的尺寸、分辨率、像素密度的关系
  15. 【Python实用工具】查询本机IP地址
  16. 比较不错的MaciOS软件论坛
  17. matlab/simulink电力电子仿真斜坡信号Ramp设置和使用
  18. 注册表知识:HKEY_LOCAL_MACHINE根键详解
  19. 如何用电话扩大Android内存,扩大内存 Android开启App2SD+教程
  20. python发微信红包_微信现金红包 python

热门文章

  1. java根据远程URL获取文件类型
  2. 3个月成功上岸中科大MBA切身经历
  3. [嵌入式开发模块]通用接收状态机模块
  4. 中心差分法matlab实现,动力学系统时域响应计算的六种方法Matlab源程序(Newmark,Houbolt法,中心差分法)...
  5. 使用vscode + gcc进行 STM32 单片机开发(三)DMA读写SD卡,移植FATFS文件系统
  6. 2023年最新国产芯片生态图谱
  7. CSP-S 2020莫得游记
  8. NRF905 无线模块实验
  9. 【张尧学与一等奖】中国科技奖励之我见
  10. Dreamweaver配置php站点,Dreamweaver站点配置与本地测试