Skip to content

SDIO

协议简介

常见的SD卡可以使用两种模式的通讯, SPI或者SDIO模式

SD卡: 安全数字存储卡, 内存<=2GB叫做SD, 2GB<=内存<=32GB叫做SDHC, 32<=内存叫做SDXC, stm32最大支持32GB

SDIO: 安全数字输入输出接口, 可以驱动MMC卡, SD卡, SD I/O卡(接在一些设备上用于通讯, 不是存储器), CE-ATA设备是一种硬盘使用的, 是一种总线

物理结构

image-20230719112332523

实际上是NOR Flash, 以块进行读写, 根据命令进行读写

image-20230719112749337

SD卡内部的寄存器

CID: 每个厂商申请, 可以用于区分不同的SD卡

RCA: 实际上也可以用于区分设备

CSR: 判断卡的状态

SSR: 保存卡的信息

image-20230719113154012

协议可以连接多个, stm32只能连接一个

SD卡一共有9-pin, 三根电源线, 一根时钟线, 一根命令线, 四根数据线

CLK: 时钟线, 主机产生, 上升的时候有效

CMD: 命令控制线, SDIO发送命令控制SD卡, 命令应答的时候也是通过这条线

D0-3: 数据线, 传输读写数据, 可以吧D0拉低表示忙状态

V~DD~, V~SS1~, V~SS2~: 电源以及地

image-20240107222154762

SD卡使用两种频率通讯, 一个是识别时候的频率FOD, 最高400KHz, 另一个是数据传输模式下的FPP默认25MHz, 最高50MHz

传输协议: 基于命令的, 先发送一个0, 结束的时候发送一个1, 有响应的命令返回数值

读写操作: 数据块一般为512字节, 需要CRC位保证数据传输成功, 硬件产生

image-20230719115905304

在读之前需要检测忙标志

image-20230719120254087

image-20230719120356780

用于SSR寄存器

命令

广播命令: 对连接的所有的卡发出的信号

寻址命令: 包含卡的地址

  • 命令格式

image-20230719123550551

固定48位, 传输标志是确定传输方向的

CRC算法计算进行校验

基本命令64个

image-20230719124517148

有一些扩展的命令, 特定应用命令, ACMD, 需要在发送之前发送CMD55, 之后发送ACMD命令, 如果发现不是ACMD, 执行标准命令

实际的命令

image-20230719125621779

SDIO 总共有 7 个响应类型 (代号:R1~R7),其中 SD 卡没有 R4、R5 类型响应。特定的命令对应 有特定的响应类型,比如当主机发送 CMD3 命令时,可以得到响应 R6。与命令一样,SD 卡的 响应也是通过 CMD 线连续传输的。根据响应内容大小可以分为短响应和长响应。短响应是 48bit 长度,只有 R2 类型是长响应,其长度为 136bit。各个类型响应具体情况如表 SD 卡响应类型 。

image-20230719130207910

读取sdsc地址以直接为单位, sdhc卡是块为地址

通过CMD7进行选定一张卡

擦除命令需要使用三个命令

操作模式

在初始化的时候有一个初始化模式, 叫做卡识别模式, 之后使用数据传输模式

stm32支持的模式是2.0, 使用的时候需要区分卡使用的模式且卡的容量需要区分

系统复位以后主机处于卡识别模式, 寻找可用的SDIO同时SD卡也处于卡识别模式, 直到被识别到, SD卡接收到SEND_RCA(CMD3)之后进入传输模式

image-20230721152719980

无效模式, 使用CMD15进入

空闲状态, CMD1

准备状态, 环境正常之后进入

识别状态, 可以接受命令

待机状态, 低功耗

传输状态, 读写之前

发送数据状态, 传输的时候

接收数据状态,

编程状态, 这个是写入的时候, 传输的数据不一定立刻写入

断开连接状态, 换卡, 断开连接

image-20230721161545433

CMD8确认卡的状态

CMD41询问卡的信息

image-20230721162125582

stm32的实现

image-20240108153630938

SDIOCLK=72MHz

image-20230721183344035

image-20240108153856782

使用两个时钟, 一个是SDIO适配时钟, 另一个是AHB总线时钟二分频, SDIO适配器时钟(SDIOCLK)提供SDIO主机功能, 提供SD时钟, 发送命令进行数据交换, APB2接口用于访问器访问SDIO适配器并且可以产生中断和DMA

