最近接到客户的项目中用到了SD卡来存储传感器数据,于是从网上寻得了原子哥的驱动程序,使用的单片机为STM32F103RBT6的mini板,使用的SD卡为金士顿8G,以及某宝上淘来的SD卡读写模块,使用到的参考资料为SD卡2.0协议PDF版,一切准备就绪。

配置硬件SPI格式为:主模式,8bit , CPOL为高电平,NSS信号为软件管理以使用其它IO作为片选脚,CPHA为1---数据捕获于第二个时钟沿,高位先出,首先SPI设置为低速模式256分频,然后发送0xff启动传输。

按照协议给出的初始化过程,如下图,按部就班的进行操作,首先应发送至少74个脉冲使SD卡做好数据接收准备,

for(i=0;i<10;i++)
		SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲

然后一直发送CMD0直到SD卡返回0x01,注意CRC一定为0x95,使SD卡进入空闲模式;

retry=20;
	do
	{
		r1=SD_SendCmd(CMD0,0,0x95);		//判断是否进入IDLE状态
	}while((r1!=0X01) && retry--);

NFCReaderSession readingAvailable崩溃 0x01 nfc reader tool_软件管理

接下来发送CMD8检查SD卡支持电压是否支持2.7~3.6V,命令格式如下,VHS设置为0001b,手册中建议将checkpattern设置为0xaa,对应CRC为0x87:

NFCReaderSession readingAvailable崩溃 0x01 nfc reader tool_软件管理_02

CMD8发送完成后准备接收回应R7,格式如下,我们需要判断R1部分IDLE位是否依然有效,checkpattern部分是否为0xaa,若是则说明卡支持2.7~3.6V:

if(SD_SendCmd(CMD8,0x000001AA,0x87)==1)//发送接口状态命令判断是否支持SD V2.0.checkpatern=0xaa
		{
			for(i=0;i<4;i++)
				buf[i]=SD_SPI_ReadWriteByte(0XFF);	//获得剩余回应字节
			if(buf[2]==0X01&&buf[3]==0XAA)//判断checkpattern 回应与VDH, 卡是否支持2.7~3.6V
			{
                            接下来发送ACMD41读取OCR;
                        }


                 }

NFCReaderSession readingAvailable崩溃 0x01 nfc reader tool_数据_03

接下来发送ACMD41命令告诉SD卡主机支持大容量SD卡操作,ACMD41格式为

NFCReaderSession readingAvailable崩溃 0x01 nfc reader tool_数据_04

HCS置位1,代表主机支持大容量SD卡,注意原子哥给出的程序中将命令参数写为了0x40,注意这样的话在传参时实际写入的参数为0x00000040,这和ACMD参数格式是不符的,会使SD卡返回的r1值为0x01!!!,需要把0x40改为0x40000000!!!

NFCReaderSession readingAvailable崩溃 0x01 nfc reader tool_i++_05

修改后:

NFCReaderSession readingAvailable崩溃 0x01 nfc reader tool_软件管理_06

,这样便能正确返回r1,此时SD卡应退出了空闲状态,r1为0x00,否则继续发送ACMD41指令(CMD55告诉SD卡吓一跳指令为特殊应用指令)。

后续操作不再赘述。