51单片机个别SD卡无法正确读取指定地址

lulutong_ 2016-11-06 05:35:20
1)128M的TF卡有一张可以读指定地址,另外两张不能读指定地址,但这三张TF卡都可以初始化,并且可以获取卡容量,用读卡器在电脑可以读写。
2)512M和4G的SD卡51单片机都无法读写指定地址,但是可以初始化,并且读出了CSD和CID,容量也是正确的。
3)1G的四张TF卡都可以用51单片机的程序读写,并且可以成功通过FAT16创建8个文件。
4)同样的卡,用51单片机不能读写,用STM32却可以读写,而STM32的参考代码初始化只用了cmd0和cmd1。

下面是SD卡初始化和读指定地址的代码:

/*********************************************************
函数功能:向SD卡写入cnt个0xff
*********************************************************/
void SD_BYTE_NOP(BYTE cnt)
{
do{
SPI_RW(0xff);
}while(cnt --);
}

/********************************************************
函数功能:SD卡初始化
********************************************************/
BYTE SD_Init(void)
{
WORD i;
BYTE response=0x01;
SPI_Init();//SD_CLK = 1;
SET_SPI_LOW_MODE_FLAG();
DISABLE_SPI();//SD_CS=1;
for(i=0;i<=9;i++)
{
SPI_RW(0xff);//SdWrite(0xff);
}

//return SD_GoIdleState();//

ENABLE_SPI();//SD_CS=0;
//Send Command 0 to put MMC in SPI mode
SD_Command(sd_cmd0);//(0x00,0,0x95);

response=SD_Response();
DISABLE_SPI();
SPI_RW(0xff);
if(response!=0x01)
{
DISABLE_SPI();

#if(__IS_DEBUG__)
printf("cmd0 should return 0x01 while it is %d\r\n",response);
#endif

return 0;
}

ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd8);
response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
#if(__IS_DEBUG__)
printf("Response fo cmd8 is:0x%02x\r\n", (int)response);
#endif
switch(response)
{
case 0x05:
{//V1.x或者其他
/* SD1.0/MMC start initialize */
/* Send CMD55+ACMD41, No-response is a MMC card, otherwise is a SD1.0 card */
i = 0;
do{
ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd55);
response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(0x01 != response)
{
#if(__IS_DEBUG__)
printf("Init SD Card Failed ! Send CMD55 should return 0x01, response=0x%02x\r\n",(int)response);
#endif

// DISABLE_SPI();
// return 0;
}
else
{
#if(__IS_DEBUG__)
printf("Response cmd55 OK, response=0x%02x\r\n",(int)response);
#endif
}

ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd41);

response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(0x00 == response)
{
#if(__IS_DEBUG__)
printf("Response cmd41 OK, response=0x%02x\r\n",(int)response);
#endif
break;
}
i ++;
}while(i < 200);

if(i >= 200)
{
#if(__IS_DEBUG__)
printf("Response cmd41 should be 0x00, response=0x%02x\r\n",(int)response);
#endif
}

i = 0;
while(response==0x01)
{
ENABLE_SPI();//SD_CS=0;
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd1);//0x01,0x00ffc000,0xff);
response=SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(i++ >= 200)
{//重试次数为200时会失败,会不会是因为速度太快


#if(__IS_DEBUG__)
printf("Init SD Card Failed ! try cmd1 for 4000 tick, response is:%d\r\n",(int)response);
#endif

DISABLE_SPI();
return 0;
}
}

#if(__IS_DEBUG__)
printf("try %d time fo cmd1 , response for cmd 1 ok! is:%d.\r\n",i,(int)response);
#endif

ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd59); //禁止CRC校验
response = SD_Response();
DISABLE_SPI();
SPI_RW(0xff);
if(0x00 != response)
{
#if(__IS_DEBUG__)
printf("response cmd59 error,response = %d !\r\n",(unsigned int)response);
#endif
DISABLE_SPI();
return 0;
}

ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd16);//设置块大小
response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(0x00 != response)
{
DISABLE_SPI();
return 0;
}

RESET_SPI_LOW_MODE_FLAG(); //设置SPI为高速模式
return 1;
}
break;
case 0x01:
{//SD V2.x
/* SD1.0/MMC start initialize */
/* Send CMD55+ACMD41, No-response is a MMC card, otherwise is a SD1.0 card */
i = 0;
do{
ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd55);
response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(0x01 != response)
{
DISABLE_SPI();
return 0;
}

ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd41);
response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(0x00 == response)
{
break;
}
i ++;
}while(i < 200);

ENABLE_SPI();
/***************************不丢掉垃圾数据,后面命令响应可能会失败************************/
SD_BYTE_NOP(8);
/****************************************************************************************/
SD_Command(sd_cmd58);
response = SD_Response();

DISABLE_SPI();
SPI_RW(0xff);
if(0x00 != response)
{
DISABLE_SPI();
return 0;
}

RESET_SPI_LOW_MODE_FLAG(); //设置为高速模式
return 1;
}
break;
}

DISABLE_SPI();
return 0;
}


