|
楼主 |
发表于 2014-12-29 12:51:03
|
显示全部楼层
下面是SD.C部分代码
#include "M051Series.h"
#include "SPIC.h"
#include "SDC.h"
#include "ffconf.h"
#include "ff.h"
#include "diskio.h"
unsigned char SD_Type=0;//SD卡的类型
/****************************************
*函数名称:SD_SPI_ReadWriteByte
*输 入:d 要写入的数据
*输 出:读到的数据
*功 能:SD卡SPI总线读写数据操作
******************************************/
unsigned char SD_SPI_ReadWriteByte(unsigned char d)
{
return Spi0WriteRead(d);
}
/****************************************
*函数名称:SD_SPI_ReadWriteByte
*输 入:无
*输 出:无
*功 能:SD卡初始化的时候,进入低速模式
******************************************/
void SD_SPI_SpeedLow(void)
{
Spi0SetSpeedLow();
}
/****************************************
*函数名称:SD_SPI_SpeedHigh
*输 入:无
*输 出:无
*功 能:SD卡正常工作的时候,进入高速模式
******************************************/
void SD_SPI_SpeedHigh(void)
{
Spi0SetSpeedHigh();
}
/****************************************
*函数名称:SD_SPI_Init
*输 入:无
*输 出:无
*功 能:SD卡SPI总线初始化
******************************************/
void SD_SPI_Init(void)
{
Spi0MasterInit();
// P1_PMD &=~(3UL<<8);
// P1_PMD |= 1UL<<8 ;
SD_CS(1);
}
/****************************************
*函数名称:SD_DisSelect
*输 入:无
*输 出:无
*功 能:释放SPI总线,即取消选择
******************************************/
void SD_DisSelect(void)
{
SD_CS(1);
SD_SPI_ReadWriteByte(0xFF);//提供额外的8个时钟
}
/****************************************
*函数名称:SD_Select
*输 入:无
*输 出:0,成功;
1,失败;
*功 能:选择SD卡,并且等待卡准备OK
******************************************/
unsigned char SD_Select(void)
{
SD_CS(0);
if(SD_WaitReady()==0)
{
/* 等待成功 */
return 0;
}
SD_DisSelect();
/* 等待失败 */
return 1;
}
/****************************************
*函数名称:SD_WaitReady
*输 入:无
*输 出:0,准备好了;
其他,错误代码
*功 能:等待卡准备好
******************************************/
unsigned char SD_WaitReady(void)
{
unsigned int t=0;
do
{
if(SD_SPI_ReadWriteByte(0XFF)==0XFF)
{
return 0;
}
t++;
}while(t<0XFFFFFF);
return 1;
}
/****************************************
*函数名称:SD_GetResponse
*输 入:ucResponse 要得到的返回值
*输 出:0,成功得到了该回应值
其他,得到回应值失败
*功 能:等待SD卡回应
******************************************/
unsigned char SD_GetResponse(unsigned char ucResponse)
{
unsigned short int Count=0xFFFF;//等待次数
while ((SD_SPI_ReadWriteByte(0XFF)!=ucResponse)&&Count)
{
/* 等待得到准确的回应 */
Count--;
}
if (Count==0)
{
/* 得到回应失败 */
return MSD_RESPONSE_FAILURE;
}
else
{ /* 正确回应 */
return MSD_RESPONSE_NO_ERROR;
}
}
/****************************************
*函数名称:SD_RecvData
*输 入:buf 数据缓存区
len 要读取的数据长度
*输 出:0,成功;
其他,失败;
*功 能:从sd卡读取一个数据包的内容
******************************************/
unsigned char SD_RecvData(unsigned char*buf,unsigned short int len)
{
if(SD_GetResponse(0xFE))
{
/* 等待SD卡发回数据起始令牌0xFE */
return 1;
}
/* 开始接收数据 */
while(len--)
{
*buf=Spi0WriteRead(0xFF);
buf++;
}
/* 下面是2个伪CRC(dummy CRC)*/
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
/* 读取成功 */
return 0;
}
/****************************************
*函数名称:SD_SendBlock
*输 入:buf 数据缓存区
cmd 指令
*输 出:0,成功;
其他,失败;
*功 能:向sd卡写入一个数据包的内容 512字节
******************************************/
unsigned char SD_SendBlock(unsigned char*buf,unsigned char cmd)
{
unsigned short int t;
if(SD_WaitReady())
{
/* 等待准备失效 */
return 1;
}
SD_SPI_ReadWriteByte(cmd);
/* 不是结束指令 */
if(cmd!=0XFD)
{
/* 提高速度,减少函数传参时间 */
for(t=0;t<512;t++)
{
Spi0WriteRead(buf[t]);
}
/* 忽略crc */
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
/* 接收响应 */
t=SD_SPI_ReadWriteByte(0xFF);
if((t&0x1F)!=0x05)
{
/* 响应错误 */
return 2;
}
}
/* 写入成功 */
return 0;
}
/****************************************
*函数名称:SD_SendCmd
*输 入:cmd 命令
arg 命令参数
crc crc校验值
*输 出:SD卡返回的响应
*功 能:向SD卡发送一个命令
******************************************/
unsigned char SD_SendCmd(unsigned char cmd, unsigned int arg, unsigned char crc)
{
unsigned char r1;
unsigned char Retry=0;
/* 取消上次片选 */
SD_DisSelect();
if(SD_Select())
{
/* 片选失效 */
return 0XFF;
}
/* 分别写入命令 */
SD_SPI_ReadWriteByte(cmd | 0x40);
SD_SPI_ReadWriteByte(arg >> 24);
SD_SPI_ReadWriteByte(arg >> 16);
SD_SPI_ReadWriteByte(arg >> 8);
SD_SPI_ReadWriteByte(arg);
SD_SPI_ReadWriteByte(crc);
/* 当停止读时跳过一个字节 */
if(cmd==CMD12)
{
SD_SPI_ReadWriteByte(0xFF);
}
/* 等待响应,或超时退出 */
Retry=0X1F;
do
{
r1=SD_SPI_ReadWriteByte(0xFF);
}while((r1&0X80) && Retry--);
/* 返回状态值 */
return r1;
}
/****************************************
*函数名称:SD_GetCID
*输 入:cid_data
arg 命令参数
crc crc校验值
*输 出:SD卡返回的响应
*功 能:获取SD卡的CID信息,包括制造商信息
******************************************/
unsigned char SD_GetCID(unsigned char *cid_data)
{
unsigned char r1;
/* 发CMD10命令,读CID */
r1=SD_SendCmd(CMD10,0,0x01);
if(r1==0x00)
{
/* 接收16个字节的数据 */
r1=SD_RecvData(cid_data,16);
}
/* 取消片选 */
SD_DisSelect();
if(r1)
{
return 1;
}
return 0;
}
/****************************************
*函数名称:SD_GetCSD
*输 入:csd_data 存放CID的内存,至少16Byte
*输 出:0:NO_ERR
1:错误
*功 能:获取SD卡的CSD信息,包括容量和速度信息
******************************************/
unsigned char SD_GetCSD(unsigned char *csd_data)
{
unsigned char r1;
/* 发CMD9命令,读CSD */
r1=SD_SendCmd(CMD9,0,0x01);
if(r1==0)
{
/* 接收16个字节的数据 */
r1=SD_RecvData(csd_data, 16);
}
/* 取消片选 */
SD_DisSelect();
if(r1)
{
return 1;
}
return 0;
}
/****************************************
*函数名称:SD_GetSectorCount
*输 入:无
*输 出:0 取容量出错
其他 SD卡的容量(扇区数/512字节)
*功 能:获取SD卡的总扇区数(扇区数)
每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
******************************************/
unsigned int SD_GetSectorCount(void)
{
unsigned char csd[16];
unsigned char n;
unsigned short int csize;
unsigned int Capacity;
/* 取CSD信息,如果期间出错,返回0 */
if(SD_GetCSD(csd)!=0)
{
return 0;
}
/* 如果为SDHC卡,按照下面方式计算 */
if((csd[0]&0xC0)==0x40) // V2.00的卡
{
/* 得到扇区数 */
csize = csd[9] + ((unsigned short int)csd[8] << 8) + 1;
Capacity = (unsigned int)csize << 10;
}
else//V1.XX的卡
{
/* 得到扇区数 */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((unsigned short int)csd[7] << 2) + ((unsigned short int)(csd[6] & 3) << 10) + 1;
Capacity= (unsigned int)csize << (n - 9);
}
return Capacity;
}
/****************************************
*函数名称:SD_Initialize
*输 入:无
*输 出:0 -成功
其他 -失败
*功 能:SD卡初始化
******************************************/
unsigned char SD_Initialize(void)
{
unsigned char r1; // 存放SD卡的返回值
unsigned short int retry; // 用来进行超时计数
unsigned char buf[4];
unsigned int i;
/* 初始化IO */
SD_SPI_Init();
/* 设置到低速模式 */
SD_SPI_SpeedLow();
for(i=0;i<10;i++)
{
/* 发送最少74个脉冲 */
SD_SPI_ReadWriteByte(0XFF);
}
retry=20;
do
{
/* 进入IDLE状态 */
r1=SD_SendCmd(CMD0,0,0x95);
}while((r1!=0X01) && retry--);
/* 默认无卡 */
SD_Type=0;
if(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
{
for(i=0;i<4;i++)
{
/* 等待应答 */
buf[i]=SD_SPI_ReadWriteByte(0XFF);
}
/* 卡是否支持2.7~3.6V */
if(buf[2]==0X01&&buf[3]==0XAA)
{
retry=0XFFFE;
do
{
/* 发送CMD55 */
SD_SendCmd(CMD55,0,0X01);
/* 发送CMD41 */
r1=SD_SendCmd(CMD41,0x40000000,0X01);
}while(r1&&retry--);
/* 鉴别SD2.0卡版本开始 */
if(retry&&SD_SendCmd(CMD58,0,0X01)==0)
{
for(i=0;i<4;i++)
{
/* 得到OCR值 */
buf[i]=SD_SPI_ReadWriteByte(0XFF);
}
/* 检查CCS */
if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;
else SD_Type=SD_TYPE_V2;
}
}
}
else//SD V1.x/ MMC V3
{
/* 发送CMD55 */
SD_SendCmd(CMD55,0,0X01);
/* 发送CMD41 */
r1=SD_SendCmd(CMD41,0,0X01);
if(r1<=1)
{
SD_Type=SD_TYPE_V1;
retry=0XFFFE;
do //等待退出IDLE模式
{
/* 发送CMD55 */
SD_SendCmd(CMD55,0,0X01);
/* 发送CMD41 */
r1=SD_SendCmd(CMD41,0,0X01);
}while(r1&&retry--);
}
else//MMC卡不支持CMD55+CMD41识别
{
/* MMC V3 */
SD_Type=SD_TYPE_MMC;
retry=0XFFFE;
/* 等待退出IDLE模式 */
do
{
/* 发送CMD1 */
r1=SD_SendCmd(CMD1,0,0X01);
}while(r1&&retry--);
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)
{
/* 错误的卡 */
SD_Type=SD_TYPE_ERR;
}
}
}
/* 取消片选 */
SD_DisSelect();
/* 高速 */
SD_SPI_SpeedHigh();
if(SD_Type)return 0;
if(r1) return r1;
/* 其他错误 */
return 0xAA;
}
/****************************************
*函数名称:SD_ReadDisk
*输 入:buf -数据缓存区
sector-扇区
cnt -扇区数
*输 出:0 -成功
其他 -失败
*功 能:SD卡读
******************************************/
unsigned char SD_ReadDisk(unsigned char*buf,unsigned int sector,unsigned char cnt)
{
unsigned char r1;
if(SD_Type!=SD_TYPE_V2HC)
{
/* 转换为字节地址 */
sector <<= 9;
}
if(cnt==1)
{
/* 读命令 */
r1=SD_SendCmd(CMD17,sector,0X01);
/* 指令发送成功 */
if(r1==0)
{
/* 接收512个字节 */
r1=SD_RecvData(buf,512);
}
}
else
{
/* 连续读命令 */
r1=SD_SendCmd(CMD18,sector,0X01);
do
{
/* 接收512个字节 */
r1=SD_RecvData(buf,512);
buf+=512;
}while(--cnt && r1==0);
/* 发送停止命令 */
SD_SendCmd(CMD12,0,0X01);
}
/* 取消片选 */
SD_DisSelect();
return r1;
}
/****************************************
*函数名称:SD_WriteDisk
*输 入:buf -数据缓存区
sector-扇区
cnt -扇区数
*输 出:0 -成功
其他 -失败
*功 能:SD卡写
******************************************/
unsigned char SD_WriteDisk(unsigned char*buf,unsigned int sector,unsigned char cnt)
{
unsigned short int r1;
/* 转换为字节地址 */
if(SD_Type!=SD_TYPE_V2HC)
{
sector *= 512;
}
if(cnt==1)
{
/* 读命令 */
r1=SD_SendCmd(CMD24,sector,0X01);
/* 指令发送成功 */
if(r1==0)
{
/* 写512个字节 */
r1=SD_SendBlock(buf,0xFE);
}
}
else
{
if(SD_Type!=SD_TYPE_MMC)
{
SD_SendCmd(CMD55,0,0X01);
SD_SendCmd(CMD23,cnt,0X01);//发送指令
}
r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令
if(r1==0)
{
do
{
r1=SD_SendBlock(buf,0xFC);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
r1=SD_SendBlock(0,0xFD);//接收512个字节
}
}
SD_DisSelect();//取消片选
return r1;
}
|
|