前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >STM32Cube-20(补充) | 在SD卡上移植FATFS文件系统

STM32Cube-20(补充) | 在SD卡上移植FATFS文件系统

作者头像
Mculover666
发布2020-07-16 11:43:53
2K0
发布2020-07-16 11:43:53
举报
文章被收录于专栏:TencentOS-tinyTencentOS-tiny

1. 准备工作

硬件准备

  • 开发板 首先需要准备一个开发板,这里我准备的是STM32L4的开发板(BearPi):
  • Micro SD卡 小熊派开发板板载 Micro SD 卡槽,需要提前自行准备一张 Micro SD卡,如图:

软件准备

  • 需要安装好Keil - MDK及芯片对应的包,以便编译和下载生成的代码;
  • 准备一个串口调试助手,这里我使用的是Serial Port Utility

Keil MDK和串口助手Serial Port Utility 的安装包都可以在文末关注公众号获取,回复关键字获取相应的安装包:

2.创建CubeMX工程

选择芯片型号

打开STM32CubeMX,打开MCU选择器:

搜索并选中芯片STM32L431RCT6:

配置时钟源

  • 如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
  • 如果使用默认内部时钟(HSI),这一步可以略过;

这里我都使用外部时钟:

配置串口

小熊派开发板板载ST-Link并且虚拟了一个串口,原理图如下:

这里我将开关拨到AT-MCU模式,使PC的串口与USART1之间连接。

接下来开始配置USART1

配置 SDMMC 接口

知识小卡片 —— SDMMC接口

SDMMC接口的全称叫SD/SDIO MMC card host interface,SD/SDIO MMC 卡 主机接口,通俗的来说,就是这个接口支持SD卡,支持SDIO设备,支持MMC卡。

知识小卡片结束啦~

首先查看小熊派开发板的原理图:

然后根据原理图配置 SDMMC 接口:

配置FATFS文件系统

使用STM32CubeMX配置FATFS文件系统非常方便,只需要在软件中开启即可,软件会自动帮我们移植好。

这里需要修改两个配置:

  • 开启文件名支持简体中文;
  • 开启长文件名支持,并将长文件名动态缓存在栈中(普通文件名最多8个字节,开启长文件名支持后可达255个字节)

配置时钟树

STM32L4的最高主频到80M,所以配置PLL,最后使HCLK = 80Mhz即可:

生成工程设置

因为之前开启FATFS选择了长文件名动态缓存在栈中,所以我们要将栈空间修改大一点:

代码生成设置

最后设置生成独立的初始化文件:

生成代码

点击GENERATE CODE即可生成MDK-V5工程:

3. 在MDK中编写、编译、下载用户代码

重定向printf( )函数

参考:【STM32Cube_09】重定向printf函数到串口输出的多种方法

SD卡分区并格式化为FAT文件系统

正常SD卡不需要该步骤!

如果已经使用SD卡进行了裸机读写SD卡的实验,那么需要注意:该实验中读写的是0扇区,实验之后已经破坏了SD卡的分区表和FAT文件系统信息

重新建立SD卡的分区表和FAT文件系统有两种方法:

  • 使用FATFS提供的API
  • 在PC上直接格式化
  • 在PC上使用DiskGenius软件重新分区和格式化

这里我使用第二种方法,比较简单方便,如果对FATFS提供的API感兴趣,请前去FATFS官网查看:

首先使用读卡器将SD卡插到电脑上,会显示如下:

然后直接右键选择格式化:

如果第二种方法没用的话,可以使用第三种方法,来打开 DiskGenius 软件查看SD卡:

重新建立分区表并格式化:

之后可以看到SD卡恢复正常,可以进行FATFS实验啦:

使用FATFS挂载SD卡

注意:在挂载之前必须要保证SD卡正常拥有FAT文件系统。

挂载文件系统使用f_mount API,该API将文件系统对象注册/注销到FatFs模块,API原型如下:

FRESULT f_mount (
  FATFS*       fs,    /* [IN] Filesystem object */
  const TCHAR* path,  /* [IN] Logical drive number */
  BYTE         opt    /* [IN] Initialization option */
);

在main.c文件中添加如下代码,先定义FATFS所使用的一些全局变量:

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

/* USER CODE BEGIN PV */
FATFS   fs;            /* FATFS 文件系统对象 */
FRESULT fr;         /* FATFS API 返回值 */
/* USER CODE END PV */

然后在 main 函数中,while(1)之前添加如下代码:

/* USER CODE BEGIN 2 */
printf("FATFS test...\r\n");
/* 挂载SD卡 */
fr = f_mount(&fs, "", 0);
if(fr == FR_OK)
{
    printf("SD card mount ok!\r\n");
}
else
{
    printf("SD card mount error, error code:%d.\r\n",fr);
}
/* USER CODE END 2 */

编译下载,运行结果如下:

创建文件并向文件中写入内容

