CH32移植Fatfs文件操作系统(沁恒RISC-V内核)
本文所用芯片:CH32V307VCT6
使用SDIO读写SD卡,同时移植Fatfs对文件进行管理
1.首先在MounRiverStudio(后续称为MRS)中新建一个工程
选择自己单片机的型号,点击完成。
接下来我们去找到沁恒官方的例程 打开例程中 EVT->EXAM->SDIO->User文件夹
复制sdio.c和sdio.h
把这两个文件粘贴到你的工程中去。
然后到Fatfs官网下载最新的文件 下载网址:elm-chan.org/fsw/ff/00in…
滚动页面到底,可以看到Download
选择我圈出来的这个选项
浏览器会自动开始下载,下载完成后解压文件,打开文件夹能看到:
我们选择source,里面是Fatfs的源码
选中除了两个txt结尾的文件
也一同复制到我们的工程中去。
然后我们在工程中在新建一个headfile.h文件用来管理头文件
这样工程中总共有
Ps:这样直接在user中添加.h文件和.c文件的方式不太好,我这里是为了方便演示,实际使用最好把自己的代码放到一个新的文件夹下面。
然后回到MRS中(自己添加文件夹的同学,记得添加下文件夹路径)
我们先打开headfile.h文件夹
把一会要用到的.h文件定义好。
Fatfs的移植主要在diskio.c中,所以我们先打开这个文件
第一步适配应用层函数
将headfile.h文件包含进 diskio.c (diskio.h也可以)
然后我们往下看,能看到3个#define,这是对设备类型的定义
我们本次移植的SD卡,属于MMC类型,所以我们可以直接用源文件中的定义,记住这个DEV_MMC 他的define为 1
我们接下来的操作主要都是争对他。
因为我们这里使用默认的3个类型,所以我们最好去ff_conf.h中修改
使用卷的个数,我们先改成3,然后回到原来的地方
继续往下看能够看到几个函数,把文件滑倒底总共也只有 disk_status disk_initialize disk_read disk_write disk_ioctl 5个函数,我们要做的就是适配这5个函数即可。
我们由上及下的顺序来操作 看第一个函数
1.disk_status
看名字我们也能知道,这是获取Disk磁盘设备状态的函数,但是我们其实用不到这个,沁恒官方的SD卡初始化中已经对SD的状态做出来判断,所以我们直接放弃这个函数。
将函数switch中的除了DEV_MMC的选项直接改成break(因为我们本次移植只用到了SD卡,所以其他设备一律不检测,强制返回设备未初始化),对DEV_MMC选项直接返回 0 (也就初始化成功状态)。
2.disk_initialize
我们还是先看名字,就能知道这个函数是磁盘初始化函数,所以我们要在这个函数中初始化我们的磁盘也就是SD卡初始化。
同样的我们将函数switch中的除了DEV_MMC的选项直接改成break(因为我们本次移植只用到了SD卡,所以其他设备一律不检测,强制返回设备未初始化),然后对DEV_MMC选项进行SD卡初始化,沁恒官方的SD初始化函数为SD_Init();函数原型在sdio.c中可以查看,有兴趣的同学可以去了解下SD初始化的过程(自己移植非常的痛苦,我们就先享受下便利),SD_Init() 返回值为0代表初始化成功(刚好0在Fatfs中也是成功),所以我们直接返回就好了。这个函数移植结束,我们看下一个。
3.disk_read
磁盘读取函数,我们先找到sdio.c中对应磁盘读取函数SD_ReadDisk(),复制到DEV_MMC选项下面,然后我们看SD_ReadDisk函数需要的参数(数据地址,扇区,数量),再看我们disk_read函数的传参(驱动器编号,数据地址,扇区,数量)这不是巧了嘛,我们直接复制粘贴就好了
这个函数我们也移植好了。
4.disk_write
磁盘写入函数,同理找到sdio.c中的磁盘写入函数SD_WriteDisk(),依样画葫芦。
但是会有一个警告,原因是传入参数
const BYTE *buff
带有const类型,传入SD_WriteDisk 后 const 就被丢弃了,这个不影响,我们先不管。
5.disk_ioctl
这个函数主要是用来获取磁盘的各种信息
GET_SECTOR_SIZE是获取磁盘扇区大小,就保存在sido.c中的SDCardInfo结构体下CardBlockSize
GET_BLOCK_SIZE是用来指定擦除的最小单位,就是SDCardInfo结构体下CardBlockSize
这里有的同学可能就要疑惑了,为什么这两个是一样的,这个Fatfs中,块是大于等于扇区的,和SD卡里刚好相反(为什么会这样我也不知道,有大佬指点迷津吗)
GET_SECTOR_COUNT是获取扇区个数
按照FatFs官网的驱动中还有几个指令,但是用不上我们就先不写了。
好了,我们移植5个函数完成。
大功告吉,点击编译。
没有报错。我们开始愉快的写代码。
我们先来挂载下磁盘。
我们现在main.c文件最上方注释了变量定义区的地方定义
FATFS fs; /* FatFs文件系统对象 */
FIL fnew; /* 文件对象 */
UINT fnum; /* 文件成功读写数量 */
FRESULT res_sd; /* 文件操作结果 */
BYTE work[FF_MAX_SS];
BYTE WriteBuffer[] = {"txt.test\r\n"};/* 写缓冲区*/
然后在main函数中我们开始挂载磁盘
res_sd = f_mount(&fs,"1:",1);
if(res_sd == FR_NO_FILESYSTEM)
{
printf("formatting\r\n");
res_sd=f_mkfs("1:",0,work, sizeof(work));
res_sd = f_mount(NULL,"1:",1);
/* 重新挂载 */
res_sd = f_mount(&fs,"1:",1);
}
点击编译,然后我们就发现,报错了,原因是f_mkfs未定义(不能创建文件系统这怎么能忍)
但是我们点击转跳发现这个函数在ff.c中已存在
我们可以看到灰色的f_mkfs,这是编译器屏蔽编译的提示,我们往上翻就可以看到,有两个判断条件
FF_FS_READONLY = 0,!FF_FS_READONLY == 1 所以我们看另一个FF_USE_MKFS ,看名字叫使用mkfs,不就是我们要用的函数吗,我们进去把他改为1
这下应该好了把,都改完了,点击编译。
又报错了
提示没有get_fattime函数(获取文件时间),我们点一下,发现这个函数真的没有,那没办法了,我们只能自己创建了,因为我们用不到这个函数(要用的话需要上RTC)
我们在diskio.c最下面定义这个没啥用的函数
DWORD get_fattime (void)
{
return 0;
}
别忘了在diskio.h中声明下
此时我们再点编译,就没有问题了。
一步到位,我们已经移植完毕Fatfs了,可以开始愉快的使用了(怎么使用我就不教了,大家自己百度吧)
注意事项,如果全部完成后依旧出现文件打开/创建失败,可能是文件名超长了,把ffconf.h中FF_USE_LFN改为1 (启用长文件名)就好了,但是依旧不建议文件名太长。
PS:最近使用了一下沁恒的CH32系列芯片,还是挺好用的,几乎和ST标准库一模一样,芯片性能和价格都比较出色(沁恒打钱),后续估计还会CH系列的使用教程,感谢观看。
转载自:https://juejin.cn/post/7193618591453806651