/*写一个字节函数*/
u8 SpiWriteByte(u8 TxData)
{
u8 RxData;
SPI1BUF = TxData; //待发送数据装载待发送寄存器中
while(!SPI1STATbits.SPITBF); //等待接收完成
SPI1BUF = 0xFF;
while(!SPI1STATbits.SPIRBF);
RxData = SPI1BUF;
return RxData;
//IFS0bits.SPI1IF = 0; //清零中断标志
}
/*发送命令函数*/
u8 SdSendCommand(u8* cmd)
{
u8 time, r;
SpiWriteByte(cmd[0]); //写入序列号
SpiWriteByte(cmd[1]); //数据段第4个字节
SpiWriteByte(cmd[2]); //数据段第3个字节
SpiWriteByte(cmd[3]); //数据段第2个字节
SpiWriteByte(cmd[4]); //数据段第1个字节
SpiWriteByte(cmd[5]); //CRC校验和
/*获取16为的回应*/
SpiWriteByte(0xFF);
time = 0;
do
{
r = SpiWriteByte(0xFF); //获取后8位的回应
time ++;
}while((r == 0xFF) && (time < 100));
return r; //返回状态位
}
/*SD卡的初始化*/
u8 SdInit(void)
{
u8 i, time, r1 = 0xFF;
u8* pcmd; //用于获取数组首地址
/*初始化SPI的IO口和SPI模式*/
Spi1Init();
u8 cmd0[6] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95}; //CMD0使SD卡进入IDLE状态
u8 cmd16[6] = {0x50, 0x00, 0x00, 0x02, 0x00, 0x01}; //CMD16,设置扇区大小为512字节
u8 cmd55[6] = {0x77, 0x00, 0x00, 0x00, 0x00, 0x01}; //SD卡使用CMD55+ACMD41来进行初始化
u8 acmd41[6] = {0x69, 0x00, 0x00, 0x00, 0x00, 0x01};
/*SD卡复位,进入SPI模式,使用CMD0*/
CS = 1; //发送74个时钟之前要禁止SD卡
for(i = 0; i < 10; i ++) //在向SD卡发送数据之前,必需先SD发送至少74个时钟
{
SpiWriteByte(0xFF); //发送了80个时钟
}
/*发送CMD0进行复位*/
time = 0;
CS = 0;
do
{
pcmd = cmd0;
r1 = SdSendCommand(pcmd); //写入CMD0
time ++; //用来计时是否超时
}while((r1 != 0x01) && (time < 200));
if(time >= 200)
{
return (INIT_CMD0_ERROR); //CMD0写入失败
}
CS = 1;
r1 = 0xFF; //清楚r1返回标志位
SpiWriteByte(0xFF); //写入指令后附加8个填充时钟
/*发送CMD55+ACMD41对SD卡进行初始化*/
CS = 0;
time = 0;
do
{
pcmd = cmd55;
SdSendCommand(pcmd); //写入CMD55
pcmd = acmd41;
r1 = SdSendCommand(pcmd); //写入命令ACMD41
time ++;
}while((r1 != 0) && (time < 200));
if(time >= 200)
{
return INIT_ACMD41_ERROR;
}
CS = 1;
r1 = 0xFF;
SpiWriteByte(0xFF); //写入指令后附加8个填充时钟
/*发送CMD16,设置SD卡块的大小为512字节*/
CS = 0;
time = 0;
do
{
pcmd = cmd16;
r1 = SdSendCommand(pcmd);
time ++;
}while((r1 != 0) && (time < 200));
if(time >= 200)
{
return INIT_CMD16_ERROR;
}
CS = 1;
r1 = 0xFF;
SpiWriteByte(0xFF);
/*SD卡初始化结束后需要转为高速模式*/
SPI1CON1bits.SPRE = 6; //辅助预分频比为2:1
SPI1CON1bits.PPRE = 2; //主预分频比为4:1
return 0;
}
/*写一个扇区*/
u8 SDWriteSector(u32 sector, u8* buffer)
{
u8 r1 = 1;
u8* pcmd;
u16 retry, i, j;
u8 cmd24[6]={0x58, 0x00, 0x00, 0x00, 0x00, 0xFF}; //向SD卡中单个扇区(512字节)写入数据,用CMD24
/*将扇区地址转换为字节地址*/
sector = sector >> 9;
/*将字节地址加载到命令CMD24中*/
cmd24[1] = sector >> 24;
cmd24[2] = sector >> 16;
cmd24[3] = sector >> 8;
cmd24[4] = sector;
/*发送CMD24写命令*/
CS = 0;
retry = 0;
do
{
pcmd = cmd24;
r1 = SdSendCommand(pcmd); //写入CMD24
retry ++;
}while((r1 != 0x0) && (retry < 200));
if(retry >= 200)
{
return INIT_CMD24_ERROR; //写入CMD24失败
}
//写入3个空数据,等待SD卡准备好
SpiWriteByte(0xFF);
SpiWriteByte(0xFF);
SpiWriteByte(0xFF);
SpiWriteByte(0xFE); //发开始符
/*发送512个字节*/
for(i = 0; i < 4; i ++)
{
for(j = 0; j < 126; j ++)
{
SpiWriteByte(*buffer);
buffer ++;
}
}
/*16位CRC校验*/
SpiWriteByte(0xFF);
SpiWriteByte(0xFF);
while((r1 = SpiWriteByte(0xFF)) == 0xFF); //等待SD卡响应
if((r1 & 0x1f) != 0x05) //如果返回值是 XXX00101 说明数据已经被SD卡接收了
{
return 1;
}
/*等到SD卡不忙*/
while(SpiWriteByte(0xFF) != 0xFF);
CS = 1;
SpiWriteByte(0xFF); //写入指令后附加8个填充时钟
return 0;
}
/*读一个扇区*/
u8 SDReadSector(u32 sector, u8* buffer)
{
u8 r1 = 1;
u8* pcmd;
u16 retry, i, j;
u8 cmd17[6] = {0x51, 0x00, 0x00, 0x00, 0x00, 0xFF}; //从SD卡中单个扇区(512字节)读取数据,用CMD17
u8 cmd12[6] = {0x1C, 0x00, 0x00, 0x00, 0x00, 0x01}; //CMD12,强制停止命令
/*将扇区地址转换为字节地址*/
sector = sector >> 9;
/*将字节地址加载到命令CMD24中*/
cmd17[1] = sector >> 24;
cmd17[2] = sector >> 16;
cmd17[3] = sector >> 8;
cmd17[4] = sector;
/*发送CMD17写命令*/
CS = 0;
retry = 0;
do
{
pcmd = cmd17;
r1 = SdSendCommand(pcmd); //写入CMD17
retry ++;
}while((r1 != 0x0) && (retry < 200));
if(retry >= 200)
{
return INIT_CMD17_ERROR; //写入CMD17失败
}
/*写入3个空数据,等待SD卡准备好*/
SpiWriteByte(0xFF);
SpiWriteByte(0xFF);
SpiWriteByte(0xFF);
while(SpiWriteByte(0xFF) != 0xFE); //等待SD卡读准备
/*读取SD卡buffer扇区中的512个字节*/
for(i = 0; i < 4; i ++)
{
for(j = 0; j < 128; j ++)
{
*buffer = SpiWriteByte(0xFF); //获取数据到buffer中
buffer ++;
}
}
/*16位CRC校验*/
SpiWriteByte(0xFF);
SpiWriteByte(0xFF);
/*写12号命令终止数据读取*/
pcmd = cmd12;
SdSendCommand(pcmd);
CS = 1;
SpiWriteByte(0xFF); //写入指令后附加8个填充时钟
return 0;
}