FATFS移植、调试过程(在STM32上使用W25Q64)

上面是我的微信和QQ群,欢迎新朋友的加入。

花了几天的时间好不容易自己移植好了FATFS,以前一般都是用别个现成的东西,真的自己移植还是有一点点的操蛋。

 

移植FATFS其实不难,当然这是对于一个成功移植好的人来说。FATFS移植资料网上有一大堆,但是在移植成功之前还是搞得我一头雾水.

 

1、准备工作

硬件:STM32F4+W25Q64

软件:FATFS 0.1版本,好像现在最高的就是0.1版的吧,没去细查。

 

FATFS官方源码下载好之后只有几个文件。

添加两个C文件进去就好了,添加文件这种事比较基础,没什么好说的。

只要我这截图上有的文件都加上去了,基本上就可以了。

这里面需要我们修改的是diskio.c,其它文件不用动,当然有时候动动也没事,我用别人的东西总喜欢看看里面是什么。

 

在diskio.c里面,一共有6个接口函数,我按照重要性从最不重要的开始讲

参考正点原子的代码,我在开头宏定义了扇区大小等内容。

 

#define   FLASH_SECTOR_SIZE      512
#define   FLASH_BLOCK_SIZE       8   
uint32_t  FLASH_SECTOR_COUNT  =  2048*6;  

这三个内容在diskio.c都会用到。这里解释一下这三个东西,我之前查这个搞了半天没理解

 

 

FLASH_SECTOR_SIZE   是指一个扇区块的大小 512个字节
 
FLASH_BLOCK_SIZE 一个扇区分成了8块,也就是4K的大小,为什么是八块,百度后发现是因为与FAT类型有关,具体解释在正点原子

-第四十五章 FATFS实验里面有说明

 

 
FLASH_SECTOR_COUNT  这一段的内容是指有多少个扇区块,有什么用呢,在格式化W25Q64的时候,这个就可以认为是我的W25Q64的容量

因为在W25Q64里面是没有MBR/DBR这些大小的,所以需要使用FATFS格式化成一个存储设备

 

要使用格式化就需要使用diskio.c里面的disk_ioctl函数

这是第一个函数。

#if _USE_IOCTL
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
switch(cmd)
{
case CTRL_SYNC:
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = FLASH_BLOCK_SIZE;
res = RES_OK;
break;
case GET_SECTOR_COUNT:
*(DWORD*)buff = FLASH_SECTOR_COUNT;
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
return res;
}
#endif

从函数可以看到,这里需要修改宏定义_USE_IOCTL,这个定义在FATFS附带的头文件ffconf.h里面

#define _USE_WRITE 1 /* 1: Enable disk_write function */
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */

同样在ffconf.h里面,需要配置

#define _USE_MKFS 1 /* 0:Disable or 1:Enable */

/* To enable f_mkfs() function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */

如果不置1,可能编译报错

 

然后是第二个函数,不用理他,一个获取时间的

/*-----------------------------------------------------------------------*/
/* Get current time                                                      */
/*-----------------------------------------------------------------------*/ 
DWORD get_fattime(void)
{
  return RES_OK;

 

第三个函数,获取状态,也不用理他
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber (0..) */
)
{
return RES_OK;
}

 

第四个函数是初始化函数,把自己W25Q64的初始化接口放进去就可以了

DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber (0..) */
)
{
//DSTATUS stat;
uint8_t result;
if(pdrv)
{return STA_NOINIT;}
result = W25Q64Init();
if(result==0)
{return RES_OK;}
else
{return STA_NOINIT;}
}

 

做初始化函数之前,一定要自己测试可以正常读写W25Q64,SD卡也是一样的

一般来说,这四个函数都不会有什么问题,影响成功关键的是读写的接口函数,首先是写的函数,这里最好是一次写512个字节的数据。

我的做法是调用FATFS自带的格式化函数,这个函数会使用到写函数,有一段内容需要写进来,这段内容是DBR,这里提供一个我参考的链接:http://www.devlabs.cn/?p=226

 

我首先在main函数里面挂载文件系统,紧接着格式化设备,一定要先挂载,再格式化,否则可能提示找不着设备

 

			result = f_mount(&fs, "0:", 1);    //挂载文件系统
			result = f_mkfs("0:",0,4096);      //格式化W25Q64,重点刷入DBR数据

挂载文件系统如果返回报错,就用

result = f_mount(&fs, "0:",0);
她们的区别是最后一个参数,1为立即挂载,0是在执行例如OPEN等操作的时候才挂载

 

 

f_mkfs("0:",0,4096);这个建议用我这种,第一个参数是路径,第二个是参数0是需要引导区,1是不要引导区
这里也决定了格式化完了之后是什么设备 0:FDISK, 1:SFD 1是那种超级软盘。


最后一个参数4096可以随便了,大家可以用0 ,自动分配

 

#if _USE_WRITE
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..128) */
)
{
BYTE tmp;
// uint8_t Reardata[FLASH_SECTOR_SIZE];

  if (!count) return RES_PARERR;

for(;count>0;count--)
{
tmp = W25Q64Write(sector*FLASH_SECTOR_SIZE,FLASH_SECTOR_SIZE,(uint8_t*)buff);
// W25Q64Read(sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE, Reardata);
sector++;
buff+=FLASH_SECTOR_SIZE;
}

if(tmp==0)
return RES_OK;
else
return RES_ERROR;
}

 

