小猫爪:动手笔记02-FatFs移植

  • 1 前言
  • 2 准备
    • 2.1 下载FatFs源码
    • 2.2 准备待移植工程
  • 3 移植
    • 3.1 添加文件
    • 3.2 编译
    • 3.3 完善接口
  • 4 运行
  • END

1 前言

今天我要移植一个简单的文件系统FatFs,至于文件系统是啥,FatFs是啥我就不多逼逼了,下面直接开干。这里我使用的平台为RT1050,开发环境为KEIL。

2 准备

2.1 下载FatFs源码

下载地址:http://elm-chan.org/fsw/ff/00index_e.html
下载后解压打开:
一览无余,一眼就看到了source文件夹,打开一看:
看到readme就要打开看一看:

FatFs Module Source Files R0.14aFILES00readme.txt   This file.00history.txt  Revision history.ff.c           FatFs module.ffconf.h       Configuration file of FatFs module.ff.h           Common include file for FatFs and application module.diskio.h       Common include file for FatFs and disk I/O module.diskio.c       An example of glue function to attach existing disk I/O module to FatFs.ffunicode.c    Optional Unicode utility functions.ffsystem.c     An example of optional O/S related functions.Low level disk I/O module is not included in this archive because the FatFsmodule is only a generic file system layer and it does not depend on any specificstorage device. You need to provide a low level disk I/O module written tocontrol the storage device that attached to the target system.

可以看到里面对每一个文件都作了非常详细的说明。这里简单的给每个文件解释一下:
integer.h:文件中包含了一些数值类型定义。
diskio.c:包含底层存储介质的操作函数,这些函数需要用户自己实现,主要添加
底层驱动函数。
ff.c: FatFs 核心文件,文件管理的实现方法。该文件独立于底层介质操作文件的
函数,利用这些函数实现文件的读写。
ffunicode.c:包含了多语言支持的编码格式,例如简体中文936 编码、英文437 编
码等。
ffconf.h:这个头文件包含了对FatFs 功能配置的宏定义,通过修改这些宏定义就可
以裁剪FatFs 的功能。

需要重点修改的文件就是diskio.c和ffconf.h。diskio.c文件就是FatFs应用层程序
与MCU的接口,ffconf.h文件可以配置其功能。

2.2 准备待移植工程

准备一个可以对SD卡正常读写的工程,我已经偷偷地准备好了,下面砸门正式开始吧。

3 移植

3.1 添加文件

复制source文件夹至工程下并改名fatfs,在工程中添加新分组FatFs,并且添加fatfs文件夹下的所有文件至新的分组,如下:

随后将fatfs路径包含进编译路径中,如下:

3.2 编译

文件已经添加完毕,废话不多说,直接编译。

  1. 出错:有很多错误和警告。
    原因:因为这些函数就是FatFs接口函数,需要使用者去定义,所以这些函数没有定义。
    修改:可以直接删掉注释掉,或者写一个空函数放在那。

  2. 出错:flexspi_nor_debug\sdcard_polling.out: Error: L6218E: Undefined symbol get_fattime (referred from ff.o).
    原因:get_fattime函数没有定义,这是FatFs时间戳功能,通常需要MCU里的RTC时钟来支持,这里我不使用时间戳。
    修改:找到ffconf.h中的FF_FS_NORTC,将其改为1,如下:

#define FF_FS_NORTC      1

废话不多说,再次编译。

没有错误,成功移植,那是不可能的。

3.3 完善接口

关键来了,需要完善接口,那么需要完善的接口有哪些呢。打开diskio.h文件,找到以下:

DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);

可以看到FatFs的接口函数一共有五个,下面则需要将这五个函数与我们自己的MCU的SD卡驱动对接,完成接口的定义。

(1)添加设备号
首先找到diskio.c中设备号定义:

/* Definitions of physical drive number for each drive */
#define DEV_RAM     0   /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC     1   /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB     2   /* Example: Map USB MSD to physical drive 2 */

可以看到并没有SD卡,所以需要在后面加一个SD卡的设备号,添加完如下:

/* Definitions of physical drive number for each drive */
#define DEV_RAM     0   /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC     1   /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB     2   /* Example: Map USB MSD to physical drive 2 */
#define DEV_SD      3   /* Example: Map USB MSD to physical drive 2 */

同时还需要将ffconf.h文件中的FF_VOLUMES参数改成4。

#define FF_VOLUMES       4

因为总共有4个设备号。

(2)添加接口函数
在接口函数中,照葫芦画瓢,添加属于SD卡的接口函数,我这里就以disk_initialize举一个例子,修改完如下:

