#define ATA 0// 预留 SD 卡使用
#define SPI_FLASH 1// 外部 SPI Flash
DSTATUS disk_status(BYTE pdrv)
{
DSTATUS status = STA_NOINIT;
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH:
/* SPI Flash 状态检测:读取 SPI Flash 设备 ID */
if (sFLASH_ID == SPI_FLASH_ReadID()) {
/* 设备 ID 读取结果正确 */
status &= ~STA_NOINIT;
} else {
/* 设备 ID 读取结果错误 */
status = STA_NOINIT;
}
break;
default:
status = STA_NOINIT;
}
return status;
}
这是一个用于获取磁盘状态的函数,具体分析如下:
函数声明:
DSTATUS disk_status(BYTE pdrv);
该函数返回一个 DSTATUS
类型的状态,接受一个 BYTE
类型的参数 pdrv
。
局部变量初始化:
DSTATUS status = STA_NOINIT;
在函数一开始,status
被初始化为 STA_NOINIT
,这是磁盘状态的初始值。
Switch 语句:
pdrv
等于 ATA
,则执行一个空操作(break
),表示SD卡。pdrv
等于 SPI_FLASH
,则进行SPI Flash状态检测。
SPI_FLASH_ReadID()
读取的值,那么将 status
的 STA_NOINIT
标志位清零。status
设置为 STA_NOINIT
。pdrv
不是上述两者之一,将 status
设置为 STA_NOINIT
。返回状态:
return status;
返回最终的磁盘状态。
DSTATUS disk_initialize(BYTE pdrv)
{
uint16_t i;
DSTATUS status = STA_NOINIT;
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH: /* SPI Flash */
/* 初始化 SPI Flash */
SPI_FLASH_Init();
/* 延时一小段时间 */
i = 500;
while (--i);
/* 唤醒 SPI Flash */
SPI_Flash_WAKEUP();
/* 获取 SPI Flash 芯片状态 */
status = disk_status(SPI_FLASH);
break;
default:
status = STA_NOINIT;
}
return status;
}
这是一个用于初始化磁盘的函数,具体分析如下:
函数声明:
DSTATUS disk_initialize(BYTE pdrv);
该函数返回一个 DSTATUS
类型的状态,接受一个 BYTE
类型的参数 pdrv
。
局部变量初始化:
uint16_t i;
DSTATUS status = STA_NOINIT;
在函数一开始,定义了一个 uint16_t
类型的变量 i
用于延时,同时将 status
初始化为 STA_NOINIT
,即磁盘状态的初始值。
Switch 语句:
pdrv
等于 ATA
,则执行一个空操作(break
),表示SD卡。pdrv
等于 SPI_FLASH
,则进行SPI Flash的初始化过程。
disk_status
函数。返回状态:
return status;
返回最终的磁盘初始化状态。
总体来说,该函数用于根据输入的磁盘编号 pdrv
进行初始化操作,主要处理了SD卡和SPI Flash的情况,包括SPI Flash的初始化、唤醒以及获取芯片状态。最终返回磁盘的初始化状态。
DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
DRESULT status = RES_PARERR;
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH:
/* 扇区偏移 2MB,外部 Flash 文件系统空间放在 SPI Flash 后面 6MB 空间 */
sector += 512;
SPI_FLASH_BufferRead(buff, sector << 12, count << 12);
status = RES_OK;
break;
default:
status = RES_PARERR;
}
return status;
}
typedef unsigned char BYTE;
/* These types MUST be 16-bit */
typedef short SHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types MUST be 16-bit or 32-bit */
typedef int INT;
typedef unsigned int UINT;
/* These types MUST be 32-bit */
typedef long LONG;
typedef unsigned long DWORD;
外部flash读写起始地址为512*4096 也就是2*1024*1024 为2MB
/* 扇区偏移 2MB,外部 Flash 文件系统空间放在 SPI Flash 后面 6MB 空间 */
sector += 512;
SPI_FLASH_BufferRead(buff, sector << 12, count << 12);
/*
左移 12 位实际是乘以 4096
SPI_FLASH_BufferRead(buff,sector*4096,count*4096);
*/
status = RES_OK;
break;
开发板使用的 SPI Flash 芯片型号为 W25Q64FV,每个扇区大小为 4096 个字节 (4KB),总共有 8M字节空间,为兼容后面实验程序,我们只将后部分 6MB 空间分配给 FatFs 使用,前部分 2MB 空间用于其他实验需要,即 FatFs 是从 2MB 空间开始,为实现这个效果需要将所有的读写地址都偏移 512 个扇区空间。
DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) {
uint32_t write_addr;
DRESULT status = RES_PARERR;
if (!count) {
return RES_PARERR; /* Check parameter */
}
switch (pdrv) {
case ATA: /* SD CARD */
break;
case SPI_FLASH:
/* 扇区偏移 2MB,外部 Flash 文件系统空间放在 SPI Flash 后面 6MB 空间 */
sector += 512;
write_addr = sector << 12;
//先擦除再写入
SPI_FLASH_SectorErase(write_addr);
SPI_FLASH_BufferWrite((u8 *)buff, write_addr, count << 12);
status = RES_OK;
break;
default:
status = RES_PARERR;
}
return status;
}
同的读取扇区同理,不过一定要记得写入前要擦除
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 SD_CARD :
// Process of the command for the ATA drive
return res;
case SPI_FLASH :
switch(cmd)
{
//返回扇区个数
case GET_SECTOR_COUNT:
/* 扇区数量:1536*4096/1024/1024=6(MB) */
*(DWORD*)buff = 1536;
break;
//返回每个扇区大小
case GET_SECTOR_SIZE:
*(WORD*)buff = 4096;
break;
//返回擦除扇区的最小个数(单位为扇区)
case GET_BLOCK_SIZE:
*(WORD*)buff = 1;
break;
}
// Process of the command for the MMC/SD card
res = RES_OK;
return res;
}
__weak DWORD get_fattime(void)
{
/* 返回当前时间戳 */
return ((DWORD)(2015 - 1980) << 25) /* Year 2015 */
| ((DWORD)1 << 21) /* Month 1 */
| ((DWORD)1 << 16) /* Mday 1 */
| ((DWORD)0 << 11) /* Hour 0 */
| ((DWORD)0 << 5) /* Min 0 */
| ((DWORD)0 >> 1); /* Sec 0 */
}