/*================================================================
入口参数:
出口参数:
返回参数:
0 ->失败
1 ->成功
函数功能:
1)从address开始出读取len个字节到buf;
2)最长可读取512字节;
3)支持跨扇区读数;
维护人
================================================================*/
BYTE SD_ReadBlock1(BYTE buf[],DWORD address,WORD len)
{
BYTE readRetryCnt = 100;
WORD count = 0x0000;
BYTE retryCnt = 0x00;
WORD offset = 0x00000;
BYTE response = 0x00;

offset = address - address / 512 * 512;
address /= 512;
address *= 512;
ENABLE_SPI();

g_B_sd_cmd_buf[0] = 0x11;
g_B_sd_cmd_buf[1] = (BYTE)(((BYTE *)&address)[0]);
g_B_sd_cmd_buf[2] = (BYTE)(((BYTE *)&address)[1]);
g_B_sd_cmd_buf[3] = (BYTE)(((BYTE *)&address)[2]);
g_B_sd_cmd_buf[4] = (BYTE)(((BYTE *)&address)[3]);
g_B_sd_cmd_buf[5] = 0xff;
SD_Command(g_B_sd_cmd_buf);

/*********************发送读扇区命令后,响应非0表示成功*********************/
retryCnt = 0;
do
{
response = SD_Response();
retryCnt ++;

if(retryCnt >= 100)
{
DISABLE_SPI();
SPI_RW(0xff);
return 0;
}
}while(response);//SD_Response());
/**************************************************************************/
//SET_SPI_LOW_MODE_FLAG();
/**********************等待SD卡响应0xfe,启动数据传输**********************/
retryCnt = 0;
do
{
response = SPI_RW(0xff);
if(0xfe == response){
{
break;
}
retryCnt ++;
if(retryCnt >= 10){

DISABLE_SPI();
SPI_RW(0xff);
return 0;
}
}while(retryCnt < 100);
/*************************************************************************/

if(len > 512 - offset)
{//读取的区域需要跨扇区
/********************丢弃该扇区offse前的数据*********************/
for(count = 0; count < offset; count ++)
{
SPI_RW(0xff);
}
/*************************************************************/

/********************从该扇区offset偏移处开始接收***************/
while(count < 512)
{
buf[count - offset] = SPI_RW(0xff);
count ++;
len --;//接收到一个字节,接收缓冲减1
}
/***************************************************************/

//data block sent - now send checksum
SPI_RW(0xff);//SdRead();
SPI_RW(0xff);//SdRead();
//Now read in the DATA RESPONSE token
DISABLE_SPI();//SD_CS=1;
SPI_RW(0xff);//SdRead();

//======================接收下一个扇区剩下的字节======================
ENABLE_SPI();
address += 512;
g_B_sd_cmd_buf[0] = 0x11;
g_B_sd_cmd_buf[1] = (BYTE)(((BYTE *)&address)[0]);
g_B_sd_cmd_buf[2] = (BYTE)(((BYTE *)&address)[1]);
g_B_sd_cmd_buf[3] = (BYTE)(((BYTE *)&address)[2]);
g_B_sd_cmd_buf[4] = (BYTE)(((BYTE *)&address)[3]);
g_B_sd_cmd_buf[5] = 0xff;
SD_Command(g_B_sd_cmd_buf);
retryCnt = 100;
do
{
retryCnt --;
if(!retryCnt)
{
DISABLE_SPI();
SPI_RW(0xff);
return 0;
}
}while(SD_Response());

retryCnt = 0;
do
{
if(0xfe == SPI_RW(0xff)){break;}
retryCnt ++;
if(retryCnt >= 100)
{
#if(__IS_DEBUG__)
printf("in SD_ReadBlock1,error 3, try %d times !\r\n",(unsigned int)retryCnt);
#endif
DISABLE_SPI();
SPI_RW(0xff);
return 0;
}
}while(retryCnt < 100);
for(count = 0; count < len; count ++)
{
buf[512 - offset + count] = SPI_RW(0xff);
}
while(count++ < 512){SPI_RW(0xff);}
//data block sent - now send checksum
SPI_RW(0xff);//SdRead();
SPI_RW(0xff);//SdRead();
//Now read in the DATA RESPONSE token
DISABLE_SPI();//SD_CS=1;
SPI_RW(0xff);//SdRead();
return 1;
}
else
{//读取的区域在一个扇区
for(count = 0; count < offset; count ++)
{
SPI_RW(0xff);
}
while(count < offset + len)
{
buf[count - offset] = SPI_RW(0xff);
count ++;
}
/***************************剩下的字节一定要读完,否则会导致下次读扇区是错误***************/
while(count ++ < 512){SPI_RW(0xff);}
/******************************************************************************************/
//data block sent - now send checksum
SPI_RW(0xff);//SdRead();
SPI_RW(0xff);//SdRead();
//Now read in the DATA RESPONSE token
DISABLE_SPI();//SD_CS=1;
SPI_RW(0xff);//SdRead();
return 1;

}
...全文
729 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
EmbeddedLong 2016-11-18
  • 打赏
  • 举报
回复
一晃四年了 大家一直都还在坚持!
of123 2016-11-10
  • 打赏
  • 举报
回复
“无法读写”的具体现象是什么?
fly 100% 2016-11-10
  • 打赏
  • 举报
回复
都用单线模式试试
of123 2016-11-09
  • 打赏
  • 举报
回复
用示波器抓一下信号,看哪里错了。

27,374

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