STM32 SDIO驱动SD卡,初探 (标志库)

经过两天的调试,终于完成了SD卡的上电,初始化,读信息的部分。不说废话,先上图:

读到SD卡大小

 上代码(使用标志库):

sdio.c
#include "sdio.h"
uint8_t flag_bit;//完成初始化标志位
CID read_cid;
CID read_csd;
uint32_t rca;
uint32_t size;
uint32_t SD_identify()
{
    uint8_t temp;
   GPIO_InitTypeDef HGPIO;
   SDIO_InitTypeDef HSDIO;
   //时钟使能
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE); 
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE); 
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO,ENABLE);
   
   //GPIO初始化
   
   HGPIO.GPIO_Mode=GPIO_Mode_AF;
   HGPIO.GPIO_OType=GPIO_OType_PP;
   HGPIO.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
   HGPIO.GPIO_PuPd=GPIO_PuPd_UP;
   HGPIO.GPIO_Speed=GPIO_Speed_100MHz;
   GPIO_Init(GPIOC,&HGPIO);
   HGPIO.GPIO_Mode=GPIO_Mode_AF;
   HGPIO.GPIO_OType=GPIO_OType_PP;
   HGPIO.GPIO_Pin=GPIO_Pin_2;
   HGPIO.GPIO_PuPd=GPIO_PuPd_UP;
   HGPIO.GPIO_Speed=GPIO_Speed_100MHz;
   GPIO_Init(GPIOD,&HGPIO);

   //复用功能配置
   GPIO_PinAFConfig(GPIOC,GPIO_PinSource8,GPIO_AF_SDIO);
   GPIO_PinAFConfig(GPIOC,GPIO_PinSource9,GPIO_AF_SDIO);
   GPIO_PinAFConfig(GPIOC,GPIO_PinSource10,GPIO_AF_SDIO);
   GPIO_PinAFConfig(GPIOC,GPIO_PinSource11,GPIO_AF_SDIO);
   GPIO_PinAFConfig(GPIOC,GPIO_PinSource12,GPIO_AF_SDIO);
   GPIO_PinAFConfig(GPIOD,GPIO_PinSource2,GPIO_AF_SDIO);

   //SDIO初始化
   HSDIO.SDIO_BusWide=SDIO_BusWide_1b;
   HSDIO.SDIO_ClockBypass=SDIO_ClockBypass_Disable;
   HSDIO.SDIO_ClockDiv=118;
   HSDIO.SDIO_ClockEdge=SDIO_ClockEdge_Rising;
   HSDIO.SDIO_ClockPowerSave=SDIO_ClockBypass_Disable;
   HSDIO.SDIO_HardwareFlowControl=SDIO_HardwareFlowControl_Disable;
   SDIO_Init(&HSDIO);
   temp=sd_power_on();
   if(flag_bit==1)
   {
       read_sdcard_csd();
       return temp;
   }
   else
   {
       return temp;
   }
}
void sd_send_commder(uint32_t commder_int,uint32_t arg,uint32_t response)
{
    SDIO_CmdInitTypeDef HSDIO_COMMDER;
    HSDIO_COMMDER.SDIO_Argument=arg;
    HSDIO_COMMDER.SDIO_CmdIndex=commder_int;
    HSDIO_COMMDER.SDIO_CPSM=SDIO_CPSM_Enable;
    HSDIO_COMMDER.SDIO_Response=response;
    HSDIO_COMMDER.SDIO_Wait=SDIO_Wait_No;
    SDIO_SendCommand(&HSDIO_COMMDER);
}
uint8_t sd_power_on()
{
    int i;
    uint8_t temp;
    uint16_t timeout;
    uint32_t response;
    timeout=0xffff;
    SDIO_SetPowerState(SDIO_PowerState_ON);
    SDIO_ClockCmd(ENABLE);
    for ( i=0; i < 78; i++)
    {
        sd_send_commder(0,0,SDIO_Response_No);
        temp=cmdresponse(0);
    }
    delay_us(200);
    sd_send_commder(0,0,SDIO_Response_No);
    temp=cmdresponse(0);
    if (temp==sd_ok)
    {
        delay_us(200);
        SDIO->ICR|=(1<<7);
        sd_send_commder(8,0x000001AA,SDIO_Response_Short);
        temp=cmdresponse7();
        if(temp!=sd_ok) return sd_timeout;
        delay_us(200);
        while (timeout>0)
        {
            sd_send_commder(55,(uint32_t)0,SDIO_Response_Short);
            temp=cmdresponse7();
            if(temp!=sd_ok) return temp;
            delay_us(200);
            sd_send_commder(41,0x40200000,SDIO_Response_Short);
            temp=cmdresponse3();
            if (temp!=sd_ok) return temp;
            response=SDIO_GetResponse(SDIO_RESP1);
            if((response>>31)==1) break;
            delay_us(200);
            timeout--;//上电完成
        }
        if (timeout==0)
        {
            return sd_timeout;
        }
        else
        {  
            flag_bit =1;
            return sd_ok;
        } 
    }
    else
    {
        return temp;
    }

    
}
sd_error read_sdcard_csd()
{
    uint8_t temp;
    uint16_t a;
    sd_send_commder(2,(uint32_t)0,SDIO_Response_Long);//获取卡信息
    temp=cmdresponse7();
    if (temp!=sd_ok) return temp;
    read_cid.Rresp1=SDIO->RESP1;
    read_cid.Rresp2=SDIO->RESP2;
    read_cid.Rresp3=SDIO->RESP3;
    read_cid.Rresp4=SDIO->RESP4;
    delay_us(200);
    sd_send_commder(3,(uint32_t)0,SDIO_Response_Short);//进入传输模式
    temp=cmdresponse7();
    if (temp!=sd_ok) return temp;
    rca=SDIO->RESP1;
    rca>>=16;
    sd_send_commder(9,(uint32_t)(rca<<16),SDIO_Response_Long);//读取sd卡特殊寄存器
    temp=cmdresponse7();
    if (temp!=sd_ok) return temp;
    read_csd.Rresp1=SDIO->RESP1;
    read_csd.Rresp2=SDIO->RESP2;
    read_csd.Rresp3=SDIO->RESP3;
    read_csd.Rresp4=SDIO->RESP4;
    a=(uint16_t)(read_csd.Rresp3>>16);
    size=(a+1)*512;
    return sd_ok;
}
uint8_t cmdresponse()
{
    u32 temp;
    uint8_t timeout=0xff;
    uint8_t return_data=sd_ok;
    while (timeout)
    {
        temp=SDIO->STA;
        if(temp&&(1<<7))break;
        timeout--;
    }
    if(timeout==0)return sd_timeout;
    SDIO->ICR=0X5FF;
    return return_data;
    
}
uint8_t cmdresponse7()
{
    uint32_t temp=sd_ok;
    uint16_t timeout=0xffff;
    uint32_t register_read;
    while (timeout)
    {
        register_read=SDIO->STA;
        if(register_read&((1<<0)|(1<<2)|(1<<6))) break;
        timeout--;
    }
    if (timeout==0)
    {
        return sd_timeout;
    }
    if (((register_read&(1<<6))>>6)==0x01)
    {
        SDIO->ICR|=(1<<6);
        return sd_ok;
    }
    if (((register_read&(1<<2))>>2)==0x01)
    {
        SDIO->ICR|=(1<<2);
        return sd_timeout;
    }
    if ((register_read&(1<<0))==0x01)
    {
        SDIO->ICR|=(1<<0);
        return sd_crcerroe;
    }
}
uint8_t cmdresponse3()
{
    uint32_t temp=sd_ok;
    uint16_t timeout=0xffff;
    uint32_t register_read;
    while (timeout)
    {
        register_read=SDIO->STA;
        if(register_read&((1<<0)|(1<<2)|(1<<6))) break;
        timeout--;
    }
    if (timeout==0)
    {
        return sd_timeout;
    }
    if (((register_read&(1<<2))>>2)==0x01)
    {
        SDIO->ICR|=(1<<2);
        return sd_timeout;
    }
    SDIO->ICR=0X5FF;
    return sd_ok;	
}
sdio.h
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_sdio.h"
#include "delay.h"
typedef enum
{
    sd_ok=0x40,
    sd_timeout=0x04,
    sd_crcerroe=0x01,
    sd_send_ok=0x80

}sd_error;
typedef struct sdio
{
    uint32_t Rresp1;
    uint32_t Rresp2;
    uint32_t Rresp3;
    uint32_t Rresp4;
}CID;
extern CID read_cid;
extern CID read_csd;
extern uint32_t rca;
extern uint32_t size;
uint32_t SD_identify(void);
void sd_send_commder(uint32_t commder_int,uint32_t arg,uint32_t response);
uint8_t sd_power_on();
sd_error read_sdcard_csd();
uint8_t cmdresponse();
uint8_t cmdresponse7();
uint8_t cmdresponse3();

