STM32F407-移植FATFS
上一节操作完flash后,这一节给flash安装文件系统,通过文件系统方式访问flash;
这就需要移植嵌入式领域的文件系统FATFS;
FATFS是开源项目,可在其官网下载源码;
本案例使用的时V0.11
FATFS移植步骤
主要需要修改以下FATFS底层几个驱动接口,让其关联到flash;
1、disk_status()
检查当前设备是否准备就绪;返回值主要为修改此状态,STA_NOINIT;
准备就绪清掉 此状态STA_NOINIT;
没有准备就绪立此状态 STA_NOINIT;
pdrv值传入的设备编号;这里将FLASH定义为1;
#define DEV_SD 0
#define DEV_FLASH 1
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat = STA_NOINIT;
switch(pdrv)
{
case DEV_SD:
{
break;
}
case DEV_FLASH:
{
if(My_Flash_Read_ID() == 0x17)
{
stat &= ~STA_NOINIT;
}
else
{
stat = STA_NOINIT;
}
break;
}
default:
break;
}
return stat;
}
2、disk_initialize()
主要进行底层驱动初始化,本案例为调用 flash初始化
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
switch(pdrv)
{
case DEV_SD:
{
break;
}
case DEV_FLASH:
{
My_Flash_Init();
stat = disk_status(DEV_FLASH);
break;
}
default:
break;
}
return stat;
}
3、disk_read()
调用 FLASH读函数
这里会引入扇区sector的概念;本案例中将扇区大小配成 FLASH的扇区大小;4096
#define FLASH_SECTOR_SIZE 4096
count指有几个扇区sector
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 DEV_SD:
{
break;
}
case DEV_FLASH:
{
My_FLASH_Read_Buff(sector * FLASH_SECTOR_SIZE,(void *)buff, count * FLASH_SECTOR_SIZE);
res = RES_OK;
break;
}
default:
break;
}
return res;
}
4、disk_write()
调用FLASH读函数
注意点:
flash写入时需要先擦除;
所以要先调用擦除函数,再写;
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;
switch(pdrv)
{
case DEV_SD:
{
break;
}
case DEV_FLASH:
{
while(count--)
{
//写入前先擦除
My_FLASH_Erase_Sector(sector * FLASH_SECTOR_SIZE);
//把要写入的扇区号转换成地址
My_FLASH_Write_Buff(sector * FLASH_SECTOR_SIZE,(u8*)buff, FLASH_SECTOR_SIZE);
sector++;
buff += FLASH_SECTOR_SIZE;
}
res = RES_OK;
break;
}
default:
break;
}
return res;
}
5、disk_ioctl()
这里主要需要告诉FATFS扇区大小及个数
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 DEV_SD:
{
break;
}
case DEV_FLASH:
{
switch(cmd)
{
//存储介质有多少个sector,文件系统通过该值获得存储介质的容量
case GET_SECTOR_COUNT:
*(DWORD *)buff = (16*1024*1024/FLASH_SECTOR_SIZE);//4096-1536
res = RES_OK;
break;
//每个扇区的个数
case GET_SECTOR_SIZE:
*(DWORD *)buff = FLASH_SECTOR_SIZE;
res = RES_OK;
break;
//获取擦除的最小个数, 以sector为单位
case GET_BLOCK_SIZE:
*(DWORD *)buff = 1;
res = RES_OK;
break;
//写入同步在disk_write函数已经完成,这里默认返回ok
case CTRL_SYNC:
res = RES_OK;
break;
default:
res = RES_PARERR;
break;
}
break;
}
default:
break;
}
return res;
}
6、get_fattime()
这个函数需要是FATFS获取文件时间;本例没有实现,直接返回了0;
其他配置
除了上述6个驱动函数需要实现外;以下几个地方也需要注意修改,均在ffconf.h中:
1、虚拟设备个数
本案例中用了两个设备;
0:SD (未实现)
1:FLASH (已实现)
所以这里设备个数配置为2
2、扇区空间大小
本案例中扇区大小定义为 4096;所以最大上限需要修改:
3、打开制作文件系统开关
FLASH之前没有被制作为文件系统,所以要首先制作为文件系统;需要打开该开关;否则无法调用相关函数;
FATFS功能调用
直接上代码
printf("下边是FATFS实验\n");
ret = f_mount(&fs,"1:",1); //先挂载
printf("f_mount is %d\n",ret);
if(ret == FR_NO_FILESYSTEM) //没有文件系统
{
ret = f_mkfs("1:",0,0 ); //制作文件系统
printf("f_mkfs is %d\n",ret);
f_mount(0, "1:", 1);
ret = f_mount(&fs,"1:",1);
printf("f_mount is %d\n",ret);
}
#if 1
//写数据
ret = f_open(&fil, "1:/t", FA_READ|FA_WRITE | FA_CREATE_ALWAYS);
printf("f_open is %d\n",ret);
ret = f_write(&fil, mystrval, strlen(mystrval) +1, &bw);
printf("f_write is %d, write number is %d\n",ret,bw);
f_close(&fil);
//读数据
ret = f_open(&fil, "1:/t", FA_READ|FA_WRITE | FA_OPEN_EXISTING);
printf("f_open is %d\n",ret);
if(ret == 0)
{
ret = f_read(&fil, data, sizeof(data), &bw);
printf("f_read is %d, read number is %d,value is %s\n",ret,bw,data);
}
#endif
f_close(&fil);
f_mount(0, "1:", 1);
需要注意的函数说明
1、f_mount函数说明
这个函数相当于挂载;将FLASH挂载到程序中;
传入的第一个参数为设备结构体;由于该结构体很大,最好定义为全局变量,防止出现栈溢出;
传入0,或者NULL,表示卸载
第二个参数:为设备号,FLASH设备号为1;另外冒号需要带上;"1:"
第三个参数:1:表示立即挂载;0:稍后挂载
2、f_mkfs函数说明
这个就是制作文件系统的函数;这里需要注意;首先要先挂载;制作完成后,需要卸载再挂载;
如果不挂载就直接调用该函数会报 FR_NOT_ENABLED
的错误
参数1:设备号
参数2:文件格式 0:硬盘 1:软盘
参数3:扇区个数;0:FATFS自己计算
3、f_open、f_read 、f_write函数
这几个函数和标准文件操作函数类似,一般没啥问题;这里需要注意两个问题:
1)文件结构体尽量也要定义为全局;可能空间太大导致问题
2)如果f_open返回 FR_NO_FILE
报错;在代码都正确的情况下;可能是底层驱动的几个函数,类型转换时出的问题;disk_ioctl、disk_write、disk_read这三个函数中可能存在数据类型转换导致的一些数据问题;