SDIOCLK=HCLK

image-20240108155202587

image-20230721183807207

image-20240108155633828

image-20240108155829162

image-20240108160541244

输出的时钟可以使用两种, FIFO是一个32个字的存储单元, 使用DMA进行传输

image-20230721184139651

命令通道

image-20230721192352934

数据通道

image-20240108161638925

命令格式

image-20240108162018331

image-20240108162128452

image-20240108162219022

寄存器

image-20240108162249773

  • SDIO_POWER: 电源控制寄存器

image-20230721190317841

  • SDIO_CLKCR: 时钟控制寄存器

image-20230721190414369

默认的时候使用的是1根总线, 初始化结束以后可以使用4位的模式

image-20240108170517958

开始初始化的时候设置小于400KHz, 之后时钟频率小于25MHz

  • SDIO_ARG: 参数寄存器

image-20230721190452248

  • SDIO_CMD: 命令寄存器

image-20230721190107858

一般位10设置为1, 使用状态机

位6-7根据命令进行设置

0-5代表要发送的命令

  • SDIO_RESPCMD: 命令响应寄存器

image-20230721190552042

  • SDIO_RESPx: 响应寄存器

image-20230721190709273

  • SDIO_DTIMER: 数据定时器寄存器

image-20230721190745284

在写入数据控制器进行数据传输之前必须先写入数据定时器寄存器和数据长度寄存器

  • SDIO_DLEN: 数据长度寄存器

image-20230721190820520

这个的数值必须是块数据长度的倍数

  • SDIO_DCTRL: 数据控制寄存器

image-20230721190903000

块的长度设置为512字节

image-20240108171442596

传输的时候使用的是块模式进行传输的

  • SDIO_DCOUNT: 数据计数器寄存器

image-20230721190946068

  • SDIO_STA: 状态寄存器

image-20240108171550273

  • SDIO_ICR: 清除中断寄存器
  • SDIO_MASK: 中断屏蔽寄存器
  • SDIO_FIFOCNT: 计数器寄存器
  • SDIO_FIFO: FIFO寄存器, 数据缓冲

接收和发送FIFO是32位宽度读或写一组寄存器,它在连续的32个地址上包含32个寄存器,CPU可以使用FIFO读写多个操作数。

image-20240108171652567

操作的时候需要以4字节对齐的内存进行操作

使用

c
typedef struct
{
  uint32_t SDIO_ClockEdge;            /*!< Specifies the clock transition on which the bit capture is made.
                                           This parameter can be a value of @ref SDIO_Clock_Edge
                                           设置时钟的有效边沿*/

  uint32_t SDIO_ClockBypass;          /*!< Specifies whether the SDIO Clock divider bypass is
                                           enabled or disabled.
                                           This parameter can be a value of @ref SDIO_Clock_Bypass 
                                           时钟分频设置, 使能这直接SDIOCLK驱动CLK线, 禁用的话分品之后使用*/

  uint32_t SDIO_ClockPowerSave;       /*!< Specifies whether SDIO Clock output is enabled or
                                           disabled when the bus is idle.
                                           This parameter can be a value of @ref SDIO_Clock_Power_Save 
                                           是否使用节能模式*/

  uint32_t SDIO_BusWide;              /*!< Specifies the SDIO bus width.
                                           This parameter can be a value of @ref SDIO_Bus_Wide 
                                           数据的宽度, 一般设置为8位*/

  uint32_t SDIO_HardwareFlowControl;  /*!< Specifies whether the SDIO hardware flow control is enabled or disabled.
                                           This parameter can be a value of @ref SDIO_Hardware_Flow_Control 
                                           是否使能硬件控制FIFO*/

  uint8_t SDIO_ClockDiv;              /*!< Specifies the clock frequency of the SDIO controller.
                                           This parameter can be a value between 0x00 and 0xFF.
                                           时钟分频, CLK时钟线的值=SDIOCLK/(CLKDIV+2)*/
                                           
} SDIO_InitTypeDef;//初始化

