我用的也是stm32, 也是用程序模拟的sd卡时序,我的读出来了,看了看你的程序, 有两点不同:
1, 我的crc校验是真校验, 你的没有校验, 无校验的我没有试过, 虽然说spi模式不需要校验吧,好象网上都是把校验字节写成0xff;
2,发送cmd17, 等待卡应答, 这个过程我会尝试多次, 超出次数,我才会认为不成功.
还有winhex的0地址, 好象不是真正的0, 这个我忘记了, 当时头都大了, 程序过去后,也记不清了
以下是程序,只作参考:
/***********************************************
TF卡, 亦称micro SD卡
************************************************/
#include <stm32f10x_lib.h>
#include "my.h"
#define SPI_MODE
#ifndef SPI_MODE
#define SD_MODE
#endif
//#define NCR 5 //5clk
#define NID 5
//#define NAC 2
//#define NRC 8
#define NCC 8
//#define NWR 5
#define NCS 5 //clk , 0 *8 clock cycles
#define NCR 10 //clk 1 8 *8 clock cycles
#define NCX 5 //clk 0 8 *8 clock cycles
#define NRC 10 //clk 1 8 clock cycles
#define NAC 10 // 1 *8 clock cycles
#define NWR 10 //clk, 1 *8 clock cycles
#define NEC 5 //clk, 0 *8 clock cycles
#define NDS 5 //clk,0 *8 clock cycles
#define NBR 8 //clk, 1 *8 clock cycles
#define TF_CLK_H GPIO_SetBits(GPIOB, GPIO_Pin_15)
#define TF_CLK_L GPIO_ResetBits(GPIOB, GPIO_Pin_15) //SPI CLK
#define TF_CMD_H GPIO_SetBits(GPIOD, GPIO_Pin_13)
#define TF_CMD_L GPIO_ResetBits(GPIOD, GPIO_Pin_13) //SPI DI
#define TF_DI_H TF_CMD_H
#define TF_DI_L TF_CMD_L
#define TF_D0_H GPIO_SetBits(GPIOB, GPIO_Pin_14)
#define TF_D0_L GPIO_ResetBits(GPIOB, GPIO_Pin_14)
#define TF_D1_H GPIO_SetBits(GPIOB, GPIO_Pin_13)
#define TF_D1_L GPIO_ResetBits(GPIOB, GPIO_Pin_13)
#define TF_D2_H GPIO_SetBits(GPIOA, GPIO_Pin_11)
#define TF_D2_L GPIO_ResetBits(GPIOA, GPIO_Pin_11)
#define TF_D3_H GPIO_SetBits(GPIOC, GPIO_Pin_6)
#define TF_D3_L GPIO_ResetBits(GPIOC, GPIO_Pin_6) //SPI CS , ACTIVE LOW
#define TF_CS_H TF_D3_H
#define TF_CS_L TF_D3_L
#define TF_CMD_R GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_13)
#define TF_D0_R GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) //SPI DOUT
#define TF_D1_R GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13)
#define TF_D2_R GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11)
#define TF_D3_R GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_6)
#define TF_TEST_R GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_12) //检测TF卡有无, 低电平有效
uchar tf_crc7(uchar *pda, uchar n) //CRC-7生成函数(直接生成最后一个CMD指令字节), pda: 数据地址(*(pda+0)为首字节); n: 数据字节数; //G(x) =x7 + x3 + 1
{
uchar i,j,crc, temp; //crc: bit6--bit0有效, bit7: 做移出位
crc =0;
for(i=0; i<n; i++)
{
temp =*(pda+i);
j =8;
do
{
crc <<=1;
if(temp & 0x80)
{
crc |=0x01;
}
else
{
crc &=0xfe;
}
temp <<=1; //移位
if(crc & 0x80)
{
crc =crc ^ 0x89;
} //异或
j -=1;
}
while(j);
}
for(i=0; i<7; i++)
{
crc <<=1;
if(crc & 0x80)
{
crc =crc ^ 0x89;
}
} //完成这一步已经是 CRC检验码了
return((crc<<1) | 0x01);
}
void tf_send_cmd(uchar *pcmd,uchar speed) //发送cmd指令, *pcmd中不包括CRC和停止位, speed速度, 调用此函数时, 要求clk 为L //speed =1 for slow(<=400KHz), 0 for quick
{
#ifdef SPI_MODE //SPI模式
uchar i,j,temp,cmd[6];
for(i =0; i<6-1; i++)
{
cmd[i] =*(pcmd+i);
}
cmd[5] =tf_crc7(cmd,5);
for(i=0; i<6; i++)
{
TF_CLK_L;
temp =cmd[i];
for(j=0; j<8; j++)
{
TF_CLK_L;
if(speed) delayus(1);
if(temp & 0x80)
{
TF_DI_H;
}
else
{
TF_DI_L;
}
TF_CLK_H;
if(speed) delayus(1);
temp <<=1;
}
}
TF_CLK_L;
#endif
#ifdef SD_MODE //SD模式
uchar i,j,temp,cmd[6];
while(!TF_D0_R)
{
TF_CLK_L;
delay(1);
TF_CLK_H;
delay(1);
TF_CLK_L;
}
for(i =0; i<6-1; i++)
{
cmd[i] =*(pcmd+i);
}
cmd[5] =tf_crc7(cmd,5);
for(i=0; i<6; i++)
{
TF_CLK_L;
temp =cmd[i];
for(j=0; j<8; j++)
{
TF_CLK_L;
if(speed) delayus(1);
if(temp & 0x80)
{
TF_DI_H;
}
else
{
TF_DI_L;
}
TF_CLK_H;
if(speed) delayus(1);
temp <<=1;
}
}
TF_CLK_L;
TF_CMD_H;
#endif
}
void tf_rev_res(uchar *prev,uchar n,uchar speed) //接收响应,SPI模式, *prev: 接收的数据放在这里; n: 要求接收的字节数; speed:速度 1 for slow, 0 for quick
{
#ifdef SPI_MODE //SPI模式
uchar i,j,temp,en;
ushort k;
TF_CLK_L;
TF_D0_H;
en =0;
k =0;
for(i=0; i<n; i++)
{
temp =0;
for(j=0; j<8; j++)
{
TF_CLK_L;
if(speed) delayus(1);
TF_CLK_H;
if(speed) delayus(1);
temp <<=1;
if(TF_D0_R && en)
{
temp |=0x01;
}
else if((!TF_D0_R) && (!en))
{
k =0;
en =1;
}
else if(en==0)
{
if(k<0xffff) k +=1;
j =255;
}
if(k>60000) break;
}
if(k>60000) break;
*(prev+i) =temp;
}
if(en==0) *prev =0xff;
#endif
#ifdef SD_MODE //SD模式
uchar i,j,temp,en;
ushort k;
TF_CLK_L;
TF_CMD_H;
en =0;
k =0;
for(i=0; i<n; i++)
{
temp =0;
if(i==0)
{
k =0;
while(1)
{
TF_CLK_L;
if(speed) delayus(1);
TF_CLK_H;
if(speed) delayus(1);
if(!TF_CMD_R) break;
k +=1;
if(k>60000) goto tf_rev_res_1;
}
j =1;
}
else j =0;
en =1;
k =0;
for(; j<8; j++)
{
TF_CLK_L;
if(speed) delayus(1);
TF_CLK_H;
if(speed) delayus(1);
temp <<=1;
if(TF_CMD_R && en)
{
temp |=0x01;
}
else if((!TF_CMD_R) && (!en))
{
k =0;
en =1;
}
else if(en==0)
{
if(k<0xffff) k +=1;
j =255;
}
if(k>60000) break;
}
if(k>60000) break;
*(prev+i) =temp;
}
tf_rev_res_1:
if(en==0) *prev =0xff;
#endif
}
uchar tf_rev_byte_data() //接收1个字节数据
{
#ifdef SPI_MODE //SPI模式
uchar i,result;
TF_CLK_L;
TF_D0_H;
result =0;
for(i=0; i<8; i++)
{
TF_CLK_L;
result <<=1;
TF_CLK_H;
if(TF_D0_R)
{
result |=0x01;
}
}
TF_CLK_L;
return(result);
#endif
#ifdef SD_MODE //SD模式
uchar i,result;
TF_CLK_L;
TF_D0_H;
TF_D1_H;
TF_D2_H;
TF_D3_H;
result =0;
for(i=0; i<2; i++)
{
TF_CLK_L;
result <<=4;
TF_CLK_H;
if(TF_D0_R)
{
result |=0x01;
}
if(TF_D1_R)
{
result |=0x02;
}
if(TF_D2_R)
{
result |=0x04;
}
if(TF_D3_R)
{
result |=0x08;
}
}
TF_CLK_L;
return(result);
#endif
}
void tf_rev_data(uchar *prdata,ushort n) //接收数据, SPI模式, *prdata: 接收存储; n: 要求接收的字节数
{
#ifdef SPI_MODE //SPI模式
ushort i;
for(i=0; i<n; i++)
{
*(prdata+i) =tf_rev_byte_data();
}
#endif
#ifdef SD_MODE //SD模式
ushort i;
for(i=0; i<n; i++)
{
*(prdata+i) =tf_rev_byte_data();
}
#endif
}
void tf_74clk() //CMD线上的74个逻辑1
{
#ifdef SPI_MODE //SPI模式
uchar i;
TF_CMD_H;
for(i=0; i<74; i++)
{
TF_CLK_L;
delayus(1);
TF_DI_H;
TF_CLK_H;
delayus(1);
}
TF_CLK_L;
#endif
#ifdef SD_MODE //SD模式
uchar i;
TF_CMD_H;
for(i=0; i<74; i++)
{
TF_CLK_L;
delayus(1);
TF_DI_H;
TF_CLK_H;
delayus(1);
}
TF_CLK_L;
#endif
}
void delayclk(uchar nclk,uchar speed) //等待,nclk:等待的时钟周期数; speed =1 for slow, 0 for quick
{
#ifdef SPI_MODE //SPI模式
uchar i;
TF_CMD_H;
for(i=0; i<nclk; i++)
{
TF_CLK_L;
if(speed) delayus(1);
TF_D0_H;
TF_CLK_H;
if(speed) delayus(1);
}
TF_CLK_L;
#endif
#ifdef SD_MODE //SD模式
uchar i;
TF_CMD_H;
for(i=0; i<nclk; i++)
{
TF_CLK_L;
if(speed) delayus(1);
TF_D0_H;
TF_CLK_H;
if(speed) delayus(1);
}
TF_CLK_L;
#endif
}
void tf_inti() //TF卡初始化
{
#ifdef SPI_MODE //SPI模式
uchar i,temp,cmd[5];
TF_CS_H;
TF_CLK_L;
TF_DI_H;
TF_D0_H;
TF_D1_H;
TF_D2_H;
i =0;
while(TF_TEST_R)
{
delay(10);
i +=1;
if(i>200) break;
}; //等待TF卡插入
if(i>200)
{
OwnErr =1;
return;
}
delay(1); //延迟1ms
cmd[0] =0x40;
cmd[1] =0x00;
cmd[2] =0x00;
cmd[3] =0x00;
cmd[4] =0x00;
tf_74clk(); //等待74个周期
TF_CS_H;
TF_CLK_L;
TF_CS_L;
delayus(1);
//tf_send_cmd(cmd,1); //发送CMD0
//delayclk(8,1);
i =0;
do
{
tf_send_cmd(cmd,1); //发送CMD0
delay(24);
tf_rev_res(&temp,1,1); //接收R1
i +=1;
if(i>200) break;
}
while(temp !=0x01);
if(i >200)
{
OwnErr =2;
TF_CS_H;
return;
}
TF_CS_H;
TF_CLK_L;
TF_DI_H;
TF_D0_H;
TF_D1_H;
TF_D2_H;
delayclk(8,1);
cmd[0] =0x41;
cmd[1] =0x00;
cmd[2] =0x00;
cmd[3] =0x00;
cmd[4] =0x00;
//tf_send_cmd(cmd,1); //发送CMD1
//delayclk(8,1);
TF_CS_H;
TF_CLK_L;
TF_CS_L;
delayus(1);
i =0;
do
{
tf_send_cmd(cmd,1); //发送CMD1
delay(24);
tf_rev_res(&temp,1,1);
i +=1;
}
while((temp !=0x00)&&(i<200)); //激活卡
if(i==200)
{
OwnErr =3;
TF_CS_H;
return;
}
TF_CS_H;
delayclk(8,1);
#endif
#ifdef SD_MODE //SD模式
uchar i,j,cmd[5],tem[6];
TF_CS_H;
TF_CLK_L;
TF_DI_H;
TF_D0_H;
TF_D1_H;
TF_D2_H;
i =0;
while(TF_TEST_R)
{
delay(10);
i +=1;
if(i>200) break;
}; //等待TF卡插入
if(i>200)
{
OwnErr =1;
return;
}
delay(1); //延迟1ms
cmd[0] =0x40;
cmd[1] =0x00;
cmd[2] =0x00;
cmd[3] =0x00;
cmd[4] =0x00;
tf_74clk(); //等待74个周期
//tf_send_cmd(cmd,1); //发送CMD0
//delayclk(8,1);
i =0;
//do
{
tf_send_cmd(cmd,1); //发送CMD0
delay(24);
//tf_rev_res(&temp,1,1); //接收R1
//i +=1;
//if(i>200) break;
}
//while(temp !=0x01);
cmd[0] =0x40 | 8;
cmd[1] =0x00;
cmd[2] =0x00;
cmd[3] =0x01;
cmd[4] =0xaa;
tf_send_cmd(cmd,1); //发送CMD8
delay(24);
if(i >200)
{
OwnErr =2;
TF_CS_H;
return;
}
j =0;
tf_inti_1:
TF_CS_H;
TF_CLK_L;
TF_DI_H;
TF_D0_H;
TF_D1_H;
TF_D2_H;
delayclk(8,1);
cmd[0] =0x40 | 55;
cmd[1] =0x00;
cmd[2] =0x00;
cmd[3] =0x00;
cmd[4] =0x00;
TF_CS_H;
TF_CLK_L;
//TF_CS_L;
delayus(1);
i =0;
do
{
tf_send_cmd(cmd,1); //发送CMD55
delay(24);
tf_rev_res(tem,6,1);
i +=1;
}
while( (((tem[0] & 0xc0) !=0x00)||((tem[1] & 0x80) !=0x00)) && (i<200) ) ; //下一个发送应用指令
cmd[0] =0x40 | 41;
cmd[1] =0x00;
cmd[2] =0xff;
cmd[3] =0x80;
cmd[4] =0x00;
{
tf_send_cmd(cmd,1); //发送ACMD41
delayclk(8,1);
tf_rev_res(tem,6,1);
j +=1;
}
if((((tem[0] & 0xc0) !=0x00)||((tem[1]& 0x80) !=0x80)) && (j<200)) goto tf_inti_1;
if(j==200)
{
OwnErr =3;
TF_CS_H;
return;
}
if(i==200)
{
OwnErr =3;
TF_CS_H;
return;
}
TF_CS_H;
delayclk(8,1);
#endif
}
uchar tf_single_read(uchar *pbuf, uint sector) //读扇区(512字节), *pbuf: 存储区; sector: 扇区号; 返回0表示成功
{
#ifdef SPI_MODE //SPI模式
uchar cmd[5],i,temp;
uint addr;
addr =sector;
addr <<=9;
cmd[0] =0x40 | 0x11;
cmd[1] =(addr>>24);
cmd[2] =(addr>>16);
cmd[3] =(addr>>8);
cmd[4] =addr;
TF_CS_H;
TF_CLK_L;
TF_DI_H;
TF_D0_H;
TF_D1_H;
TF_D2_H;
//delay(1);
TF_CS_L;
//delay(1);
//tf_send_cmd(cmd,0); //发送单块数据读指令
//delayus(1); //间断一下
i =0;
while(1)
{
tf_send_cmd(cmd,0); //发送单块数据读指令
//delayus(1); //间断一下
tf_rev_res(&temp,1,0);
if(temp ==0) break;
i +=1;
if(i>200)
{
TF_CS_H;
return(1);
}
}; //读回应R1, 0x00才合法
delayus(1);
i=0;
while(tf_rev_byte_data() !=0xfe)
{
i +=1;
if(i>200)
{
TF_CS_H;
return(1);
};
} //读起始令牌, 0xfe合法
tf_rev_data(pbuf,512); //读512字节数据
i =tf_rev_byte_data();
i =tf_rev_byte_data(); //读CRC16
//delayus(1);
TF_CS_H;
//delayclk(8,0);
return(0); //成功
#endif
#ifdef SD_MODE //SD模式
uchar cmd[5],i,temp[6];
uint addr;
addr =sector;
addr <<=9;
cmd[0] =0x40 | 0x11;
cmd[1] =(addr>>24);
cmd[2] =(addr>>16);
cmd[3] =(addr>>8);
cmd[4] =addr;
TF_CS_H;
TF_CLK_L;
TF_DI_H;
TF_D0_H;
TF_D1_H;
TF_D2_H;
//delay(1);
// TF_CS_L;
//delay(1);
//tf_send_cmd(cmd,0); //发送单块数据读指令
//delayus(1); //间断一下
i =0;
while(1)
{
tf_send_cmd(cmd,0); //发送单块数据读指令
//delayus(1); //间断一下
tf_rev_res(temp,6,0);
if((temp[1]&0x80) ==0) break;
i +=1;
if(i>200)
{
TF_CS_H;
return(1);
}
}; //读回应R1, 0x00才合法
delayus(1);
i=0;
while(tf_rev_byte_data() !=0xfe)
{
i +=1;
if(i>200)
{
TF_CS_H;
return(1);
};
} //读起始令牌, 0xfe合法
tf_rev_data(pbuf,512); //读512字节数据
i =tf_rev_byte_data();
i =tf_rev_byte_data(); //读CRC16
//delayus(1);
TF_CS_H;
//delayclk(8,0);
return(0); //成功
#endif
}
|