中间坑还是挺多的,我把我遇到的坑和解决办法进行罗列

1、用调试器进行调试时,返回值正常,不调试就会返回超时,后加延迟解决。在sd卡协议v2.0版中提到,“两个命令之间至少要有8个时钟的延迟后发生新的命令。

2、发送ACMD41命令后一直返回crc校验错误,这是个大坑!!!。在调试中发现,虽然crc校验位被至位,但命令响应寄存器中已经读到了相印的数据,并且看原子哥的代码中也忽略了crc校验错误位。下面是原子哥的代码

SD_Error CmdResp3Error(void)
{
	u32 status;						 
 	while(1)
	{
		status=SDMMC1->STA;
		if(status&((1<<0)|(1<<2)|(1<<6)))break;//CRC错误/命令响应超时/已经收到响应(CRC校验成功)	
	}
 	if(status&(1<<2))					//响应超时
	{											 
		SDMMC1->ICR|=1<<2;				//清除命令响应超时标志
		return SD_CMD_RSP_TIMEOUT;
	}	 
   	SDMMC1->ICR=0X5FF;	 				//清除标记
 	return SD_OK;								  
}

3、搞错响应类型,会导致crc错误,请各位同仁注意检查响应类型

SDIO_Response_Short  //短响应

SDIO_Response_Long  //长响应,28位

SDIO_Response_No  //无响应

4、上电后要先给卡>74个时钟,然后再发送cmd0

 for ( i=0; i < 78; i++)
    {
        sd_send_commder(0,0,SDIO_Response_No);
        temp=cmdresponse(0);
    }

欣喜之余,打算最近把fat文件系统移植上去。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个人创造世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值