DSTATUS disk_initialize (BYTE);//SD卡的初始化
DSTATUS disk_status (BYTE);//获取SD卡的状态,这里可以不用管
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);//从SD卡读取数据
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);//将数据写入SD卡,若该文件系统为只读文件系统则不用实现该函数
DRESULT disk_ioctl (BYTE, BYTE, void*);//获取SD卡文件系统相关信息
3)函数实现
FATFS初始化函数:
/* Physical drive nmuber (0..) */
DSTATUS disk_initialize ( BYTE drv )
{
switch (drv)
{
case 0 :
return RES_OK;
case 1 :
return RES_OK;
case 2 :
return RES_OK;
case 3 :
return RES_OK;
default:
return STA_NOINIT;
}
}
/* Physical drive nmuber (0..) */
DSTATUS disk_status ( BYTE drv )
{
switch (drv)
{
case 0 :
return RES_OK;
case 1 :
return RES_OK;
case 2 :
return RES_OK;
default:
return STA_NOINIT;
}
}
FATFS底层读数据函数:
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) */
)
{
if( !count )
{
return RES_PARERR; /* count不能等于0,否则返回参数错误 */
}
switch (drv)
{
case 0:
if(count==1) /* 1个sector的读操作 */
{
return RES_OK;
}
else /* 多个sector的读操作 */
{
return RES_OK;
}
case 1:
if(count==1) /* 1个sector的读操作 */
{
return RES_OK;
}
else /* 多个sector的读操作 */
{
return RES_OK;
}
default:
return RES_ERROR;
}
}
FATFS底层写数据函数:
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) */
)
{
if( !count )
{
return RES_PARERR; /* count不能等于0,否则返回参数错误 */
}
switch (drv)
{
case 0:
if(count==1) /* 1个sector的写操作 */
{
return RES_OK;
}
else /* 多个sector的写操作 */
{
return RES_OK;
}
case 1:
if(count==1) /* 1个sector的写操作 */
{
return RES_OK;
}
else /* 多个sector的写操作 */
{
return RES_OK;
}
default:return RES_ERROR;
}
}
FATFS磁盘控制函数:
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
if (drv==0)
{
switch (ctrl)
{
case CTRL_SYNC :
return RES_OK;
case GET_SECTOR_COUNT :
return RES_OK;
case GET_BLOCK_SIZE :
return RES_OK;
case CTRL_POWER :
break;
case CTRL_LOCK :
break;
case CTRL_EJECT :
break;
/* MMC/SDC command */
case MMC_GET_TYPE :
break;
case MMC_GET_CSD :
break;
case MMC_GET_CID :
break;
case MMC_GET_OCR :
break;
case MMC_GET_SDSTAT :
break;
}
}else if(drv==1){
switch (ctrl)
{
case CTRL_SYNC :
return RES_OK;
case GET_SECTOR_COUNT :
return RES_OK;
case GET_SECTOR_SIZE :
return RES_OK;
case GET_BLOCK_SIZE :
return RES_OK;
case CTRL_POWER :
break;
case CTRL_LOCK :
break;
case CTRL_EJECT :
break;
/* MMC/SDC command */
case MMC_GET_TYPE :
break;
case MMC_GET_CSD :
break;
case MMC_GET_CID :
break;
case MMC_GET_OCR :
break;
case MMC_GET_SDSTAT :
break;
}
}
else{
return RES_PARERR;
}
return RES_PARERR;
}
以上函数都只是实现一个框架,并没有做实际的事情,下一步就需要把操作SD卡的程序填充在这个框架里面。
4)实现 disk_initialize() 函数
该函数在挂载文件系统的时候会被调用,主要是实现读写SD卡前对SD卡进行初始化,根据SD卡的传输协议,我们按照如下步骤初始化SD卡:
a、判断SD卡是否插入,可以通过检查SD卡卡座的CD脚电平进行判断,一般插入卡后该引脚会变成低电平;
b、稍微延时一段时间后发送至少74个时钟给SD卡;
c、发送CMD0命令给SD卡,直到SD卡返回0x01为止,这里可以循环多次发送;
程序如下:
/* Start send CMD0 till return 0x01 means in IDLE state */
for(retry=0; retry<0xFFF; retry++)
{
r1 = MSD0_send_command(CMD0, 0, 0x95);
if(r1 == 0x01)
{
retry = 0;
break;
}
}
d、发送CMD8获取卡的类型,不同类型的卡其初始化方式有所不同;
e、根据卡的类型对卡进行初始化。具体初始化方式可以参考附件程序;
注:在初始化SD卡之前应该初始化SPI接口和相关的管脚。
实现后的程序如下:
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0..) */
)
{
int Status;
switch (drv)
{
case 0 :
Status = MSD0_Init();
if(Status==0){
return RES_OK;
}else{
return STA_NOINIT;
}
case 1 :
return RES_OK;
case 2 :
return RES_OK;
case 3 :
return RES_OK;
default:
return STA_NOINIT;
}
}
MSD0_Init()函数在SPI_MSD0_Driver.c文件中实现。
5)实现disk_read()函数
该函数是读取SD卡扇区数据的函数,根据SD卡数据传输协议可知有读取单扇区和读取多扇区两种操作模式,为提高读文件的速度应该实现读取多扇区函数。
实现后的程序如下:
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) */
)
{
int Status;
if( !count )
{
return RES_PARERR; /* count不能等于0,否则返回参数错误 */
}
switch (drv)
{
case 0:
if(count==1) /* 1个sector的读操作 */
{
Status = MSD0_ReadSingleBlock( sector ,buff );
if(Status == 0){
return RES_OK;
}else{
return RES_ERROR;
}
}
else /* 多个sector的读操作 */
{
Status = MSD0_ReadMultiBlock( sector , buff ,count);
if(Status == 0){
return RES_OK;
}else{
return RES_ERROR;
}
}
case 1:
if(count==1) /* 1个sector的读操作 */
{
return RES_OK;
}
else /* 多个sector的读操作 */
{
return RES_OK;
}
default:
return RES_ERROR;
}
}
MSD0_ReadSingleBlock()和MSD0_ReadMultiBlock()函数都是SD卡操作的底层函数,我们在SPI_MSD0_Driver.c文件中实现。
6)实现disk_write()函数
该函数主要实现对SD卡进行写数据操作,和读数据操作一样也分单块写和多块写,建议实现多块写的方式,这样可以提高写数据速度。
实现后的程序如下:
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) */
)
{
int Status;
if( !count )
{
return RES_PARERR; /* count不能等于0,否则返回参数错误 */
}
switch (drv)
{
case 0:
if(count==1) /* 1个sector的写操作 */
{
Status = MSD0_WriteSingleBlock( sector , (uint8_t *)(&buff[0]) );
if(Status == 0){
return RES_OK;
}else{
return RES_ERROR;
}
}
else /* 多个sector的写操作 */
{
Status = MSD0_WriteMultiBlock( sector , (uint8_t *)(&buff[0]) , count );
if(Status == 0){
return RES_OK;
}else{
return RES_ERROR;
}
}
case 1:
if(count==1) /* 1个sector的写操作 */
{
return RES_OK;
}
else /* 多个sector的写操作 */
{
return RES_OK;
}
default:return RES_ERROR;
}
}
MSD0_WriteSingleBlock()和MSD0_WriteMultiBlock()函数都是SD卡操作的底层函数,我们在SPI_MSD0_Driver.c文件中实现。
7)实现disk_ioctl()函数
该函数在磁盘格式化、获取文件系统信息等操作时会被调用。
实现后的程序如下:
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
if (drv==0)
{
MSD0_GetCardInfo(&SD0_CardInfo);
switch (ctrl)
{
case CTRL_SYNC :
return RES_OK;
case GET_SECTOR_COUNT :
*(DWORD*)buff = SD0_CardInfo.Capacity/SD0_CardInfo.BlockSize;
return RES_OK;
case GET_BLOCK_SIZE :
*(WORD*)buff = SD0_CardInfo.BlockSize;
return RES_OK;
case CTRL_POWER :
break;
case CTRL_LOCK :
break;
case CTRL_EJECT :
break;
/* MMC/SDC command */
case MMC_GET_TYPE :
break;
case MMC_GET_CSD :
break;
case MMC_GET_CID :
break;
case MMC_GET_OCR :
break;
case MMC_GET_SDSTAT :
break;
}
}else if(drv==1){
switch (ctrl)
{
case CTRL_SYNC :
return RES_OK;
case GET_SECTOR_COUNT :
return RES_OK;
case GET_SECTOR_SIZE :
return RES_OK;
case GET_BLOCK_SIZE :
return RES_OK;
case CTRL_POWER :
break;
case CTRL_LOCK :
break;
case CTRL_EJECT :
break;
/* MMC/SDC command */
case MMC_GET_TYPE :
break;
case MMC_GET_CSD :
break;
case MMC_GET_CID :
break;
case MMC_GET_OCR :
break;
case MMC_GET_SDSTAT :
break;
}
}
else{
return RES_PARERR;
}
return RES_PARERR;
}
MSD0_GetCardInfo()函数也在SPI_MSD0_Driver.c文件中实现,其中SD0_CardInfo为PMSD_CARDINFO类型的全局变量,它在SPI_MSD0_Driver.h文件中被定义。
8)到此diskio.c这个文件中的所有函数就已经实现,下一步就是实现SPI_MSD0_Driver.c文件中的相关函数。
4、文件系统测试
1)测试写文件
测试代码如下:
printf("write file test......
");
res = f_open(&fdst, "0:/test.txt", FA_CREATE_ALWAYS | FA_WRITE);
if(res != FR_OK){
printf("open file error : %d
",res);
}else{
res = f_write(&fdst, textFileBuffer, sizeof(textFileBuffer), &bw); /* Write it to the dst file */
if(res == FR_OK){
printf("write data ok! %d
",bw);
}else{
printf("write data error : %d
",res);
}
/*close file */
f_close(&fdst);
}
注意:成功打开文件后一定要调用f_close()函数,否则数据无法写入SD卡中。
2)测试读文件
printf("read file test......
");
res = f_open(&fsrc, "0:/test.txt", FA_OPEN_EXISTING | FA_READ);
if(res != FR_OK){
printf("open file error : %d
",res);
}else{
res = f_read(&fsrc, buffer, sizeof(textFileBuffer), &br); /* Read a chunk of src file */
if(res==FR_OK){
printf("read data num : %d
",br);
printf("%s
",buffer);
}else{
printf("read file error : %d
",res);
}
/*close file */
f_close(&fsrc);
}
refer:
http://bbs.21ic.com/icview-883729-1-1.html