STM32F103RC,FATFS,w25x16移植笔记
2016-06-30 16:34
441 查看
这些天移植了FatFS文件系统到STM32F103RC板上,使用STM32的SPI_FLASH库,出现了一些问题现在记录下来。
接下来说一下移植的过程:
移植的最新版本为FatFS 0.12版本版本中主要包含以下几个文件:diskio.c diskio.h ff.c ff.h ffconf.h integer.h。
其中,ff相关的文件为FatFS的核心文件系统文件,diskio相关的文件为文件系统与底层硬件交互的接口文件,ffconf.h是用来配置文件系统配置的一些参数,integer.h是对不同平台变量类型的定义。
1.修改ffconf.h
2.diskio.c
disk_initialize 增加SPI_FLASH_Init()以及SPI_FLASH_ReadID()函数进行SPI_FLASH的初始化操作
disk_read 增加SPI_FLASH_BufferRead,该函数是从指定地址读取指定字节数。
disk_write 增加相对应的Flash写入函数,Flash在写入的时候需要先擦除后写入。使用的Flash芯片为w25x16的16MB Flash芯片,此芯片的最小擦除单位为4k字节的一个扇区,因此在写入的时候,不考虑增加缓存的情况下即及时写入时,需要先将所写入的区域部分所占的扇区数据读取出来,并将对应的扇区擦除,然后将写入的区域与刚刚读取数据的区域合并后,再次写入对应的几个扇区中。
disk_ioctl 至少增加GET_SECTOR_COUNT、GET_BLOCK_SIZE、CTRL_SYNC三个状态的返回值,GET_SECTOR_COUNT的返回值为按照读取扇区来算总的扇区个数,GET_BLOCK_SIZE的返回值为读取扇区的大小,CTRL_SYNC返回值为RES_OK即可。
至此,文件系统移植完毕,调用的时候f_mkfs(“0:”,0,512);只需要调用一次,其他的测试如下
至此移植完成。
移植中遇到的问题:
1.执行挂载f_mount时出现FR_NO_FILESYSTEM提示。原因为没有执行f_mkfs,整个flash没有文件系统格式化。
2.执行过f_mkfs,但是依然出现FR_NO_FILESYSTEM的提示。仔细查找跟踪代码后,发现
接下来说一下移植的过程:
移植的最新版本为FatFS 0.12版本版本中主要包含以下几个文件:diskio.c diskio.h ff.c ff.h ffconf.h integer.h。
其中,ff相关的文件为FatFS的核心文件系统文件,diskio相关的文件为文件系统与底层硬件交互的接口文件,ffconf.h是用来配置文件系统配置的一些参数,integer.h是对不同平台变量类型的定义。
1.修改ffconf.h
_FS_READONLY //文件系统只读 _FS_MINIMIZE //移除一些函数,定义最小文件系统 _USE_STRFUNC //允许使用一些字符串函数 _USE_FIND //开启一些查询函数 _USE_MKFS //f_mkfs,可以格式化Flash _USE_FASTSEEK //开启一些快速定位函数 _USE_EXPAND //开启一些扩展函数 _USE_CHMOD //开启权限相关的函数 _USE_LABEL //开启卷标相关函数 _USE_FORWARD //开启使用数据流而不用缓冲区 _CODE_PAGE //代码页格式 _USE_LFN //开启长文件名模式 _MAX_LFN //设置最长文件名长度 _LFN_UNICODE //设置长文件名编码格式 _STRF_ENCODE //长命名文件中字符串编码格式 _FS_RPATH //支持目录更改 _VOLUMES //支持硬盘个数 _STR_VOLUME_ID //允许字符串模式的ID _VOLUME_STRS //字符串模式的具体字符串 _MULTI_PARTITION //允许新建多个分区 _MIN_SS //所支持最小的扇区大小 _MAX_SS //所支持最大的扇区大小 _USE_TRIM //支持空闲区域回收 _FS_NOFSINFO //支持查询文件系统信息 _FS_TINY //支持微型文件系统 _FS_EXFAT //支持扩展性文件系统 _FS_NORTC //支持不使用RTC的文件系统 _NORTC_MON //不使用RTC时的月份 _NORTC_MDAY //不使用RTC时的日 _NORTC_YEAR //不使用RTC时的年 _FS_LOCK //支持文件上锁功能 _FS_REENTRANT //支持文件重入,多线程访问 _FS_TIMEOUT //重入模式下超时周期 我的设置如下: #define _USE_MKFS 1 #define _CODE_PAGE 936 #define _VOLUMES 1 #define _MIN_SS 512 #define _MAX_SS 512 其余均为0或默认值
2.diskio.c
disk_initialize 增加SPI_FLASH_Init()以及SPI_FLASH_ReadID()函数进行SPI_FLASH的初始化操作
DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { DSTATUS stat; u32 FlashID; switch (pdrv) { case SPI_FLASH : SPI_FLASH_Init(); FlashID = SPI_FLASH_ReadID(); stat = 0; return stat; } return STA_NOINIT; }
disk_read 增加SPI_FLASH_BufferRead,该函数是从指定地址读取指定字节数。
DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) { DRESULT res; switch (pdrv) { case SPI_FLASH : SPI_FLASH_BufferRead(buff,sector * SPI_FLASH_SECTOR,count * SPI_FLASH_SECTOR); res = RES_OK; return res; } return RES_PARERR; }
disk_write 增加相对应的Flash写入函数,Flash在写入的时候需要先擦除后写入。使用的Flash芯片为w25x16的16MB Flash芯片,此芯片的最小擦除单位为4k字节的一个扇区,因此在写入的时候,不考虑增加缓存的情况下即及时写入时,需要先将所写入的区域部分所占的扇区数据读取出来,并将对应的扇区擦除,然后将写入的区域与刚刚读取数据的区域合并后,再次写入对应的几个扇区中。
DRESULT disk_write ( BYTE pdrv, /* Physical drive nmuber to identify the drive */ const BYTE *buff, /* Data to be written */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to write */ ) { DRESULT res; UINT i = 0; UINT SectorWriteTotal = 0; //写入数据总共占用的扇区个数 UINT SectorWriteLeft = 0; //写入数据占用剩余不到一个扇区的字节个数 UINT SectorPhyLocation = 0; //芯片上物理扇区的标号 u32 AddrStart = sector * SPI_FLASH_SECTOR; //写入数据的起始地址 UINT WriteLeftBytes = count * SPI_FLASH_SECTOR; //写入数据的剩余字节个数 UINT CurrenSectorLeft = 0; //当前扇区未被占用的剩余字节个数 UINT SectorPhyLocationAddr = 0; //芯片上物理扇区的地址 switch (pdrv) { case SPI_FLASH : SectorWriteTotal = count * SPI_FLASH_SECTOR / PHY_SECTOR_SIZE; //计算当前需要写入的数据量需要多少个扇区 向下取证 SectorWriteLeft = count * SPI_FLASH_SECTOR % PHY_SECTOR_SIZE; //计算不足一个扇区的字节个数 if(SectorWriteLeft > 0) //若存在不足一个扇区的数据,则需要多写入一个扇区 SectorWriteTotal += 1; SectorPhyLocation = sector * SPI_FLASH_SECTOR / PHY_SECTOR_SIZE; //计算写入数据的起始位置对应到芯片上的第几个扇区 for(i = 0; i < SectorWriteTotal;i++) { SectorPhyLocationAddr = (SectorPhyLocation + i) * PHY_SECTOR_SIZE; //下一个要操作的扇区物理地址 SPI_FLASH_BufferRead(EraseBuff,SectorPhyLocationAddr,PHY_SECTOR_SIZE); //把当前扇区的所有内容读出来放入缓冲区 SPI_FLASH_SectorErase(SectorPhyLocationAddr); //将当前扇区的内容擦除 CurrenSectorLeft = PHY_SECTOR_SIZE; //重置当前扇区剩余的字节个数为整个扇区的大小 if(AddrStart != SectorPhyLocationAddr) //判断若要写入的地址与扇区的起始地址不重合,则证明扇区起始地址与要写入的地址间原本可能存在数据 { SPI_FLASH_BufferWrite(EraseBuff,SectorPhyLocationAddr,(AddrStart - SectorPhyLocationAddr)); //将两地址间的有效数据反写 CurrenSectorLeft = CurrenSectorLeft - (AddrStart - SectorPhyLocationAddr); //当前扇区剩余字节数减去已写入的字节数量 } if(WriteLeftBytes <= CurrenSectorLeft) //判断当前扇区可以把剩下要写入的数据装下 { SPI_FLASH_BufferWrite((u8 *)buff,AddrStart,WriteLeftBytes); //则在起始位置写入剩下所有的数据 AddrStart += WriteLeftBytes; //起始地址调整到末尾 (此时此操作可能无意义) CurrenSectorLeft = CurrenSectorLeft - WriteLeftBytes; //扇区剩余字节减去写入数量 WriteLeftBytes = 0; //剩余写入数据量为0,写入完毕 } else //当前扇区只可以装入一部分要写入的数据 { SPI_FLASH_BufferWrite((u8 *)buff,AddrStart,CurrenSectorLeft); //将数据写满该扇区的剩余部分 AddrStart += CurrenSectorLeft; //写入地址调整 WriteLeftBytes -= CurrenSectorLeft; //剩余写入字节数调整 CurrenSectorLeft = 0; //当前扇区剩余字节数清0 } if(CurrenSectorLeft > 0) //若当前扇区未被写满,则将剩余部分缓冲区反写回Flash SPI_FLASH_BufferWrite(EraseBuff,AddrStart,CurrenSectorLeft); } res = RES_OK; return res; } return RES_PARERR; }
disk_ioctl 至少增加GET_SECTOR_COUNT、GET_BLOCK_SIZE、CTRL_SYNC三个状态的返回值,GET_SECTOR_COUNT的返回值为按照读取扇区来算总的扇区个数,GET_BLOCK_SIZE的返回值为读取扇区的大小,CTRL_SYNC返回值为RES_OK即可。
DRESULT disk_ioctl ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE cmd, /* Control code */ void *buff /* Buffer to send/receive control data */ ) { DRESULT res; switch (pdrv) { case SPI_FLASH : switch(cmd) { case GET_SECTOR_COUNT: (*(DWORD *)buff) = 32768; res = RES_OK; break; case GET_BLOCK_SIZE: (*(DWORD *)buff) = SPI_FLASH_SECTOR; res = RES_OK; break; case CTRL_SYNC: res = RES_OK; break; } return res; } return RES_PARERR; }
至此,文件系统移植完毕,调用的时候f_mkfs(“0:”,0,512);只需要调用一次,其他的测试如下
void FatfsTest() { FATFS fs; FIL fsrc; BYTE buffer[4096]; FRESULT res; UINT br, bw; BYTE if_Erase = 0; BYTE if_mkfs = 0; SPI_FLASH_Init(); if(if_Erase) SPI_FLASH_BulkErase(); res = f_mount(&fs,"0:",1); if(res == FR_NO_FILESYSTEM) { f_mkfs("0:",0,512); res = f_mount(&fs,"0:",1); } res = f_open(&fsrc, "0:src", FA_CREATE_ALWAYS | FA_WRITE | FA_READ); res = f_write(&fsrc, "12345", 5, &bw); res = f_close(&fsrc); res = f_open(&fsrc, "0:src", FA_WRITE | FA_READ); res = f_read(&fsrc, buffer, sizeof(buffer), &br); }
至此移植完成。
移植中遇到的问题:
1.执行挂载f_mount时出现FR_NO_FILESYSTEM提示。原因为没有执行f_mkfs,整个flash没有文件系统格式化。
2.执行过f_mkfs,但是依然出现FR_NO_FILESYSTEM的提示。仔细查找跟踪代码后,发现
disk_write(pdrv, fs->win, 0, 1)写入flash后立刻读出数据不一致,尤其是tbl[4] = sys; 写入错误会导致读出的时候找不到具体对应的文件系统,从而导致错误提示。原因是写入函数没有将原先的数据擦除,原先将该区域写入0,之后没有擦除则无法恢复。Flash的特性是1可以翻转写入0,但0不能写入1,只有擦除后,才可以正确。因此修改了disk_write,增加了先擦出再写入。
相关文章推荐
- 文件系统变为raw 无法访问的解决方法
- PHP 文件系统详解
- 把jQuery的each(callback)方法移植到c#中
- IIS 服务器的备份和移植技巧
- Powershell实现克隆NTFS文件系统权限
- 解析libcurl在android下的移植、编译与测试
- php中的filesystem文件系统函数介绍及使用示例
- 用Python编写一个简单的FUSE文件系统的教程
- Objective-c代码如何移植为Swift代码 Objective-c代码转移到Swift过程介绍
- 将SSH移植到arm soc上
- ok6410开发板移植DirectFB手记
- 【转自中科蓝鲸】集群NAS与集群文件系统的区别
- STM32 IO口双向问题
- 使用CMake来构建STM32工程
- HBase 系统架构
- Supporting Python 3(支持python3)——语言区别和暂时解决方法
- Supporting Python 3(支持python3)——重组和重命名
- J2ME游戏移植到Android平台的方法
- J2me游戏如何快速移植到Android(1)
- J2me游戏如何快速移植到Android (2)