DSTATUS SD_disk_initialize(void)
{}
DSTATUS disk_initialize (BYTE pdrv              /* Physical drive nmuber to identify the drive */
)
{DSTATUS stat;int result;switch (pdrv) {case DEV_RAM ://result = RAM_disk_initialize();// translate the reslut code herereturn stat;case DEV_MMC ://result = MMC_disk_initialize();// translate the reslut code herereturn stat;case DEV_USB ://result = USB_disk_initialize();// translate the reslut code herereturn stat;case DEV_SD :stat= SD_disk_initialize();return stat;    }return STA_NOINIT;
}

同理将diskio.c下所有的函数都添加属于SD卡的接口函数。

(3)完善添加的接口函数
上面一共添加了五个函数,分别是SD_disk_status,SD_disk_initialize,SD_disk_read,SD_disk_write,disk_ioctl下面就需要将这个五个函数与MCU的SD卡驱动函数联系在一起。

  1. SD_disk_status:返回当前SD卡的状态,可有可无的东西,直接不写,直接返回RES_OK。
DSTATUS sd_disk_status(BYTE pdrv)
{return RES_OK;
}
  1. SD_disk_initialize:初始化SD卡,就是完成一些SD卡的初始化
DSTATUS SD_disk_initialize(void)
{/* power off card */SD_SetCardPower(&g_sd, false);/* wait card insert */SD_PollingCardInsert(&g_sd, kSD_Inserted);/* power on the card */SD_SetCardPower(&g_sd, true);/* Init card. */if (SD_CardInit(&g_sd)){return STA_NODISK;}return RES_OK;
}
  1. SD_disk_read:读取SD卡数据,就是SD卡读数据的函数
DRESULT SD_disk_read(BYTE* buff, LBA_t sector, UINT count)
{if (kStatus_Success != SD_ReadBlocks(&g_sd, buff, sector, count)){return RES_ERROR;}return RES_OK;
}
  1. SD_disk_write:写SD卡数据,就是往SD卡里写数据的函数
DRESULT SD_disk_write( const BYTE* buff, LBA_t sector, UINT count)
{if (kStatus_Success != SD_WriteBlocks(&g_sd, buff, sector, count)){return RES_ERROR;}return RES_OK;
}
  1. SD_disk_ioctl:用来扩展对存储器的操作,比如获得存储器大小等,所有的操作在diskio.h中都有定义。取出FatFs通用的命令如下:
/* Generic command (Used by FatFs) */
#define CTRL_SYNC           0   /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT    1   /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE     2   /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE      3   /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM           4   /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
名称 描述 条件
CTRL_SYNC 写操作同步命令 FF_FS_READONLY == 0
GET_SECTOR_COUNT 获取扇区数量 FF_USE_MKFS == 1
GET_SECTOR_SIZE 获取扇区大小 FF_MAX_SS != FF_MIN_SS
GET_BLOCK_SIZE 获取块大小 FF_USE_MKFS == 1
CTRL_TRIM 发布TRIM命令 FF_USE_TRIM == 1

可以看到这些命令是否需要由一些宏定义来进行定义的,那这些宏定义代表着什么呢?这些宏定义在ffconf.h里面都可以找到,并且每一个宏定义的具体意义都标注的很清楚,找到这些宏定义后发现在它的原始配置中只有|FF_FS_READONLY == 0满足条件,所以我们只需要完成CTRL_SYNC这个命令(当然也可以直接将有效宏定义直接使能,但是这篇文件侧重的是怎样移植FatFs,所以就完全按照它的默认配置来吧,如果想了解更多,可以互相讨论)。所以我的SD_disk_ioctl代码如下:

DRESULT SD_disk_ioctl(BYTE cmd, void* buff)
{DRESULT result = RES_OK;switch (cmd){case CTRL_SYNC:result = RES_OK;break;default:result = RES_PARERR;break;}return result;
}

为了方便操作,我使能了FatFs相对路径的功能,也就是ffconf.h文件下的FF_FS_RPATH,修改成如下:

#define FF_FS_RPATH      2
/* This option configures support for relative path.
/
/   0: Disable relative path and remove related functions.
/   1: Enable relative path. f_chdir() and f_chdrive() are available.
/   2: f_getcwd() function is available in addition to 1.
*/

到这里就完成了所有的移植工作了,接下来运行它。

4 运行

修改main函数,测试刚刚移植的FatFs,代码如下(当然了,我也是Ctrl+CV老手了,直接Copy不香吗?):

int main()
{FRESULT error;DIR directory; /* Directory object */FILINFO fileInformation;UINT bytesWritten;UINT bytesRead;const TCHAR driverNumberBuffer[3U] = {'3', ':', '/'};volatile bool failedFlag           = false;char ch                            = '0';BYTE work[FF_MAX_SS];BOARD_ConfigMPU();BOARD_InitPins();BOARD_BootClockRUN();BOARD_InitDebugConsole();PRINTF("\r\nFATFS example to demonstrate how to use FATFS with SD card.\r\n");PRINTF("\r\nPlease insert a card into board.\r\n");if (sdcardWaitCardInsert() != kStatus_Success){return -1;}if (f_mount(&g_fileSystem, driverNumberBuffer, 0U)){PRINTF("Mount volume failed.\r\n");return -1;}error = f_chdrive((char const *)&driverNumberBuffer[0U]);if (error){PRINTF("Change drive failed.\r\n");return -1;}PRINTF("\r\nCreate directory......\r\n");error = f_mkdir(_T("/dir_1"));if (error){if (error == FR_EXIST){PRINTF("Directory exists.\r\n");}else{PRINTF("Make directory failed.\r\n");return -1;}}PRINTF("\r\nCreate a file in that directory......\r\n");error = f_open(&g_fileObject, _T("/dir_1/f_1.dat"), (FA_WRITE | FA_READ | FA_CREATE_ALWAYS));if (error){if (error == FR_EXIST){PRINTF("File exists.\r\n");}else{PRINTF("Open file failed.\r\n");return -1;}}PRINTF("\r\nCreate a directory in that directory......\r\n");error = f_mkdir(_T("/dir_1/dir_2"));if (error){if (error == FR_EXIST){PRINTF("Directory exists.\r\n");}else{PRINTF("Directory creation failed.\r\n");return -1;}}PRINTF("\r\nList the file in that directory......\r\n");if (f_opendir(&directory, "/dir_1")){PRINTF("Open directory failed.\r\n");return -1;}for (;;){error = f_readdir(&directory, &fileInformation);/* To the end. */if ((error != FR_OK) || (fileInformation.fname[0U] == 0U)){break;}if (fileInformation.fname[0] == '.'){continue;}if (fileInformation.fattrib & AM_DIR){PRINTF("Directory file : %s.\r\n", fileInformation.fname);}else{PRINTF("General file : %s.\r\n", fileInformation.fname);}}memset(g_bufferWrite, 'a', sizeof(g_bufferWrite));g_bufferWrite[BUFFER_SIZE - 2U] = '\r';g_bufferWrite[BUFFER_SIZE - 1U] = '\n';PRINTF("\r\nWrite/read file until encounters error......\r\n");while (true){if (failedFlag || (ch == 'q')){break;}PRINTF("\r\nWrite to above created file.\r\n");error = f_write(&g_fileObject, g_bufferWrite, sizeof(g_bufferWrite), &bytesWritten);if ((error) || (bytesWritten != sizeof(g_bufferWrite))){PRINTF("Write file failed. \r\n");failedFlag = true;continue;}/* Move the file pointer */if (f_lseek(&g_fileObject, 0U)){PRINTF("Set file pointer position failed. \r\n");failedFlag = true;continue;}PRINTF("Read from above created file.\r\n");memset(g_bufferRead, 0U, sizeof(g_bufferRead));error = f_read(&g_fileObject, g_bufferRead, sizeof(g_bufferRead), &bytesRead);if ((error) || (bytesRead != sizeof(g_bufferRead))){PRINTF("Read file failed. \r\n");failedFlag = true;continue;}PRINTF("Compare the read/write content......\r\n");if (memcmp(g_bufferWrite, g_bufferRead, sizeof(g_bufferWrite))){PRINTF("Compare read/write content isn't consistent.\r\n");failedFlag = true;continue;}PRINTF("The read/write content is consistent.\r\n");PRINTF("\r\nInput 'q' to quit read/write.\r\nInput other char to read/write file again.\r\n");ch = GETCHAR();PUTCHAR(ch);}PRINTF("\r\nThe example will not read/write file again.\r\n");if (f_close(&g_fileObject)){PRINTF("\r\nClose file failed.\r\n");return -1;}while (true){}
}

END

小猫爪:动手笔记02-FatFs移植相关推荐

  1. 微信小程序学习笔记02:微信小程序注册

    文章目录 零.学习目标 一.小程序注册方法 1.注册 2.登录 二.小程序开发工具 1.下载开发工具 2.安装开发工具 3.启动开发工具 三.创建第一个小程序 1.启动开发者工具 2.新建项目 3.模 ...

  2. 小猫爪:i.MX RT1050学习笔记23-FreeRTOS移植之宇宙最详细

    小猫爪:i.MX RT1050学习笔记23-FreeRTOS移植之宇宙最详细 1 前言 2 准备 2.1 下载FreeRTOS源代码 2.2 准备一个RT1050的普通工程 3 移植 3.1 添加文件 ...

  3. 小猫爪:S32K3学习笔记21-S32K3之SAF及其应用

    小猫爪:S32K3学习笔记21-S32K3之SAF及其应用 1 前言 2 SAF简介 3 SAF框架 4 SAF组件 4.1 eMcem和Bist 4.2 sReco 4.3 mSel 4.4 sBo ...

  4. 小猫爪:i.MX RT1050学习笔记22-eLCDIF

    小猫爪:i.MX RT1050学习笔记22-eLCDIF 1 前言 2 结构 3 初始化结构体 4 开启一次简单的传输过程 5 PXP END 1 前言 RT1052 系列芯片内部自带一个增强型液晶P ...

  5. 小猫爪:S32K3学习笔记20:S32K3之SCST及其应用

    小猫爪:S32K3学习笔记20:S32K3之SCST及其应用 1 前言 2 SCST简介 3 移植 4 应用 4.1 启动测试 4.2 使能FPU相关测试项 4.3 49号测试项中的MPU配置 4.4 ...

  6. 小猫爪:i.MX RT1050学习笔记3-CCM

    小猫爪:i.MX RT1050学习笔记3-CCM 1 前言 2 RT时钟的管理 3 CCM的结构 4 CCM的时钟树 5 时钟模块的具体功能 5.1 生成时钟 5.1.1 时钟源 5.1.2 7个PL ...

  7. 小猫爪:S32K3学习笔记09-S32K3之Safety简介

    小猫爪:S32K3学习笔记09-S32K3之Safety简介 1 前言 2 Safety相关硬件介绍 3 Safety相关软件介绍 4 Safety文章目录 END 1 前言   接下来,就要开始进学 ...

  8. 小猫爪:S32K3学习笔记05-S32K3之ADC

    小猫爪:S32K3学习笔记05-S32K3之ADC 1 前言 2 资源简介 3 ADC功能详解 3.1 ADC mux-mode channels 3.2 ADC内部框架 3.3 时钟源 3.4 通道 ...

  9. 小猫爪:S32K3学习笔记10-S32K3之EIM和ERM

    小猫爪:S32K3学习笔记10-S32K3之EIM和ERM 1 前言 2 EIM(Error Injection Module) 3 ERM(Error Reporting Module) 4 MCA ...

最新文章

  1. java 判断是否为邮箱_Java判断邮箱是否存在 有返回值
  2. linux :故障提示:Error:No suitable device found: no device found for connection System eth0
  3. HTML课堂笔记02-21
  4. Jquery取得iframe下内容的方法
  5. Windows下部署elasticsearch和kibana
  6. Http协议中常用字段总结(不定时完善中)
  7. 掌握3分钟网络排障秘技,网络管理员不再做“苦命人”
  8. deep-sort 代码阅读(https://github.com/nwojke/deep_sort)
  9. Java从入门到入土
  10. Java面试宝典 Beta5.0版 (2018年最新公测版)
  11. shark恒破解笔记5-VB之rtcMsgBox
  12. 工业软件下载大全202108
  13. C# Xml序列化Dictionary
  14. 深入理解Java虚拟机读书笔记之垃圾收集器与内存分配策略
  15. 卡方检验在关联分析中的应用
  16. 解决RuntimeError: stack expects a non-empty Tensorlist问题
  17. IO Workload Characterization Revisited: A Data-Mining Approach
  18. .NET Core API网关Ocelot(十四)【转换Claims,日志,跟踪】
  19. 19. OP-TEE中TA与CA执行流程详解-------软件架构篇
  20. ssh登录报no matching MAC found. Their offer: hmac-sha2-512异常

热门文章

  1. 你放心输出使用在线益智游戏
  2. 5.微信拜年短信自动回复
  3. Nginx HA双机热备
  4. 下一代数据存储OneStorage闪亮登场,华为打造全场景智能的基石
  5. 调用RemoteApp
  6. mapbox 地图样式规范
  7. Hyperledger fabric的项目实战---江苏省农牧厅渔业管理系统代码实现
  8. python hasattr_Python hasattr()用法及代码示例
  9. 多元微积分_保守场内的线积分
  10. 运用Zabbix实现内网服务器状态及局域网状况监控(5) —— Zabbix监控路由器