typedef struct
{
  uint32_t SDIO_Argument;  /*!< Specifies the SDIO command argument which is sent
                                to a card as part of a command message. If a command
                                contains an argument, it must be loaded into this register
                                before writing the command to the command register 
                                命令参数*/

  uint32_t SDIO_CmdIndex;  /*!< Specifies the SDIO command index. It must be lower than 0x40. 命令号*/

  uint32_t SDIO_Response;  /*!< Specifies the SDIO response type.
                                This parameter can be a value of @ref SDIO_Response_Type 
                                响应的类型*/

  uint32_t SDIO_Wait;      /*!< Specifies whether SDIO wait-for-interrupt request is enabled or disabled.
                                This parameter can be a value of @ref SDIO_Wait_Interrupt_State
                                等待使能, 是否等待响应*/

  uint32_t SDIO_CPSM;      /*!< Specifies whether SDIO Command path state machine (CPSM)
                                is enabled or disabled.
                                This parameter can be a value of @ref SDIO_CPSM_State
                                命令路径状态机*/
} SDIO_CmdInitTypeDef;//发送命令

typedef struct
{
  uint32_t SDIO_DataTimeOut;    /*!< Specifies the data timeout period in card bus clock periods.
  							  数据时钟超时, 多少时钟之后进入超时*/

  uint32_t SDIO_DataLength;     /*!< Specifies the number of data bytes to be transferred. 数据长度*/
 
  uint32_t SDIO_DataBlockSize;  /*!< Specifies the data block size for block transfer.
                                     This parameter can be a value of @ref SDIO_Data_Block_Size 数据块的大小*/
 
  uint32_t SDIO_TransferDir;    /*!< Specifies the data transfer direction, whether the transfer
                                     is a read or write.
                                     This parameter can be a value of @ref SDIO_Transfer_Direction
                                     数据传输的方向*/
 
  uint32_t SDIO_TransferMode;   /*!< Specifies whether data transfer is in stream or block mode.
                                     This parameter can be a value of @ref SDIO_Transfer_Type
                                     数据传输的模式, 数据块和数据流, 流是MMC卡*/
 
  uint32_t SDIO_DPSM;           /*!< Specifies whether SDIO Data path state machine (DPSM)
                                     is enabled or disabled.
                                     This parameter can be a value of @ref SDIO_DPSM_State 数据路径状态机*/
} SDIO_DataInitTypeDef;//用于数据发送接收

实际使用

image-20230724200731339

image-20230724201533241

实际上程序是移植过来的

【固件库】STM32F10x_StdPeriph_Lib_V3.5.0\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples \SDIO\uSDCard下面的所有文件

以及

【固件库】STM32F10x_StdPeriph_Lib_V3.5.0\【固件库】STM32F10x_StdPeriph_Lib_V3.5.0\Utilities\STM32_EVAL\Common下面的

image-20230725140935063

还有【固件库】STM32F10x_StdPeriph_Lib_V3.5.0\【固件库】STM32F10x_StdPeriph_Lib_V3.5.0\Utilities\STM32_EVAL\STM3210E_EVAL的

image-20230725141119995

eval是评估板的名字

使用

  • 初始化中断优先级
c
static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure the NVIC Preemption Priority Bits */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
  • 初始化引脚, 以及DMA
c
static void GPIO_Configuration(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  /*!< GPIOC and GPIOD Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD , ENABLE);

  /*!< Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  /*!< Configure PD.02 CMD line */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_Init(GPIOD, &GPIO_InitStructure); 

  /*!< Enable the SDIO AHB Clock 初始化时钟*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);

  /*!< Enable the DMA2 Clock 使能DMA的时钟*/
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
}
  • SDIO恢复初始化(之前初始化的是引脚)
c
void SDIO_DeInit(void)
{
  SDIO->POWER = 0x00000000;
  SDIO->CLKCR = 0x00000000;
  SDIO->ARG = 0x00000000;
  SDIO->CMD = 0x00000000;
  SDIO->DTIMER = 0x00000000;
  SDIO->DLEN = 0x00000000;
  SDIO->DCTRL = 0x00000000;
  SDIO->ICR = 0x00C007FF;
  SDIO->MASK = 0x00000000;
}
  • 上电初始化
c
/*
 * 函数名:SD_PowerON
 * 描述  :确保SD卡的工作电压和配置控制时钟
 * 输入  :无
 * 输出  :-SD_Error SD卡错误代码
 *         成功时则为 SD_OK
 * 调用  :在 SD_Init() 调用
 */
