目录
串行FLASH文件系统FatFs-移植过程
准备工作及移植前说明
底层disk接口程序API配置
中间层API功能实现及常用文件操作函数使用
文件系统偏移
中文文件名和长文件名
串行FLASH文件系统FatFs-移植过程
准备工作及移植前说明
我们需要在SPI——读写串行FLASH的基础驱动程序上进行FatFs文件系统的移植。
首先我们将FatFS的src文件夹复制到STM32 FLASH工程下的USER目录,并重命名为FATFS
我们移植文件系统主要就是实现底层disk函数的具体功能
底层disk接口程序API配置
1、首先将diskio.c和ff.c包含到工程中
2、添加完成之后,点击编译,报错找不到头文件,我们需要将diskio.c官方测试样例的三个头文件注释掉
3、将diskio.c中的result = ATA_disk_status();、result = MMC_disk_status();和result = USB_disk_status();注释
4、注释完之后,再次编译,找不到get_fattime
我们需要手动将get_fattime()函数添加到文件中
get_fattime()函数需要返回一个时间值,我们暂时先不管,让值返回0
5、我们可以发现diskio.h中官方已经定义了三个物理存储介质编号ATA、MMC和USB,diskio中的所有存储介质操作函数通过传入参数判断区分具体操作哪个存储介质
我们将其都注释掉,然后自定以两个存储介质SD_CARD和SPI_FLASH,并将所有底层操作函数中所有的switch case中的原存储介质替换掉
6、首先我们来看disk_initialize函数,只有一个参数用于传入存储设备编号,编号用于区分操作的存储器,返回值返回当前的存储器状态。该函数用于初始化存储设备,并使设备进入读写可用的状态,初始化完之后用于返回一个状态值来告诉上层的调用者。
该函数用于被FatFs module(中间层)调用,不能直接使用,需要使用中间层的f_mount挂载函数来调用(我们初始化文件系统都通过使用f_mount来实现)
(1)首先将SPI_FLASH_Init();函数添加到“case SPI_FLASH :”中。
(2)接着要返回一个状态,但我们仅仅通过SPI_FLASH_Init()不知道是否初始化FLASH成功。因此我们通过SPI_FLASH_ReadID()函数通过判断读取设备号是否成功来判断。
将SPI_FLASH_ReadID()放在“DSTATUS disk_status (BYTE pdrv){}”状态读取函数中
(3)状态读取函数共有三种状态返回值,分别表示设备初始化失败、未发现设备、设备写保护三种。通过低三位的状态标志位来确定设备状态。
一般来说我们的FLASH不存在写保护的状态,而我们判断FLASH是否初始化成功是通过读取ReadID和sFLASH_ID这个宏是否相等来确定的。因此结果只有两种状态,所以我们初始化状态正常就直接返回0(将所有位都置0),而初始化状态失败就返回STA_NOINIT或者STA_NODISK。
通过返回值,上层就可以知道设备初始化成功或者失败、或者物理设备不存在,并出现提醒的错误。
(4)如果我们不确定FLASH是否处于低功耗模式,我们需要在init后面添加SPI_Flash_WAKEUP()函数来确保FLASH处于正常功耗模式(因为FLASH在低功耗状态下,无法正常工作)
7、继续我们来配置disk_read()函数
disk_read()用于读取扇区(一个或者多个),第一个参数为设备号;第二个参数为读取扇区的起始地址,读取完数据后通过指针返回给上层,具体传入数组或指针由上层定义;第三个参数为开始的扇区号;第四个个参数为读取的扇区个数
返回值要注意其中的RES_PARERR表示输入的参数不支持(sector超出范围等导致)
通过调用void SPI_FLASH_BufferRead(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead);函数来实现扇区的读取。通过disk_read()中的sector扇区号来计算出ReadAddr起始地址,通过count扇区个数来算出NumByteToRead要读取多少个字节。
这里回忆一下知识点:一个扇区4096Byte(4KB),一个块有16个扇区
通过调用SPI_FLASH_BufferRead()函数,并算出对应参数。默认读取成功,返回值为RES_OK
8、接着配置disk_write()函数
参数与disk_read()相同
对于写入,我们的SPI-FLASH没有检测是否写入的功能,因此直接返回RES_OK
注意使用写功能,必须将_FS_READONLY置0,否则只支持只读
9、再来配置disk_ioctl函数,
在初始化设备前,必须将存储设备进行格式化,建立好文件信息结构,从而才能实现对设备存储内容以文件格式进行读写。
第一个参数为设备号;第二个参数为cmd命令号,文件系统通过命令号来告诉底层,比如获取当前设备的容量,某个文件的大小等等(底层通过switch...case...来确定不同的返回值);第三个参数buff既可以作为输入也可以作为输出
具体的cmd命令如下
具体命令使用需要配置对应条件
(1)开始对FLASH进行配置
(2)这里以常用三个命令进行配置为例
返回值默认成功,res = RES_OK。
(3)先看GET_SECTOR_COUNT
根据注释需要将扇区个数赋值给buff从而传给上层,需要将buff强制转换成DWORD*
同理GET_SECTOR_SIZE和GET_BLOCK_SIZE,也需要赋值给buff,并强转为对应指针变量类型
注:buff原来为void*类型
配置完成如下:
10、最后看get_fattime,返回当前时间,值为32bit
具体手动配置固定时间可配置如下
如果想实现动态标准时间,可以配置RTC,再配置该函数
至此diskio.c配置完成,接下来配置ffconfig.h
11、需要使用文件系统的时候,我们只需要添加ff.h头文件包含即可
中间层API功能实现及常用文件操作函数使用
在使用文件系统时,首先要调用f_mount()函数进行文件系统挂载,从而配置和初始化文件系统
1、f_mount()函数
第一个参数为文件系统句柄,其中drv为之前在diskio.c中定义的设备号,csize为簇(表示多个扇区),ssize为每个扇区的大小,最后一个成员win[_MAX_SS]为文件系统的缓冲区
由于文件系统句柄变量所占空间很大,我们定义放在全局区,每一个存储设备需要单独定义文件系统句柄。
如果传入参数为NULL,表示取消挂载,释放当前程序的所有文件系统空间。
第二个参数path,我们设置为"0:"就代表选择第一个存储设备,由于我们刚刚设置的FLASH设备号为1,所以设置"1:"
第三个参数设置为0,表示稍后挂载;设置为1,表示立即挂载。我们一般都设置为1
f_mount()返回值为FRESULT,如下所示
2、烧写程序
返回值为11,表示设备号不可用
我们将_VOLUMES值设置为2,支持两个设备可以使用
3、继续烧写,这次出现硬件卡死
这是因为我们的FLASH每个扇区为4096字节,刚刚在diskio.c中刚配置完
我们将配置文件中的_MAX_SS改为4096,从而支持扇区最大为4096(512在SD卡应用较多)
4、再次烧写,res返回值为13,表示未找到文件系统,这是因为我们还没有创建(格式化)文件系统
5、使用f_mkfs()函数创建文件系统(注意格式化会将存储设备原来所有内容全部删除)
第一个参数为设备路径
第二个参数,如果为FDISK表示SD卡、FLASH这一类存储设备,SFD表示使用软盘。这里我们使用FDISK
第三个参数,表示每个簇的大小,我们之间设置为自动分配
返回值也为FRESULT
我们设置为如果res返回值为FR_NO_FILESYSTEM,就初始化设备,否则不初始化
但是编译报错出现无法识别f_mkfs函数,这是因为官方默认进行了文件系统的裁剪,不可用使用格式化。
因此我们再ffconf.h中将_USE_MKFS配置为1,支持文件系统初始化
6、重新烧入程序,再次复位还是找不到设备
这是因为我们在使用f_mkfs函数进行写入文件系统的信息结构之前,没有擦除FLASH,这就会导致信息写入不进去,就无法格式化成功。
因此在disk_write()函数中添加擦除扇区函数
再次烧写,格式化成功
7、注意在格式化之后如果要使用文件系统,必须先取消挂载,再重新挂载文件系统
8、打开或者创建一个文件要使用f_open函数,与C库函数类似,不作过多解释
第一个参数为文件句柄(不是文件系统句柄)
第二个参数为文件路径,如"1:test.txt"
第三个参数为文件模式
文件句柄具体内容如下
我们创建一个test.txt文件
9、使用f_write向文件写入内容,写入的内容可以为中文(即使没有配置中文编码页也行,但是没有中文编码页会导致文件名和存储路径不可用为中文)
10、使用f_read进行读取文件内容
第三个参数btr表示要读取的内容大小,我们可以使用f_size函数来获取文件的大小,通过第四个参数和第三个参数比较,我们可以判断是否读取到文件末尾
在读取文件前,我们要使用f_lseek()函数定位文件指针到文件开头
首先定义两个变量,一个用来获取已读取内容大小,一个用来存储读取内容
然后进行文件内容读取
烧入程序,读写内容成功
我们可以将_USE_FASTSEEK定义为1,进行快速定位
如果将_FS_MINIMIZE配置为3,就不支持定位了
11、最后读写完文件,一定要记得关闭,否则无法数据还在缓冲区内,无法真正存入文件。
文件系统偏移
1、文件系统向后偏移2MB
只需要修改diskio.c中的disk_read、disk_write、disk_ioctl即可
分别修改如下:(增加红色部分即可,其它不变)
中文文件名和长文件名
添加中文编码页和实现长文件名
首先添加cc936.c文件
然后修改_CODE_PAGE为936,支持中文编码
修改_USE_LFN为非0值,从而支持长文件名,设置为1,存储在全局区
更多功能可以深入探索。