前言
我们使用一个现成的SDIO-读写测试文件
(1)拷贝FatFs文件系统源文件到user目录下,并重命名为fatfs
(2)创建工作目录FATFS,并添加文件系统底层文件和中间层文件
添加头文件路径
底层驱动移植
1、修改头文件
修改为
其中ATA作为SD卡
2、disk_status函数
原:
修改后
默认返回初始化正确,因为如果真的初始化出错后面有其它操作可以继续判断
3、disk_initialize函数
原:
修改后
4、disk_read函数
修改前
修改后:
首先外部定义一个SD卡信息结构体变量
添加块读取函数
SD_ReadMultiBlocks(buff,sector * SDCardInfo.CardBlockSize,SDCardInfo.CardBlockSize,count);
其中第一个参数为输出给上层文件系统的数组,第二个变量为读取块的起始地址(块号*每个块的大小),第三个参数为每个块的大小,第四个参数为读取块的个数。
还要注意地址对齐的问题,如果上层传入的buff的地址不是四个字节对齐,由于我们的SD卡是采用DMA来进行数据搬运,按照32位搬运,所以地址需要四个字节对齐,因此如果不是,可能会导致读取出错。待会进行处理。
读取之后还需要进行等待读取完成
5、disk_write函数
修改前
修改后
与disk_read类似
(注意同样待会儿需要进行地址对齐问题的改进)
6、disk_ioctl函数
修改前:
修改后
7、最后手动添加上get_fattime函数
到此就完成最基本的文件系统接口操作了。
8、修改相关宏_CODE_PAGE为437,就可以使用英文名,并且不需要添加编码页
由于暂时只添加了一个SD存储介质,因此_VOLUMES设置为1
如果还添加了FLASH,_MAX_SS必须设置为4096,否则无法使用FLASH
此外_USE_MKFS必须设置为1,才可以格式化文件系统
还有_USE_STRFUNC要设置为1,才可以使用f_gets、fputs相关函数
9、main函数
我们将之前移植的FLASH文件系统的main文件拿过来,并进行简单修改
#include "stm32f10x.h"
#include "./sdio/bsp_sdio_sdcard.h"
#include "./usart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "ff.h"
/**
******************************************************************************
* 定义变量
******************************************************************************
*/
FATFS fs; /* FatFs文件系统对象 */
FIL fnew; /* 文件对象 */
FRESULT res_sd; /* 文件操作结果 */
UINT fnum; /* 文件成功读写数量 */
BYTE ReadBuffer[1024]={0}; /* 读缓冲区 */
BYTE WriteBuffer[] = /* 写缓冲区*/
"欢迎使用野火STM32 开发板 今天是个好日子,新建文件系统测试文件\r\n";
extern SD_CardInfo SDCardInfo;
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* 初始化LED */
LED_GPIO_Config();
LED_BLUE;
/* 初始化调试串口,一般为串口1 */
USART_Config();
printf("\r\n****** 这是一个SD卡 文件系统实验 ******\r\n");
//在外部SPI Flash挂载文件系统,文件系统挂载时会对SPI设备初始化
res_sd = f_mount(&fs,"0:",1);
// printf("容量=%lld",SDCardInfo.CardCapacity/1024/1024);
/*----------------------- 格式化测试 ---------------------------*/
/* 如果没有文件系统就格式化创建创建文件系统 */
if(res_sd == FR_NO_FILESYSTEM)
{
printf("》SD卡还没有文件系统,即将进行格式化...\r\n");
/* 格式化 */
res_sd=f_mkfs("0:",0,0);
if(res_sd == FR_OK)
{
printf("》SD卡已成功格式化文件系统。\r\n");
/* 格式化后,先取消挂载 */
res_sd = f_mount(NULL,"0:",1);
/* 重新挂载 */
res_sd = f_mount(&fs,"0:",1);
}
else
{
LED_RED;
printf("《《格式化失败。》》\r\n");
while(1);
}
}
else if(res_sd!=FR_OK)
{
printf("!!SD卡挂载文件系统失败。(%d)\r\n",res_sd);
printf("!!可能原因:SD卡初始化不成功。\r\n");
while(1);
}
else
{
printf("》文件系统挂载成功,可以进行读写测试\r\n");
}
/*----------------------- 文件系统测试:写测试 -----------------------------*/
/* 打开文件,如果文件不存在则创建它 */
printf("\r\n****** 即将进行文件写入测试... ******\r\n");
res_sd = f_open(&fnew, "0:FatFs读写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
if ( res_sd == FR_OK )
{
printf("》打开/创建FatFs读写测试文件.txt文件成功,向文件写入数据。\r\n");
/* 将指定存储区内容写入到文件内 */
res_sd=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
if(res_sd==FR_OK)
{
printf("》文件写入成功,写入字节数据:%d\n",fnum);
printf("》向文件写入的数据为:\r\n%s\r\n",WriteBuffer);
}
else
{
printf("!!文件写入失败:(%d)\n",res_sd);
}
/* 不再读写,关闭文件 */
f_close(&fnew);
}
else
{
LED_RED;
printf("!!打开/创建文件失败。\r\n");
}
/*------------------- 文件系统测试:读测试 ------------------------------------*/
printf("****** 即将进行文件读取测试... ******\r\n");
res_sd = f_open(&fnew, "0:FatFs读写测试文件.txt", FA_OPEN_EXISTING | FA_READ);
if(res_sd == FR_OK)
{
LED_GREEN;
printf("》打开文件成功。\r\n");
res_sd = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
if(res_sd==FR_OK)
{
printf("》文件读取成功,读到字节数据:%d\r\n",fnum);
printf("》读取得的文件数据为:\r\n%s \r\n", ReadBuffer);
}
else
{
printf("!!文件读取失败:(%d)\n",res_sd);
}
}
else
{
LED_RED;
printf("!!打开文件失败。\r\n");
}
/* 不再读写,关闭文件 */
f_close(&fnew);
/* 不再使用文件系统,取消挂载文件系统 */
f_mount(NULL,"0:",1);
/* 操作完成,停机 */
while(1)
{
}
}
10、首先将编码改为936,支持中文
然后设置支持长文件名,并将文件名存储在全局区
最后添加中文编码页
11、运行效果
12、地址对齐改进
(1)首先定义一个宏,表示SD卡块的大小
(2)对于disk_read函数修改如下:
buff&3的效果相对于buff%4判断地址能否被4整除,(因为4的二进制表示为100,所以buff&(011B),判断低两位是否有1)如果不能被4整除就执行if判断里面的内容。
首先定义一个数组scratch(unsigned int类型),将我们的数据缓冲起来,这样就不会引起DMA传输的错误,然后我们自己调用自己(用disk_read读取一个扇区),最后再拷贝给buff,传输给文件系统的上层,从而解决了地址不对齐的问题。
对于disk_write函数,方法和disk_read一样,只是传输数据方向是反的
到此SD卡FATFS文件系统的全部移植过程结束,而应用层与之前的FLASH都是一样的,不需要进行修改。