SD_Error SD_PowerON(void)
{
  SD_Error errorstatus = SD_OK;
  uint32_t response = 0, count = 0, validvoltage = 0;
  uint32_t SDType = SD_STD_CAPACITY;
	
/********************************************************************************************************/
  /* 上电初始化 
   * 配置SDIO的外设
   * SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV)   
   * 初始化时的时钟不能大于400KHz
   */
	/* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */
  SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;		
	//时钟的有效边沿
  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
	
	/* 不使用bypass模式,直接用HCLK进行分频得到SDIO_CK, 这时候输出的时钟是根据分频因子配置的, 使能的话不进行分频*/
  SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;

	/* 空闲时不关闭时钟电源 */  
  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
	
	/* 初始化的时候暂时先把数据线配置成1根 */
  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
	
	/* 失能硬件流控制 MMC卡的*/
  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
	
  SDIO_Init(&SDIO_InitStructure);

  /* 开启SDIO外设的电源 */
  SDIO_SetPowerState(SDIO_PowerState_ON);

  /* 使能 SDIO 时钟 */
  SDIO_ClockCmd(ENABLE);  
/********************************************************************************************************/   
  /* 下面发送一系列命令,开始卡识别流程
   * CMD0: GO_IDLE_STATE(复位所以SD卡进入空闲状态) 
   * 没有响应  
	 */
  SDIO_CmdInitStructure.SDIO_Argument = 0x0;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE;
	
	/* 没有响应 */
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;
	
	/* 关闭等待中断 */
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
	
	/* 则CPSM在开始发送命令之前等待数据传输结束 */
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; 
  SDIO_SendCommand(&SDIO_CmdInitStructure);	  		
	
	/* 检测是否正确接收到cmd0 */
  errorstatus = CmdError();
	
	/* 命令发送出错,返回 */
  if (errorstatus != SD_OK)	
  {
    /* CMD Response TimeOut (wait for CMDSENT flag) */
    return(errorstatus);
  }
/********************************************************************************************************/
  /* CMD8: SEND_IF_COND 
   * Send CMD8 to verify SD card interface operating condition
	 *          
   * Argument: - [31:12]: Reserved (shall be set to '0')
   *           - [11:8] : Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
   *           - [7:0]  : Check Pattern (recommended 0xAA) 
   * CMD Response: R7 
	 */
	 /* 接收到命令sd会返回这个参数 */
  SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;
	//命令8, 测试卡的类型
  SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND;	
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;	 
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;			 				
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
   
  /*检查是否接收到命令*/
  errorstatus = CmdResp7Error(); 
	
	/* 有响应则card遵循sd协议2.0版本 */
  if (errorstatus == SD_OK)	  	
  {
		/* SD Card 2.0 ,先把它定义会sdsc类型的卡 */
    CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0;
		
		/* 这个变量用作ACMD41的参数,用来询问是sdsc卡还是sdhc卡 */
    SDType = SD_HIGH_CAPACITY;	
  }
  else	/* 无响应,说明是1.x的或mmc的卡 */
  {
    /* 发命令 CMD55 */	  
    SDIO_CmdInitStructure.SDIO_Argument = 0x00;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
    errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
  }
	
  /* CMD55 		
   * 发送cmd55,用于检测是sd卡还是mmc卡,或是不支持的卡
	 * CMD 响应: R1
   */  
  SDIO_CmdInitStructure.SDIO_Argument = 0x00;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
	
	/* 是否响应,没响应的是mmc或不支持的卡 */
  errorstatus = CmdResp1Error(SD_CMD_APP_CMD);	
/********************************************************************************************************/
  /* If errorstatus is Command TimeOut, it is a MMC card 
   * If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch)
   * or SD card 1.x 
	 */
  if (errorstatus == SD_OK)	//响应了cmd55,是sd卡,可能为1.x,可能为2.0
  {
  	/*下面开始循环地发送sdio支持的电压范围,循环一定次数*/

    /* SD CARD
     * Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 
		 */
    while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))
    {	 
			/* 在发送ACMD命令前都要先向卡发送CMD55 
       * SEND CMD55 APP_CMD with RCA as 0 
			 */
      SDIO_CmdInitStructure.SDIO_Argument = 0x00;
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;	  
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
      SDIO_SendCommand(&SDIO_CmdInitStructure);

      errorstatus = CmdResp1Error(SD_CMD_APP_CMD);
			
      if (errorstatus != SD_OK)
      {
        return(errorstatus);
      }
			
			/* ACMD41
			 * 命令参数由支持的电压范围及HCS位组成,HCS位置一来区分卡是SDSC还是SDHC
			 * 0:SDSC
			 * 1:SDHC
       * 响应:R3,对应的是OCR寄存器			
			 */			
      SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;	  
      SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;
      SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;  
      SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
      SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
      SDIO_SendCommand(&SDIO_CmdInitStructure);

      errorstatus = CmdResp3Error();
			
      if (errorstatus != SD_OK)
      {
        return(errorstatus); 
      }
			
			/* 若卡需求电压在SDIO的供电电压范围内,会自动上电并标志pwr_up位 
			 * 读取卡寄存器,卡状态
			 */
      response = SDIO_GetResponse(SDIO_RESP1);
			
			/* 读取卡的ocr寄存器的pwr_up位,看是否已工作在正常电压 */
      validvoltage = (((response >> 31) == 1) ? 1 : 0);	
      count++;			  /* 计算循环次数 */
    }
		
    if (count >= SD_MAX_VOLT_TRIAL)					 /* 循环检测超过一定次数还没上电 */
    {
      errorstatus = SD_INVALID_VOLTRANGE;	   /* SDIO不支持card的供电电压 */
      return(errorstatus);
    }
		
		/*检查卡返回信息中的HCS位*/
		/* 判断ocr中的ccs位 ,如果是sdsc卡则不执行下面的语句 */
    if (response &= SD_HIGH_CAPACITY)       
    {
      CardType = SDIO_HIGH_CAPACITY_SD_CARD; /* 把卡类型从初始化的sdsc型改为sdhc型 */
    }

  }/* else MMC Card */

  return(errorstatus);		
}
c
/*
 * 函数名:SD_InitializeCards
 * 描述  :初始化所有的卡或者单个卡进入就绪状态
 * 输入  :无
 * 输出  :-SD_Error SD卡错误代码
 *         成功时则为 SD_OK
 * 调用  :在 SD_Init() 调用,在调用power_on()上电卡识别完毕后,调用此函数进行卡初始化
 */
