【转】SDHC卡驱动及初始化
瞎忙了几天终于让4G的SDHC卡在STC90C516的SPI模式下跑了起来,因为当初找资料的时候遇到了太多的困难,最后是在IH YFF的帮助下,看了E文的SD2.0协议才有点小明白的.
最初的想法是弄一个数码相框玩玩,试跑了一个A例程,结果没有成功.到网上搜了很多相关的例程,结果发现和A例程的代码大同小异都是针对小于2G的SD卡写的.虽然网上有人说SD卡的协议写得很那个,但是实在没有办法了.后来看了协议才知道那实在是个误解.呵呵.
SD卡的协议有V1.0和V2.0之分,A例程和网上流传的各种例程都是V1.0的,而我的SDHC(金士顿4G的卡)(大于2G的都要用V2.0才能跑起来).我用A例程时在初始化的时候就在ACMD41这里挂掉了.
下面的这些函数和版无关,网上流传的都可以用
void Write_Byte(uchar dat);
uchar Read_Byte(void );
uchar Write_MCD(uchar cmd,ulong par,uchar crc);
我用的初始化函数的思想是这样的:
注:每个命令都要多次测试,最好设定一个测试变量,超时返回出错值.
uchar SDHC_Init()
{
int i;
for(i=0;i<20;i++)
Read_Byte();
SPI_CS=0;
i=0;
while(0x01 != Write_CMD(0,0x00000000,0x95))if(i++ >100)return(1);
i=0;
while(0x01!=Write_CMD(8,0x000001aa,0x89))if(i++ >100)return(2);
i=0;
do
{
Write_CMD(55,0x00000000,0xff); //返回值:不用测,因为该命令只是为了进ACMD
if(i++ >100)return(3);
}while(Write_CMD(41,0x40000000,0xff) !=0x00);
SPI_CS=1;
Read_Byte();
return(0); //返回0表示成功
}
另外一点和V1.0不同的地方是,V2.0对SD卡的读写(不是SD卡寄存器)都是以512的字节进行的.
uchar SDHC_Read_Sector(ulong addr,uchar *buffer)//从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令)
{
uint time;
uchar temp;
time=0;
do
{
temp=Write_CMD(17,addr,0xff); //写入CMD17
if(time++ >=TRY_TIME)
{
return(1); //读块失败
}
}while(temp!=0);
while (Read_Byte() != 0xfe); //一直读,当读到0xfe时,说明后面的是512字节的数据了
for(time=0;time<512;time++) //将数据写入到数据缓冲区中
{
*buffer++ =Read_Byte();
}
Read_Byte();
Read_Byte();
SPI_CS=1; //SD卡关闭片选
Write_Byte(0xFF);//按照SD卡的操作时序在这里补8个时钟
return 0;
}
下面写一个例程:
#include <reg52.h>
uchar buffer[512]={0};
void Out_String(uchar *str,uint slen)
{
uint i;
for(i=0;i<slen;i++)
{
SBUF=str[i];
while(!TI);
TI=0;
}
}
void main()
{
PCON=0X80;
SCON=0X40;
TMOD=0X20;
TH1=253;
TL1=253;
TCON=0X40;
SDHC_Init();
SDHC_Read_Sector(0L,buffer);
Out_String(buffer,512);
while(1);
}
下面是结果: