- u8 SD_SendCommand(u8 cmd,u32 arg, u8 crc)
- {
- u8 r1;
- unsigned int Retry = 0;
-
- SD_CS_DISABLE();
- SPI_ReadWriteByte(0xff);//提高兼容性,如果没有这里,有些SD卡可能不支持
- SD_CS_ENABLE();//片选端置低,选中SD卡
-
- /*发送命令序列*/
- SPI_ReadWriteByte(cmd | 0x40);
- SPI_ReadWriteByte((u8)(arg>>24));//参数[31..24]
- SPI_ReadWriteByte((u8)(arg>>16));//参数[23..16]
- SPI_ReadWriteByte((u8)(arg>>8)); //参数[15..8]
- SPI_ReadWriteByte((u8)arg); //参数[7..0]
- SPI_ReadWriteByte(crc);
-
- //等待响应,或超时退出
- while((r1 = SPI_ReadWriteByte(0xff)==0xff))
- {
- Retry++;
- if(Retry>800)break;//根据实验测得,最好重试次数多点
- }
- //关闭片选
- SD_CS_DISABLE();
- //在总线上额外增加8个时钟,让SD卡完成剩下的工作
- SPI_ReadWriteByte(0xff);
-
- //返回状态值
- return r1;
-
- }
- /************************************************************************
- *SD卡初始化函数
- *延时等待SD卡上电完成
- *给至少74个脉冲让SD卡自己初始化完成
- *持续发送发送CMD0接收0x01(可以不接受)SD回应进入Idle(空闲)状态
- *
- ************************************************************************/
-
- u8 SD_Init(void)
- {
- u16 i; //用来循环计数
- u8 r1; //存放SD卡的返回值
- u16 retry; //用来进行超时计数
- u8 buff[6];
-
- SPI_ControlLine(); //SPI的配置初始化
- SPI_SetSpeed(SPI_SPEED_LOW);
- SD_CS_ENABLE();
-
- //纯延时,等待SD卡上电完成
- for(i=0;i<0xf00;i++);
-
- //先产生至少74个脉冲,让SD卡自己初始化完成
- for(i=0;i<10;i++)
- {
- SPI_ReadWriteByte(0xFF); //80clks
- }
-
- //-------------------SD卡复位到idle开始-------------------
- //循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态
- //超时则直接退出
- retry = 0;
- do
- {
- //发送CMD0,让SD卡进入IDLE状态
- ri = SD_SendCommand(CMD0,0,0x95);
- retry++;
- }while((r1 != 0x01)&& (retry<200));
- //跳出循环后,检查原因: 初始化成功?or重试超时?
- if(retry==200) return 1;//超时返回1
-
-
- //--------------SD卡复位到idle结束----------
- //获取卡片的SD版本信息
- r1 = SD_SendCommand_NoDeassert(CMD8,0x1aa,0x87);
- //如果卡片版本信息是V1.0版本的,即r1=0x05,则进行以下初始化
- if(r1==0x05)
- {
- //设置卡类型为SDV1.0,如果后面检测为MMC卡,再修改为MMC
- SD_Type = SD_TYPE_V1;
- //如果是V1.0卡,CMD8指令后没有后续数据
- //片选置高,结束本次命令
- SD_CS_DISABLE();
- //多发8个clk,让SD结束后续操作
- SPI_ReadWriteByte(0xff);
- //----------------SD卡、MMC卡初始化开始------------------
- //发卡初始化指令CMD55+ACMD41
- //如果有应答,说明是SD卡,且初始化完成
- //没有回应,说明是MMC卡,额外进行相应初始化
- retry = 0;
- do
- {
- //先发CMD55,应返回0x01,否则出错
- r1 = SD_SendCommand(CMD55,0,0);
- if(r1 !=0x01)
- return r1;
- //得到正确响应后,发ACMD41,应得到返回值0x00,佛则重试400次
- r1 = SD_SendCommand(ACMD41,0,0);
- retry++;
- }while((r1!=0x00)&&(retry<400));
- //判断是超时还是得到正确回应
- // 若有回应:是SD卡:没有回应:是MMC卡
-
- //---------------MMC卡额外初始化操作开始-------------
- if(retry==400)
- {
- retry =0;
- //发送MMC卡初始化命令(没有测试)
- do
- {
- r1=SD_SendCommand(CMD1,0,0);
- retry++;
- }while(r1!=0x00)&&(retry<400);
- if(retry==400)return 1;//MMC卡初始化超时
- //写入卡类型
- SD_Type=SD_TYPE_MMC;
- }
- //----------MMC卡额外初始化操作结束---------------
- //设置SPI为高速模式
- SPI_SetSpeed(SPI_SPEED_HIGH);
- SPI_ReaadWriteByte(0xff);
-
- //禁止CRC校验
- r1=SD_SendCommand(CMD59,0,0x95);
- if(r1!=0x00)return r1;//命令错误,返回r1
- //-------------SD卡、MMC卡初始化结束-------------
-
- }//SD卡为V1.0版本的初始化结束
- //下面是V2.0卡的初始化
- //其中需要读取OCR数据,判断是SD2.0还是SD2.0HC
- else if(r1==0x01)
- {
- //v2.0的卡,CMD8命令后会传回4字节的数据,要跳过在结束本命令
- buff[0]=SPI_ReadWriteByte(0xff);//shoule be 0x00
- buff[1]=SPI_ReadWriteByte(0xff);//shoule be 0x00
- buff[2]=SPI_ReadWriteByte(0xff);//shoule be 0x11
- SD_CS_DISABLE();
- SPI_ReadWriteByte(0xff);//the next 8 clocks
- //判断该卡是否支持2.7-3.6的电压范围
- //if(buff[2]==0x01&&buff[3]==0xaa)//如不判断,让其支持的卡更多
- //{
- retry = 0;
- //发卡初始化指令CMD55+ACMD41
- do
- {
- r1=SD_SendCommand(CMD55,0,0);
- if(r1!=0x01)return r1;
- r1=SD_SendCommand(ACMD41,0x40000000,1);
- if(retry>200)return r1;//超时则返回r1状态
- }while(r1!=0);
- //初始化指令发送完成,接下来获取OCR信息
- //----------鉴别SD2.0卡版本开始------------
- r1=SD_SendCommand_NoDeassert(CMD58,0,0);
- if(r1!=0x00)return r1;//如果命令没有返回正确应答,直接退出返回应答
- //读OCR指令发出后,紧接着是4字节的OCR信息
- buff[0]=SPI_ReadWriteByte(0xff);
- buff[1]=SPI_ReadWriteByte(0xff);
- buff[2]=SPI_ReadWriteByte(0xff);
- buff[3]=SPI_ReadWriteByte(0xff);
-
- //OCR接收完成,片选置高
- SD_CS_DISABLE();
- SPI_ReadWriteByte(0xff);
-
- //检查接收到的OCR中的bit30位(CCS),确定其为SD2还是SDHC
- //如果CCS=1:SDHC CCS=0: SD2.0
- if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC;//检查CCS
- else SD_Type=SD_TYPE_V2;
- //------------------鉴别SD2.0卡版本结束------------------
- //设置SPI为高速模式
- SPI_SetSpeed(1);
- }
- return r1
-
- }
-
- /******************************************************************
- *********************SPI模式GPIO端口设置***************************
- **************PA5=SCK、PA6=MISO、PA7=MOSI、PA4=CS******************
- ******************************************************************/
-
- void SPI_ControlLine(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC ,ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
-
- /*configuration SPI1 pins:,SCK,MISO and MOSI*/
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //MISO应该要初始化为上拉输入
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- /*configration PA4 Pin: CS Pin*/
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- }
-
- /**************************************************************************
- ***********************SPI通信模式初始化***********************************
- ***********************设置高速或低速模式**********************************
- **************************************************************************/
-
- void SPI_SetSpeed(u8 SpeedSet)
- {
- /* Initialize the SPI1 according to the SPI_InitStructure members */
- SPI_InitTypeDef SPI_InitStructure;
- if(SpeedSet==SPI_SPEED_HIGH)//高速
- {
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DatSize = SPI_DatSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
-
-
- SPI_Init(SPI1, &SPI_InitStructure);
- /*SPI1 enable*/
- SPI_Cmd(SPI1,ENABLE);
- }
- else//低速
- {
- SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
- SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
- SPI_InitStructure.SPI_DatSize = SPI_DatSize_8b;
- SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
- SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
- SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
- SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
- SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
- SPI_InitStructure.SPI_CRCPolynomial = 7;
-
- SPI_Init(SPI1,&SPI_InitStructure);
- /*SPI1 enable*/
- SPI_Cmd(SPI1,ENABLE);
- }
- }
-
- /************************************************************
- **************************发送命令***************************
- ************************************************************/
-
- u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg,u8 crc)
- {
- unsigned char r1;
- unsigned int Retry = 0;
-
- SD_CS_DISABLE();
- SPI_ReadWriteByte(0xff);//提高兼容性,如果没有这里,有些SD卡可能不支持
- SD_CS_ENABLE();//片选端置低,选中SD卡
-
- /*发送命令序列*/
- SPI_ReadWriteByte(cmd | 0x40);
- SPI_ReadWriteByte((u8)(arg>>24));//参数[31..24]
- SPI_ReadWriteByte((u8)(arg>>24));//参数[23..16]
- SPI_ReadWriteByte((u8)(arg>>24));//参数[7..0]
- SPI_ReadWriteByte(crc);
-
- //等待响应,或超时退出
- while((r1 = SPI_ReadWriteByte(0xff))==0xff)
- {
- Retry++;
- if(Retry>600)break;//根据实验测得,最好重试次数多点
- }
- //返回响应值
- return r1;
- }
-
- /**************************************************************
- ************************向SD卡写一个块*************************
- **************************************************************/
-
- u8 SD_WriteSingleBlock(u32 sector,const u8 *data)
- {
- u8 r1;
- u16 i;
- u16 retry;
-
- //设置为高速模式
- SPI_SetSpeed(SPI_SPEED_LOW);
-
- //如果不是SDHC,给定的是sector地址,将其转换成byte地址
- if(SD_Type!=SD_TYPE_V2HC)
- {
- sector = sector<<9;//512*sector即物理扇区的边界对齐地址
- }
-
- r1 = SD_SendCommand(CMD24,sector,0x00);
- if(r1 !=0x00)
- {
- return r1;//应答不正确,直接返回
- }
-
- //开始准备数据传输
- SD_CS_ENABLE();
- //先放3个空数据,等待SD卡准备好
- SPI_ReadWriteByte(0xff);
- SPI_ReadWriteByte(0xff);
- SPI_ReadWriteByte(0xff);
- //放起始令牌0xfe
- SPI_ReadWriteByte(0xfe);
-
- //发一个sector的数据
- for(i=0;i<512;i++)
- {
- SPI_ReadWriteByte(*data++);
- }
- //发2个Byte的dummy CRC
- SPI_ReadWriteByte(0xff);
- SPI_ReadWriteByte(0xff);
-
- //等待SD卡应答
- r1 = SPI_ReadWriteByte(0xff);
- if((r1&0x1f)!=0x05)
- {
- SD_CS_DISABLE();
- return r1;
- }
-
- //等待操作完成
- retry = 0;
- while(!SPI_ReadWriteByte(0xff))//卡自编程时,数据线被拉低
- {
- retry++;
- if(retry>65534) //如果长时间写入没有完成,报错退出
- {
- SD_CS_DISABLE();
- return 1; //写入超时返回1
- }
- }
-
- //写入完成,片选置1
- SD_CS_DISABLE();
- SPI_ReadWriteByte(0xff);
-
- return 0;
- }
-
- /********************************************************
- ******************从SD中读取一个块***********************
- ********************************************************/
-
- u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)
- {
- u8 r1;
- //设置为高速模式
- SPI_SetSpeed(SPI_SPEED_LOW);
-
- if(SD_Type!=SD_TYPE_V2HC)
- {
- sector = sector<<9;//512*sector即物理扇区的边界对齐地址
- }
-
- //如果不是SDHC,将sector地址转成byte地址
- //sector = sector<<9;
-
- r1 = SD_SendCommand(CMD17,sector,1);//读命令
-
- if(r1 !=0x00)return r1;
- r1 = SD_ReceiveData(buffer,512,EELEASE) ;
- if(r1 != 0)
- return r1; //读数据出错!
- else
- return 0;
- }
-
- /************************************************************
- ************************接收数据*****************************
- ************************************************************/
-
- u8 SD_ReceiveData(u8 *data,u16 len,u8 release)
- {
- u16 retry;
- u8 r1;
- //启动一次传输
- SD_CSENABLE();
- //等待SD卡发回数据起始令牌0xfe
- retry = 0;
- do
- {
- r1 = SPI_ReadWriteByte(0xff);
- retry++;
- if(retry>4000) //4000次等待后没有应答,退出报错(根据实验测试,此处最好多试几次)
- {
- SD_CS_DISABLE();
- return 1;
- }
- }while(r1 != 0xfe);
-
- //开始接收数据
- while(len--)
- {
- *data = SPI_ReadWriteByte(0xff);
- data++;
- }
- //下面是2个伪CRC(dummy CRC)
- SPI_ReadWriteByte(0xff);
- SPI_ReadWriteByte(0xff);
- //按需释放总线,将CS置高
- if(release == RELEASE)
- {
- //传输结束
- SD_CS_DISABLE();
- SPI_ReadWriteByte(0xff);
- }
- return 0;
- }
- void SPI_ReadWriteByte(u8 xxx)
- {
- }
- void USART_Configuration(void)
- {
- }