SD_Error SD_InitializeCards(void)
{
  SD_Error errorstatus = SD_OK;
  uint16_t rca = 0x01;
	//检测是不是处于掉电状态
  if (SDIO_GetPowerState() == SDIO_PowerState_OFF)
  {
    errorstatus = SD_REQUEST_NOT_APPLICABLE;
    return(errorstatus);
  }
	
	/* 判断卡的类型,不是数字类卡(是储存卡) */
  if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)
  {
    /* Send CMD2 ALL_SEND_CID 
		 * 响应:R2,对应CID寄存器
		 */
    SDIO_CmdInitStructure.SDIO_Argument = 0x0;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);

    errorstatus = CmdResp2Error();

    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
		
		/* 将返回的CID信息存储起来 */
    CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
    CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
    CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
    CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
  }
/********************************************************************************************************/
  if (   (SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) 
		   ||(SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) 
	     ||(SDIO_SECURE_DIGITAL_IO_COMBO_CARD == CardType)
       ||(SDIO_HIGH_CAPACITY_SD_CARD == CardType) )	 /* 使用的是2.0的卡 */
  {
    /* Send CMD3 SET_REL_ADDR with argument 0 
     * SD Card publishes its RCA.
     * 响应:R6,对应RCA寄存器		
		 */
    SDIO_CmdInitStructure.SDIO_Argument = 0x00;
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;		
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;		
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);
		
		/* 把接收到的卡相对地址存起来 */
    errorstatus = CmdResp6Error(SD_CMD_SET_REL_ADDR, &rca);	

    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }
  }
/********************************************************************************************************/
  if (SDIO_SECURE_DIGITAL_IO_CARD != CardType)
  {
    RCA = rca;

    /* Send CMD9 SEND_CSD with argument as card's RCA 
		 * 响应:R2  对应寄存器CSD(Card-Specific Data)
		 */
    SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);
    SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;
    SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;
    SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
    SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
    SDIO_SendCommand(&SDIO_CmdInitStructure);

    errorstatus = CmdResp2Error();

    if (SD_OK != errorstatus)
    {
      return(errorstatus);
    }

    CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);
    CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);
    CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);
    CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);
  }
/********************************************************************************************************/	
	/*全部卡初始化成功 */
  errorstatus = SD_OK; 

  return(errorstatus);
}

移植

  • 初始化diskio.c文件