这个是我的写函数,网上很多帖子没说这里要个什么效果,我这里说一下

执行格式化函数,在FF.H里面会调用这个函数,去写设备的引导区。

第一次进来的时候,也就是sector=0的时候,读取出来要有512个数据,前面510个数据是0,然后紧跟55 AA

第二次进来的时候,sector=0x3f,稍后解释,读出来512个字节,数据里面要有FAT字样,最后两个数据是 55 AA

之后就不要管了,只要做到这个效果,写函数基本完成了。

 

不过如果大家使用的是

f_mkfs("0:",1,4096); 初始化成超级软盘,第一次进来直接就是第二次的数据,就是说第一次就可以看到FAT字样,结尾数据仍然要有

 

 

判断W25Q64是不是有一个可用的文件系统,在FF.H里面

static
BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */
FATFS* fs, /* File system object */
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
)
{
fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */
if (move_window(fs, sect) != FR_OK) /* Load boot record */
return 3;


if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
return 2;


if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
return 0;
if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
return 0;


return 1;
}

首先判断数据结尾是不是55 AA,然后判断有没有FAT字样,这就是我之前要大家注意的两步。

初始化成FDISK,这函数会进来两次,作用是,第一次给写函数的sector=0 ,第二次是0x3f

 

写函数还有个要求,就是这一次写数据,要保证不把同扇区的其它数据给改变了,发一下我的鞋函数

uint8_t W25QXX_BUFFER[4096];
uint8_t W25Q64Write(uint32_t Addr, uint32_t num, uint8_t * data)
{
uint32_t secpos;
uint16_t secoff;
uint16_t secremain;   
  uint16_t i;    
  uint8_t Test_Reardata[512];

  secpos=Addr/4096;//扇区地址
secoff=Addr%4096;//在扇区内的偏移
secremain=4096-secoff;//扇区剩余空间大小

if(num<=secremain) secremain = num;//不大于4096个字节

while(1) 
{
W25Q64Read(secpos*4096,4096,W25QXX_BUFFER);//读出整个扇区的内容

for(i=0;i<secremain;i++)//校验数据
{
if(W25QXX_BUFFER[secoff+i]!=0XFF) break;//需要擦除  
}
if(i<secremain)//需要擦除
{
W25Q64SectorErase(secpos*4096);//擦除整个扇区

for(i=0;i<secremain;i++)   //复制
{
W25QXX_BUFFER[i+secoff]=data[i];  
}
// W25Q64Read(secpos*4096, 512, Test_Reardata);
W25QXX_Write_NoCheck(W25QXX_BUFFER,secpos*4096,4096);//写入整个扇区
}else 
{
W25QXX_Write_NoCheck(data,Addr,secremain);//写入整个扇区  
}
if(num==secremain)break;//写入结束
else//写入未结束
{
secpos++;//扇区地址加1
secoff=0;//偏移位置为0


data+=secremain;  //指针偏移
Addr+=secremain;//写地址偏移
num-=secremain; //字节数递减
if(num>4096)secremain=4096; //下一个扇区写不完
else secremain=num; //写一个扇区可以写完
}  
};  
return 0;
}

然后是读函数

DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to read (1..128) */
)
{
BYTE tmp;

if (!count) return RES_PARERR;

for(;count>0;count--)
{
tmp=W25Q64Read(sector*FLASH_SECTOR_SIZE, FLASH_SECTOR_SIZE, buff);
// HAL_Delay(5);
sector++;
buff+=FLASH_SECTOR_SIZE;
}

buff-=FLASH_SECTOR_SIZE;
if(tmp==0)
return RES_OK;
else
return RES_ERROR;
}

比写要简单,能读512个字节就可以了

 

  • 11
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
首先,需要明确的是,STM32W25Q64是完全不同的产品,它们分别是微控制器和闪存存储器。而FATFS是一个用于嵌入式系统的文件系统。因此,题目中的"STM32 W25Q64 FATFS速度慢"可能涉及到两个方面的问题,即STM32的操作速度与W25Q64芯片的读写速度,以及FATFS文件系统的读写性能。以下我将就这两个方面进行回答。 首先,STM32的速度问题可能与控制器的硬件和软件设计有关。可能是使用了低速的系统时钟频率或者是编写的代码存在效率上的问题。解决这个问题的方法是重新评估系统的时钟配置,以获得更高的处理速度,并且可以通过优化代码来提高程序的执行效率。 其次,W25Q64芯片的读写速度取决于其本身的性能和连接方式。要确保读写速度最大化,首先要确保正确选择了合适的SPI总线时钟,并进行合适的SPI通信设置。其次,在读写数据时需要考虑到W25Q64芯片的数据传输速率以及是否使用了缓存等功能。最后,检查硬件电路的设计与布线是否符合要求,并根据需要进行优化。 最后,FATFS文件系统的读写性能可能与文件系统的配置有关。在初始化FATFS时,需要选择合适的参数来优化文件系统的性能。例如,可以选择合适的簇大小和对齐方式,以减少磁盘片段和提高读写速度。此外,可以根据实际需求进行文件缓存的大小调整,以提高磁盘访问效率。 总结而言,如果STM32的速度慢、W25Q64芯片的读写速度慢或者FATFS的读写性能慢,需要综合考虑硬件和软件层面的因素,并根据具体问题进行适当的优化和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值