菜鸟求助喽……高手赐教哦……
这几天学习FATFS文件系统,上网查资料说是这可以移植到51、AVR、ARM等各种微控制器中,其FATFS特点如下:
1、分离缓冲的FAT结构和每一个文件,适合快速访问多个文件。
2、支持多个驱动器和分区。
3、支持FAT12 , FAT16和FAT32 。
4、支持8.3格式的文件名(LFN不支持)
5、支持两个分区规则: Fdisk和超级软盘。
6、优化8/16-bit微控制器。
FatFs Module一开始就是为了能在不同的单片机上使用而设计的,所以具有良好的层次结构,如图1所示。最顶层是应用层,使用者无需理会FatFs Module的内部结构和复杂的FAT协议,只需要调用FatFs Module提供给用户的一系列应用接口函数,如f_open,f_read,f_write、f_close等,就可以像在PC上读/写文件那样简单。
中间层FatFs Module实现了FAT文件读/写协议。FatFs Module的完全版提供的是ff.c、ff.H,除非有必要,使用者一般不用修改,使用时将需要版本的头文件直接包含进去即可。需要使用者编写移植代码的是FatFs Module提供的底层接口,它包括存储媒介读/写接口DiskIO和供给文件创建修改时间的实时时钟,包括{
disk_initialize -初始化的磁盘驱动器
disk_status -获取磁盘状态
disk_read -读部门(星期日)
disk_write -收件部门(星期日)
disk_ioctl -控制装置依赖功能
get_fattime -获取当前时间 }等这些函数。
我做过这些工作后,调试,没成功,错误发现时在发送过复位命令后在激活的过程中,激活命令发出后,便一直在等待响应,然后超时就返回了。
下面是我写的底层接口函数,高手看看哪里有错误,指教一下,万分感激!
#include<LPC213x.h>
#include"config.h"
#include "diskio.h"
#include"integer.h"
/* Definitions for MMC/SDC command */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
#define ACMD41 (0xC0+41)
BYTE respbuf[5];
static volatile
DSTATUS Stat = STA_NOINIT; /* Disk status */
/*******************************************************************************************************************
** 函数名称: void SD_Power() Name: void SD_Power()
** 功能描述: 对卡先下电,再上电 Function: turn off the card's power, and turn on
** 输 入: 无 Input: NULL
** 输 出: 无 Output: NULL
********************************************************************************************************************/
void SD_Power(void)
{
UINT i;
SD_POWER_GPIO();
SD_POWER_OUT();
SD_POWER_OFF(); /* 关闭 SD 卡电源 turn off power of sd card */
SPI_SCK_GPIO();
SPI_SCK_OUT();
SPI_SCK_CLR(); /* SCK 引脚置低 set SCK to zero */
SPI_MISO_GPIO();
SPI_MISO_OUT();
SPI_MISO_CLR(); /* MISO 引脚置低 set MISO to zero */
SPI_MOSI_GPIO();
SPI_MOSI_OUT();
SPI_MOSI_CLR(); /* MOSI 引脚置低 set MOSI to zero */
SPI_CS_GPIO();
SPI_CS_OUT();
SPI_CS_CLR(); /* CS 引脚置低 set CS to zero */
for(i = 0; i < 0x9000; i++); /* 关闭电源延时 delay after turn off power of sd card */
SD_POWER_ON(); /* 打开 SD 卡电源 turn on power of sd card */
}
/*******************************************************************************************************************
** 函数名称: void SD_HardWareInit() Name: void SD_HardWareInit()
** 功能描述: 初始化访问SD卡的硬件条件 Function: initialize the hardware condiction that access sd card
** 输 入: 无 Input: NULL
** 输 出: 无 Output: NULL
********************************************************************************************************************/
void SD_HardWareInit(void)
{
SD_Power(); /* 对卡先下电,再上电 turn off power of card, and turn on it */
SPI_INIT(); /* 初始化SPI接口 initialize SPI interface */
SD_INSERT_GPIO();
SD_INSERT_IN(); /* 检测卡完全插入口为输入口 the port checking card is input */
SD_WP_GPIO();
SD_WP_IN(); /* 写保护检测口为输入口 the port written protect is input */
SPI_CS_SET(); /* CS置高 set CS to high voltage */
S0SPCCR = 128; /* 设置SPI频率小于等于400kHZ set frequency of SPI below 400kHZ */
S0SPCR = (0x01 << 4) + (0x01 << 5); /* 设置SPI接口模式,MSTR = 1,CPOL = 1,CPHA = 0,LSBF=0 */
} /* configure SPI interface */
BYTE SPI_SendByte(BYTE dat)
{
BYTE temp;
S0SPDR = dat; /* 发送数据放入SPI数据寄存器 */
while(0 == (S0SPSR & 0x80)); /* 等待SPIF置位,即等待数据发送完毕 */
/* wait for SPIF being set, that is, wait for finishing of data being send */
temp = S0SPDR;
return temp;
}
void SD_SPIDelay(BYTE value)
{
BYTE i;
for (i = 0; i < value; i++)
SPI_SendByte(0xFF); /* 发送0xFF clock out 0xFF */
}
/*********************************************************
下面为一些数据传输函数
**********************************************************/
BOOL Read_BlockData(BYTE *buffer,UINT count)
{
BYTE tmp;
UINT i;
SPI_CS_CLR();
i = 69120;
do
{
tmp = SPI_SendByte(0xff);
}while((tmp == 0xff)&&(i--));
if(i==0) return FALSE;
if(tmp != 0xfe) return FALSE;
for(i=0;i<count;i++)
{
buffer = SPI_SendByte(0xff);
}
SPI_SendByte(0xff);
SPI_SendByte(0xff);
SPI_CS_SET();
SPI_SendByte(0xff);
return TRUE;
}
#if _READONLY == 0
BOOL Write_BlockData(BYTE *buffer,BYTE token)
{
BYTE tmp;
UINT count;
SPI_CS_CLR();
SPI_SendByte(0xff);
SPI_SendByte(token);
if(token != 0xfd)
{
count = 512;
while(count--) SPI_SendByte(*buffer++);
SPI_SendByte(0xff);
SPI_SendByte(0xff);
tmp = SPI_SendByte(0xff);
if((tmp&0x1f) != 0x05) return FALSE;
}
return TRUE;
}
#endif /* _READONLY */
BOOL SD_SendCmd( BYTE cmd, UINT arg, BYTE resptype, BYTE *resp)
{
BYTE tmp,i;
CHAR j;
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
tmp = SD_SendCmd(CMD55, 0);
if (tmp != TRUE) return FALSE;
}
SPI_CS_CLR();
SPI_SendByte(0xff); //发命令前延时8个SPI时钟
SPI_SendByte(cmd);
SPI_SendByte(arg >> 24);
SPI_SendByte(arg >> 16);
SPI_SendByte(arg >> 8);
SPI_SendByte(arg);
SPI_SendByte(0x95);
i = 100;
do
{
tmp = SPI_SendByte(0xff);
}while(((tmp&0x80) != 0) && (i--));
if(i==0) return FALSE;
for(j=resptype-1;j >= 0;j--)
{
resp[j] = SPI_SendByte(0xff);
}
SPI_SendByte(0xff);
SPI_CS_SET();
SPI_SendByte(0xff);
return TRUE;
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0) */
)
{
BYTE tmp,ocrbuf[4];
UINT j;
if (drv) return STA_NOINIT; /* Supports only single drive */
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
SD_HardWareInit();
if(SD_INSERT_STATUS() != 0) return 0;
SPI_CS_CLR();
SD_SPIDelay(25);
SPI_CS_SET();
SD_SPIDelay(2);
tmp = SD_SendCmd( CMD0, 0, 1, respbuf);
if(tmp != 1) return 0;
j=0;
SD_SendCmd( ACMD41, 0, 1, respbuf);
do{
tmp = SD_SendCmd( CMD1, 0, 1, respbuf);
if(tmp != 1) return 0;
j++;
}while(((respbuf[0]&0x01) == 0x01) &&(j < 1000));
if(j >= 1000) return 0;
tmp = SD_SendCmd( CMD58, 0, 5, respbuf);
if(tmp != 1) return 0;
if(respbuf[0] != 0) return 0;
for(j=0;j<4;j++)
{
ocrbuf[j] = respbuf[j+1];
}
if((ocrbuf[1]&0xc0) != 0xc0) return 0;
S0SPCCR = 8;
tmp = SD_SendCmd(CMD16,512,1,respbuf);
if(tmp != 1) return 0;
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Physical drive nmuber (0) */
)
{
if (drv) return STA_NOINIT; /* Supports only single drive */
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) 扇区数*/
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
sector *= 512;
if(count == 1)
{
if(SD_SendCmd( CMD17, sector, 1, respbuf) && Read_BlockData(buff, 512))
count = 0;
}
else
{
if(SD_SendCmd( CMD18, sector, 1, respbuf))
{
do{if(Read_BlockData(buff, 512))
buff += 512;
}while(--count);
SD_SendCmd( CMD12, 0, 1, respbuf);
}
}
SPI_CS_SET();
SPI_SendByte(0xff);
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0) */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (drv || !count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (Stat & STA_PROTECT) return RES_WRPRT;
sector *= 512;
if(count == 1)
{
if(SD_SendCmd( CMD24, sector, 1, respbuf) && Write_BlockData(buff, 0xfe))
count = 1;
}
else
{
if(SD_SendCmd( CMD25, sector, 1, respbuf) == 1)
do{
if(Write_BlockData(buff, 0xfe)) return 0;
buff += 512;
}while(--count);
if(Write_BlockData(0, 0xfd) == 1) count = 1;
}
SPI_CS_SET();
SPI_SendByte(0xff);
return RES_OK;
}
#endif /* _READONLY == 0 */
/*-----------------------------------------------------------------------*/
/* get_fattime 本工程上没用到这个功能 */
/*-----------------------------------------------------------------------*/
DWORD get_fattime (void)
{
return 0;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL != 0
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
BYTE n, csd[16], *ptr = buff;
WORD csize;
if (drv) return RES_PARERR;
res = RES_ERROR;
if (ctrl == CTRL_POWER) {
switch (*ptr) {
case 0: /* Sub control code == 0 (POWER_OFF) */
SD_POWER_OFF(); /* Power off */
res = RES_OK;
break;
case 1: /* Sub control code == 1 (POWER_ON) */
SD_POWER_ON(); /* Power on */
res = RES_OK;
break;
case 2: /* Sub control code == 2 (POWER_GET) */
*(ptr+1) = 1;
res = RES_OK;
break;
default :
res = RES_PARERR;
}
}
else{
if (Stat & STA_NOINIT) return RES_NOTRDY;
switch(ctrl){
case CTRL_SYNC : SPI_CS_CLR(); SPI_SendByte(0xff);res = RES_OK;break;
case GET_SECTOR_SIZE : *(WORD*)buff = 512;res = RES_OK; break;/* Get R/W sector size (WORD) */
case MMC_GET_TYPE : *ptr = 1; res = RES_OK; break;/* Get card type flags (1 byte) */
case GET_SECTOR_COUNT : if(SD_SendCmd( CMD9, 0, 1, respbuf) && Read_BlockData(csd, 16))
{ if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
*(DWORD*)buff = (DWORD)csize << 10;
} else { /* SDC ver 1.XX or MMC*/
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD*)buff = (DWORD)csize << (n - 9);
}
res = RES_OK; }
break;
case GET_BLOCK_SIZE : if(SD_SendCmd( CMD9, 0, 1, respbuf) && Read_BlockData(csd, 16))
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
res = RES_OK;
break;
case MMC_GET_CSD : if(SD_SendCmd( CMD9, 0, 1, respbuf) && Read_BlockData(csd, 16)) res = RES_OK;break;
case MMC_GET_CID : if(SD_SendCmd( CMD10, 0, 1, respbuf) && Read_BlockData(csd, 16)) res = RES_OK;break;
case MMC_GET_OCR : if(SD_SendCmd( CMD58, 0, 1, respbuf)){
for(n=4;n;n--) *ptr++ = SPI_SendByte(0xff);res = RES_OK;} break;
case MMC_GET_SDSTAT : if (SD_SendCmd( ACMD13, 0, 2, respbuf)) { /* SD_STATUS */
SPI_SendByte(0xff);
if (Read_BlockData(ptr, 64))
res = RES_OK;
}
break;
default:
res = RES_PARERR;
}
}
SPI_CS_SET();
SPI_SendByte(0xff);
return res;
}
#endif /* _USE_IOCTL != 0 */
结束!大家多多指教哦……
你可以参照我的LPC1114的程序,是一样的,可以直接移植过来!!!
[ 本帖最后由 zhaojun_xf 于 2010-7-17 08:32 编辑 ]