要想操作文件,需要先创建文件对象:

/* USER CODE BEGIN PV */
FATFS   fs;         /* FATFS 文件系统对象 */
FRESULT fr;         /* FATFS API 返回值 */
FIL     fd;         /* FATFS 文件对象    */
/* USER CODE END 2 */

在main函数中的开始定义要写入文件的内容:

/* USER CODE BEGIN 1 */
//要操作的文件名
char filename[] = "test.txt";
//文件写入内容
uint8_t write_dat[] = "Hello,FATFS!\n";
//用于接收API返回写入成功的字节数
uint16_t write_num = 0;
/* USER CODE END 1 */

然后在挂载操作成功之后进行打开->写入->关闭一个完整的操作:

/* 打开文件(若文件不存在则创建) */
fr = f_open(&fd, filename, FA_CREATE_ALWAYS | FA_WRITE);
if(fr == FR_OK)
{
    printf("open file \"%s\" ok! \r\n", filename);
}
else
{
printf("open file \"%s\" error : %d\r\n", filename, fr);
}

/* 向打开的文件中写入内容 */
fr = f_write(&fd, write_dat, sizeof(write_dat), (void *)&write_num);
if(fr == FR_OK)
{
    printf("write %d dat to file \"%s\" ok,dat is \"%s\".\r\n", write_num, filename, write_dat);
}
else
{
    printf("write dat to file \"%s\" error,error code is:%d\r\n", filename, fr);
}

/* 操作完成,关闭文件 */
fr = f_close(&fd);
if(fr == FR_OK)
{
    printf("close file \"%s\" ok!\r\n", filename);
}
else
{
    printf("close file \"%s\" error, error code is:%d.\r\n", filename, fr);
}

实验结果如下:

再将SD卡插到电脑,可以看到文件及其内容:

读取SD卡中的文件内容

同样的,先在main函数开始开辟一块缓冲区,用于存放读取的数据:

/* USER CODE BEGIN 1 */
//要操作的文件名
char filename[] = "test.txt";
//文件写入内容
uint8_t write_dat[] = "Hello,FATFS!";
//用于接收API返回写入成功的字节数
uint16_t write_num = 0;

//用于存放从文件中读取出的内容
uint8_t read_dat[20];
//用于接收API返回成功读取的字节数
uint16_t read_num = 0;
/* USER CODE END 1 */

然后进行打开->读取->关闭一个完整的操作:

/* 打开文件用于读取 */
fr = f_open(&fd, filename, FA_READ);
if(fr == FR_OK)
{
    printf("open file \"%s\" ok! \r\n", filename);
}
else
{
printf("open file \"%s\" error : %d\r\n", filename, fr);
}

/* 从打开的文件中读取内容 */
fr = f_read(&fd, read_dat, sizeof(read_dat), (void *)&read_num);
if(fr == FR_OK)
{
    printf("read %d dat to file \"%s\" ok,dat is \"%s\".\r\n", read_num, filename, read_dat);
}
else
{
    printf("read dat to file \"%s\" error,error code is:%d\r\n", filename, fr);
}

/* 操作完成,关闭文件 */
fr = f_close(&fd);
if(fr == FR_OK)
{
    printf("close file \"%s\" ok!\r\n", filename);
}
else
{
    printf("close file \"%s\" error, error code is:%d.\r\n", filename, fr);
}

实验现象如下:

FATFS API 错误码的使用

不知道大家有没有注意到,在本文中所有使用FATFS API的时候,都是如下的格式:

  • 使用FRESULT类型的变量fr接收API返回值
  • API执行之后进行判断,错误的话输出错误码

那么,API 所返回的错误码,有什么用呢?下面用一个实例来给大家演示一下~

假如本文中的实验现象如下:

可以看到,FATFS创建文件时,返回的错误码是13,那么如何定位该问题呢?13代表什么?

打开FATFS的ff.h文件即可看到所有错误码所表示的含义:

这样问题就定位到了,我们使用的SD卡是之前用于裸机实验的卡,SD卡分区被破坏,SD卡文件系统被破坏,所以FATFS创建文件时才会提示FR_NO_FILESYSTEM问题

至此,我们已经学会如何在SD卡上移植FATFS文件系统。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Mculover666 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 硬件准备
  • 软件准备
    • 2.创建CubeMX工程
    • 选择芯片型号
    • 配置时钟源
    • 配置串口
    • 配置 SDMMC 接口
    • 配置FATFS文件系统
    • 配置时钟树
    • 生成工程设置
    • 代码生成设置
    • 生成代码
      • 3. 在MDK中编写、编译、下载用户代码
      • 重定向printf( )函数
      • SD卡分区并格式化为FAT文件系统
      • 使用FATFS挂载SD卡
      • 创建文件并向文件中写入内容
      • 读取SD卡中的文件内容
      • FATFS API 错误码的使用
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档