FatFs文件系统与底层介质的驱动分离开来,对底层介质的操作都要交给用户去实现,它仅仅是提供了一个函数接口而已。表 25-1为FatFs移植时用户必须支持的函数。通过表 251我们可以清晰知道很多函数是在一定条件下才需要添加的,只有前三个函数是必须添加的。我们完全可以根据实际需求选择实现用到的函数。
前三个函数是实现读文件最基本需求。接下来三个函数是实现创建文件、修改文件需要的。为实现格式化功能,需要在disk_ioctl添加两个获取物理设备信息选项。我们一般只有实现前面六个函数就可以了,已经足够满足大部分功能。
为支持简体中文长文件名称需要添加ff_convert和ff_wtoupper函数,实际这两个已经在cc936.c文件中实现了,我们只要直接把cc936.c文件添加到工程中就可以了。
后面六个函数一般都不用。如真有需要可以参考syscall.c文件(src\option文件夹内)。
表 25-1 FatFs移植需要用户支持函数
函数
条件(ffconf.h)
备注
disk_status
disk_initialize
disk_read
总是需要
底层设备驱动函数
disk_write
get_fattime
disk_ioctl (CTRL_SYNC)
_FS_READONLY == 0
disk_ioctl (GET_SECTOR_COUNT)
disk_ioctl (GET_BLOCK_SIZE)
_USE_MKFS == 1
disk_ioctl (GET_SECTOR_SIZE)
_MAX_SS != _MIN_SS
disk_ioctl (CTRL_TRIM)
_USE_TRIM == 1
ff_convert
ff_wtoupper
_USE_LFN != 0
Unicode支持,为支持简体中文,添加cc936.c到工程即可
ff_cre_syncobj
ff_del_syncobj
ff_req_grant
ff_rel_grant
_FS_REENTRANT == 1
FatFs可重入配置,需要多任务系统支持(一般不需要)
ff_mem_alloc
ff_mem_free
_USE_LFN == 3
长文件名支持,缓冲区设置在堆空间(一般设置_USE_LFN = 2 )
底层设备驱动函数是存放在diskio.c文件,我们的目的就是把diskio.c中的函数接口与QSPI Flash芯片驱动连接起来。总共有五个函数,分别为设备状态获取(disk_status)、设备初始化(disk_initialize)、扇区读取(disk_read)、扇区写入(disk_write)、其他控制(disk_ioctl)。
接下来,我们对每个函数结合QSPI Flash芯片驱动做详细讲解。
设备状态获取代码清单 25-1设备状态获取
1 DSTATUS TM_FATFS_FLASH_SPI_disk_status(BYTE lun)
2 {
3 FLASH_DEBUG_FUNC();
4 if (sFLASH_ID == QSPI_FLASH_ReadID()) { /*检测FLASH是否正常工作*/
5 return TM_FATFS_FLASH_SPI_Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
6 } else {
7 return TM_FATFS_FLASH_SPI_Stat |= STA_NOINIT;
8 }
9 }
TM_FATFS_FLASH_SPI_disk_status函数只有一个参数lun,没有使用。对于QSPI Flash芯片,我们直接调用在QSPI_FLASH_ReadID()获取设备ID,然后判断是否正确,如果正确,函数返回正常标准;如果错误,函数返回异常标志。
设备初始化代码清单 25-2 设备初始化
1 DSTATUS TM_FATFS_FLASH_SPI_disk_initialize(BYTE lun)
2 {
3 GPIO_InitTypeDef GPIO_InitStruct;
4
5 /* 使能 QSPI 及 GPIO 时钟 */
6 QSPI_FLASH_CLK_ENABLE();
7 QSPI_FLASH_CLK_GPIO_ENABLE();
8 QSPI_FLASH_BK1_IO0_CLK_ENABLE();
9 QSPI_FLASH_BK1_IO1_CLK_ENABLE();
10 QSPI_FLASH_BK1_IO2_CLK_ENABLE();
11 QSPI_FLASH_BK1_IO3_CLK_ENABLE();
12 QSPI_FLASH_CS_GPIO_CLK_ENABLE();
13
14 //设置引脚
15 /*!< 配置 QSPI_FLASH 引脚: CLK */
16 GPIO_InitStruct.Pin = QSPI_FLASH_CLK_PIN;
17 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
18 GPIO_InitStruct.Pull = GPIO_NOPULL;
19 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
20 GPIO_InitStruct.Alternate = QSPI_FLASH_CLK_GPIO_AF;
21
22 HAL_GPIO_Init(QSPI_FLASH_CLK_GPIO_PORT, &GPIO_InitStruct);
23
24 /*!< 配置 QSPI_FLASH 引脚: IO0 */
25 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO0_PIN;
26 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO0_AF;
27 HAL_GPIO_Init(QSPI_FLASH_BK1_IO0_PORT, &GPIO_InitStruct);
28
29 /*!< 配置 QSPI_FLASH 引脚: IO1 */
30 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO1_PIN;
31 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO1_AF;
32 HAL_GPIO_Init(QSPI_FLASH_BK1_IO1_PORT, &GPIO_InitStruct);
33
34 /*!< 配置 QSPI_FLASH 引脚: IO2 */
35 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO2_PIN;
36 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO2_AF;
37 HAL_GPIO_Init(QSPI_FLASH_BK1_IO2_PORT, &GPIO_InitStruct);
38
39 /*!< 配置 QSPI_FLASH 引脚: IO3 */
40 GPIO_InitStruct.Pin = QSPI_FLASH_BK1_IO3_PIN;
41 GPIO_InitStruct.Alternate = QSPI_FLASH_BK1_IO3_AF;
42 HAL_GPIO_Init(QSPI_FLASH_BK1_IO3_PORT, &GPIO_InitStruct);
43
44 /*!< 配置 SPI_FLASH_SPI 引脚: NCS */
45 GPIO_InitStruct.Pin = QSPI_FLASH_CS_PIN;
46 GPIO_InitStruct.Alternate = QSPI_FLASH_CS_GPIO_AF;
47 HAL_GPIO_Init(QSPI_FLASH_CS_GPIO_PORT, &GPIO_InitStruct);
48
49 /* QSPI_FLASH 模式配置 */
50
51 hqspi.Instance = QUADSPI;
52 hqspi.Init.ClockPrescaler = 1;
53 hqspi.Init.FifoThreshold = 4;
54 hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
55 hqspi.Init.FlashSize = 23;
56 hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_2_CYCLE;
57 hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
58 HAL_QSPI_Init(&hqspi);
59
60 BSP_QSPI_Init();
61
62 return TM_FATFS_FLASH_SPI_disk_status(NULL);
63
64 }