r1 = SD_SendCommand(CMD55, 0, 0); if(r1!=0x01)return r1;
r1 = SD_SendCommand(ACMD41, 0x40000000, 0); if(retry>200)return r1; //超时则返回r1状态 }while(r1!=0);
//初始化指令发送完成,接下来获取OCR信息 //-----------鉴别SD2.0卡版本开始-----------
r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0); if(r1!=0x00) {
SD_CS=1;//释放SD片选信号
return r1; //如果命令没有返回正确应答,直接退出,返回应答
}//读OCR指令发出后,紧接着是4字节的OCR信息 buff[0] = SPIx_ReadWriteByte(0xFF);
buff[1] = SPIx_ReadWriteByte(0xFF); buff[2] = SPIx_ReadWriteByte(0xFF); buff[3] = SPIx_ReadWriteByte(0xFF); //OCR接收完成,片选置高 SD_CS=1;
SPIx_ReadWriteByte(0xFF);
//检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC
//如果CCS=1:SDHC CCS=0:SD2.0
if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC; //检查CCS else SD_Type = SD_TYPE_V2;
//-----------鉴别SD2.0卡版本结束----------- //设置SPI为高速模式
SPIx_SetSpeed(SPI_SPEED_4); } } return r1; }
//从SD卡中读回指定长度的数据,放置在给定位置 //输入: u8 *data(存放读回数据的内存>len)
// u16 len(数据长度)
// u8 release(传输完成后是否释放总线CS置高 0:不释放 1:释放)
//返回值:0:NO_ERR // other:错误信息
u8 SD_ReceiveData(u8 *data, u16 len, u8 release) {
// 启动一次传输
305
SD_CS=0;
if(SD_GetResponse(0xFE))//等待SD卡发回数据起始令牌0xFE
{
SD_CS=1; return 1;
}
while(len--)//开始接收数据 {
*data=SPIx_ReadWriteByte(0xFF); data++;
}
//下面是2个伪CRC(dummy CRC)
SPIx_ReadWriteByte(0xFF);
SPIx_ReadWriteByte(0xFF);
if(release==RELEASE)//按需释放总线,将CS置高
{
SD_CS=1;//传输结束 SPIx_ReadWriteByte(0xFF); }
return 0; }
//获取SD卡的CID信息,包括制造商信息
//输入: u8 *cid_data(存放CID的内存,至少16Byte) //返回值:0:NO_ERR
// 1:TIME_OUT
// other:错误信息
u8 SD_GetCID(u8 *cid_data) {
u8 r1;
//发CMD10命令,读CID
r1 = SD_SendCommand(CMD10,0,0xFF);
if(r1 != 0x00)return r1; //没返回正确应答,则退出,报错 SD_ReceiveData(cid_data,16,RELEASE);//接收16个字节的数据
return 0; }
//获取SD卡的CSD信息,包括容量和速度信息
//输入:u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR // 1:TIME_OUT // other:错误信息
306
u8 SD_GetCSD(u8 *csd_data) {
u8 r1;
r1=SD_SendCommand(CMD9,0,0xFF);//发CMD9命令,读 CSD
if(r1)return r1; //没返回正确应答,则退出,报错
SD_ReceiveData(csd_data, 16, RELEASE);//接收16个字节的数据
return 0;
}
//获取SD卡的容量(字节)
//返回值:0: 取容量出错
// 其他:SD卡的容量(字节)
u32 SD_GetCapacity(void) {
u8 csd[16]; u32 Capacity; u8 r1; u16 i;
u16 temp;
//取CSD信息,如果期间出错,返回0
if(SD_GetCSD(csd)!=0) return 0; //如果为SDHC卡,按照下面方式计算
if((csd[0]&0xC0)==0x40) {
Capacity=((u32)csd[8])<<8;
Capacity+=(u32)csd[9]+1;
Capacity = (Capacity)*1024;//得到扇区数 Capacity*=512;//得到字节数 } else {
i = csd[6]&0x03; i<<=8; i += csd[7]; i<<=2;
i += ((csd[8]&0xc0)>>6); //C_SIZE_MULT r1 = csd[9]&0x03; r1<<=1;
r1 += ((csd[10]&0x80)>>7); r1+=2;//BLOCKNR temp = 1; while(r1)
307
{
temp*=2; r1--;
}
Capacity = ((u32)(i+1))*((u32)temp); // READ_BL_LEN i = csd[5]&0x0f; //BLOCK_LEN temp = 1; while(i) {
temp*=2; i--;
}
//The final result
Capacity *= (u32)temp;//字节为单位 }
return (u32)Capacity; }
//读SD卡的一个block
//输入:u32 sector 取地址(sector值,非物理地址)
// u8 *buffer 数据存储地址(大小至少512byte)
//返回值:0: 成功 // other:失败
u8 SD_ReadSingleBlock(u32 sector, u8 *buffer) {
u8 r1;
//设置为高速模式
SPIx_SetSpeed(SPI_SPEED_4);
//如果不是SDHC,给定的是sector地址,将其转换成byte地址
if(SD_Type!=SD_TYPE_V2HC) {
sector = sector<<9;
}
r1 = SD_SendCommand(CMD17, sector, 0);//读命令 if(r1 != 0x00)return r1;
r1 = SD_ReceiveData(buffer, 512, RELEASE); if(r1 != 0)return r1; //读数据出错!
else return 0;
}
/////////////////下面2个函数为USB读写所需要的/////////////////////////
308
//定义SD卡的块大小 #define BLOCK_SIZE 512
//写入MSD/SD数据
//pBuffer:数据存放区 //ReadAddr:写入的首地址 //NumByteToRead:要写入的字节数 //返回值:0,写入完成 // 其他,写入失败
u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite) {
u32 i,NbrOfBlock = 0, Offset = 0; u32 sector; u8 r1;
NbrOfBlock = NumByteToWrite / BLOCK_SIZE;//得到要写入的块的数目 SD_CS=0;
while (NbrOfBlock--)//写入一个扇区 {
sector=WriteAddr+Offset;
if(SD_Type==SD_TYPE_V2HC)sector>>=9;//执行与普通操作相反的操作 r1=SD_SendCommand_NoDeassert(CMD24,sector,0xff);//写命令 if(r1) {
SD_CS=1;
return 1;//应答不正确,直接返回 }
SPIx_ReadWriteByte(0xFE);//放起始令牌0xFE
//放一个sector的数据
for(i=0;i<512;i++)SPIx_ReadWriteByte(*pBuffer++); //发2个Byte的 dummy CRC
SPIx_ReadWriteByte(0xff); SPIx_ReadWriteByte(0xff);
if(SD_WaitDataReady())//等待SD卡数据写入完成
{
SD_CS=1; return 2; }
Offset += 512; }
//写入完成,片选置1
SD_CS=1;
SPIx_ReadWriteByte(0xff); return 0;
309