一、工具
1、硬件:GD32F30x系列单片机
2、编译环境:KEIL
3、Flash芯片:GD25Q256DF
二、移植FatFs文件系统到单片机
关于外部Flash的驱动程序,请看链接:
关于USB设备模式下把外部Flash模拟成U盘的程序,请看链接:
1、找到官方提供的固件库中的FatFs文件夹,整体拷贝到自己工程中,如下图所示:
2、打开自己的工程,创建一个“Fatfs”文件夹并添加上面拷贝的文件夹的部分文件,如下图所示:
- ff.c文件包含了FatFs文件系统的整个核心内容,包含了操作文件系统的功能函数,不用修改;
- fattime.c文件是用于获取当前的时间的,该时间用于设定文件的创建或修改时间,有需求的可以进去添加获取实时时间的操作;
- diskio.c文件属于接口文件,用于和底层读写函数进行衔接的地方,是移植Fatfs文件系统重点修改的地方;
- ccsbcs.c文件用于不同编码的转换,不用修改;
- ffconf.h文件是FatFs文件系统的配置文件,用户可根据需求对文件系统进行配置,也是移植Fatfs文件系统重点修改的地方。
3、修改diskio.c文件
这三个宏定义代表着三个不同的设备,我只用一个,故删掉。
修改初始化设备函数,我要放在外面进行初始化,这里就默认初始化成功,如下所示:
/*-----------------------------------------------------------------------*/
/* Inicializes a Drive */
DSTATUS disk_initialize (BYTE drv) /* Physical drive nmuber (0..) */
{
DSTATUS stat = STA_NOINIT;
stat &= ~STA_NOINIT;
return stat;
}
修改获取状态函数,通过读取外部Flash的ID判断其状态,因为只有一个设备,设备号可以不用管,如下所示:
/*-----------------------------------------------------------------------*/
/* Return Disk Status */
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0..) */
)
{
DSTATUS stat;
if(gd25q256df_read_id() == 0xC84019)
{
stat = RES_OK;
}
else
{
stat = RES_ERROR;
}
return stat;
}
修改磁盘读函数,因为只有一个设备,设备号可以不用管,如下所示:
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
DRESULT disk_read (
BYTE drv, /* 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..255) */
)
{
DRESULT res;
gd25q256df_read_data(buff, sector*512, count*512);
res = RES_OK;
return res;
}
修改磁盘写函数,因为只有一个设备,设备号可以不用管,如下所示:
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0..) */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address (LBA) */
BYTE count /* Number of sectors to write (1..255) */
)
{
DRESULT res;
gd25q256df_write_data(buff, sector*512, count*512);
res = RES_OK;
return res;
}
修改磁盘I/O控制函数,因为只有一个设备,设备号可以不用管,如下所示:
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
switch(ctrl)
{
case GET_SECTOR_COUNT:
*(DWORD *)buff = 65536;
break;
case GET_SECTOR_SIZE:
*(WORD *)buff = 512;
break;
case GET_BLOCK_SIZE:
/* 暂时未用 */
break;
}
res = RES_OK;
return res;
}
4、文件系统读写测试
相关变量定义
uint32_t flash_id;
FATFS fs;
FIL file;
FRESULT res_flash;
uint8_t g_TestBuf1[] = "12345hello world 今天是个好日子,123456\r\n";
uint8_t g_TestBuf2[] = "hello world\r\n";
uint8_t g_ReadBuf[128];
uint32_t bw;
主函数中实现文件的创建和读取,验证FatFs移植是否成功
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
/* configure 4 bits pre-emption priority */
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
bsp_spi1_init();
gd25q256df_init();
flash_id = gd25q256df_read_id();
if(flash_id == 0xC84019)
{
/* 挂载设备 */
res_flash = f_mount (1, &fs);
if (res_flash == FR_OK)
{
/* 打开或者创建文件 */
res_flash = f_open(&file, "1:test1.txt", FA_CREATE_ALWAYS | FA_WRITE);
if(res_flash == FR_OK)
{
/* 向文件件中写数据 */
res_flash = f_write(&file, g_TestBuf1, sizeof(g_TestBuf1), &bw);
if (res_flash != FR_OK)
{
while(1);
}
/* 关闭文件 */
f_close(&file);
}
/* 打开或者创建文件 */
res_flash = f_open(&file, "1:test2.txt", FA_CREATE_ALWAYS | FA_WRITE);
if(res_flash == FR_OK)
{
/* 向文件件中写数据 */
res_flash = f_write(&file, g_TestBuf2, sizeof(g_TestBuf2), &bw);
if (res_flash != FR_OK)
{
while(1);
}
/* 关闭文件 */
f_close(&file);
}
/* 以读的方式打开文件 */
res_flash = f_open(&file, "1:test2.txt", FA_OPEN_EXISTING | FA_READ);
if(res_flash == FR_OK)
{
res_flash = f_read(&file, g_ReadBuf, sizeof(g_ReadBuf), &bw);
if(res_flash != FR_OK)
{
while(1);
}
/* 关闭文件 */
f_close(&file);
}
}
/* 卸载文件 */
res_flash = f_mount (1, NULL);
}
}
通过调试,可以发现是能够成功读取前面创建的文件中的内容,如下图所示:
四、扩展功能
为了能够更直观看到文件系统创建的文件和写入的内容,我结合了单片机的USB设备模式,把外部Flash模拟成一个U盘,能够直接在电脑查看创建的文件。
相关变量定义及初始化
usb_core_handle_struct usbhs_core_dev =
{
.dev =
{
.dev_desc = (uint8_t *)&device_descripter,
.config_desc = (uint8_t *)&configuration_descriptor,
.strings = usbd_strings,
.class_init = msc_init,
.class_deinit = msc_deinit,
.class_req_handler = msc_req_handler,
.class_data_handler = msc_data_handler
},
.udelay = delay_us,
.mdelay = delay_ms
};
void usb_clock_config(void);
void usb_gpio_config(void);
void usb_interrupt_config(void);
uint8_t timer_prescaler = 0;
uint32_t usbfs_prescaler = 0;
主函数中实现文件的创建并写入数据,写入完成后初始化并启动USB设备
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
/* configure 4 bits pre-emption priority */
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
bsp_spi1_init();
gd25q256df_init();
flash_id = gd25q256df_read_id();
if(flash_id == 0xC84019)
{
/* 挂载设备 */
res_flash = f_mount (1, &fs);
if (res_flash == FR_OK)
{
/* 打开或者创建文件 */
res_flash = f_open(&file, "1:test1.txt", FA_CREATE_ALWAYS | FA_WRITE);
if(res_flash == FR_OK)
{
/* 向文件件中写数据 */
res_flash = f_write(&file, g_TestBuf1, sizeof(g_TestBuf1), &bw);
if (res_flash != FR_OK)
{
while(1);
}
/* 关闭文件 */
f_close(&file);
}
/* 打开或者创建文件 */
res_flash = f_open(&file, "1:test2.txt", FA_CREATE_ALWAYS | FA_WRITE);
if(res_flash == FR_OK)
{
/* 向文件件中写数据 */
res_flash = f_write(&file, g_TestBuf2, sizeof(g_TestBuf2), &bw);
if (res_flash != FR_OK)
{
while(1);
}
/* 关闭文件 */
f_close(&file);
}
}
/* 卸载文件 */
res_flash = f_mount (1, NULL);
}
/* configure USB clock */
usb_clock_config();
/* USB timer configure */
timer_nvic_init();
/* USB device stack configure */
usbd_init(&usbhs_core_dev, USB_FS_CORE_ID);
/* USB interrupt configure */
usb_interrupt_config();
/* check if USB device is enumerated successfully */
while (usbhs_core_dev.dev.status != USB_STATUS_CONFIGURED) {}
while(1);
}
测试结果如下图所示:
#endif