【STM32】STM32 SDIO SD卡读写测试(三)-- SD_Init之Init Card阶段

相关文章

《【SDIO】SDIO、SD卡、FatFs文件系统相关文章索引》

1. 前言

本篇文章主要是介绍stm324x9i_eval_sdio_sd.c里面SD_Init()函数完整的过程。它主要是实现了SDIO的初始化SD卡的Power UPSD卡的初始化获取SD卡的相关信息等,下面会详细介绍SD卡的初始化获取SD卡的相关信息的分析。
在这里插入图片描述

2. SD_InitializeCards()

SD_InitializeCards()主要的功能是初始化SD卡获取CID和RCA的信息,并进入Standby状态。主要涉及到的函数如下:

  • CMD2: SD_CMD_ALL_SEND_CID
  • CMD3: SD_CMD_SET_REL_ADDR
  • CMD9: SD_CMD_SEND_CSD

2.1 CMD2: SD_CMD_ALL_SEND_CID

CMD2: SD_CMD_ALL_SEND_CID是通知所有卡通过 CMD 线返回 CID值,CID值是卡的唯一标识。在卡发送CID后,它进入识别状态。

#define SD_CMD_ALL_SEND_CID                        ((uint8_t)2)

/*!< Send CMD2 ALL_SEND_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);

发送出去的波形如下:
在这里插入图片描述
发送CMD2命令后,调用CmdResp2Error()获取SDIO 状态寄存器 (SDIO_STA) Value,通过返回的状态Value来判断命令响应是否已经正确被接收。如果响应被正确被接受,通过访问SDIO 响应 1…4 寄存器 (SDIO_RESPx)来获取CID的值。

errorstatus = CmdResp2Error();

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

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);

从SD2.0协议里面可以了解到CMD2的response格式是R2,R2主要获取CID或者CSD值。
在这里插入图片描述
在这里插入图片描述
为什么获取CID值需要读取SDIO Response 1…4寄存器?
因为在STM32的SDIO相关寄存器可以了解到关于127 Bit 长响应会用到SDIO_RESP1..4这4个寄存器拼接成的(如下图STM32 SDIO Datasheet所示),所以这里需要访问这4个寄存器。如果命令响应的参数的长度是32 Bit 短响应,那么就只需要读取SDIO_RESP1寄存器的Value。

R1、R2、R3、R6、R7SDIO_RESP1…4 这2个概率容易弄混:

在这里插入图片描述
逻辑分析仪抓取波形如下:
在这里插入图片描述
从上面的波形可以获取到CID值为:0x03534453433332478049D204AD012ADF,关于CID的表格如下:

Name Field Width CID-slice Value
Manufacturer ID MID 8 [127:120] 0x03
OEM/Application ID OID 16 [119:104] 0x5344
Product name PNM 40 [103:64] "S C 3 2 G"
(0x5343333247)
Product revision PRV 8 [63:56] 0x80
Product serial number PSN 32 [55:24] 0x49D204AD
reserved -- 4 [23:20] 0
Manufacturing date MDT 12 [19:8] 0x12A
(October 2018)
CRC7 checksum CRC 7 [7:1] 0x6F
not used, always 1 - 1 [0:0] 1

PNM:
The product name is a string, 5-character ASCII string.
MDT:
The “m” field [11:8] is the month code. 1 = January.
The “y” field [19:12] is the year code. 0 = 2000.

2.2 CMD3: SD_CMD_SET_REL_ADDR

CMD3: SD_CMD_SET_REL_ADDR 主机发出CMD3 (SEND_RELATIVE_ADDR)请求SD卡发布一个新的相对卡地址(RCA),它比CID短,在未来的数据传输模式中用于给SD卡寻址。一旦接收到RCA,SD卡状态就会变为待机状态。此时,如果主机希望分配另一个RCA号码,它可以通过向卡发送另一个CMD3命令来要求卡发布一个新号码。最后发布的RCA是SD卡的实际RCA号。

#define SD_CMD_SET_REL_ADDR                        ((uint8_t)3) /*!< SDIO_SEND_REL_ADDR for SD Card */

/*!< Send CMD3 SET_REL_ADDR with argument 0 */
/*!< SD Card publishes its 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);

因为发送命令CMD3的Argument是stuff bits,所以这里需要填写0x00。实际发送出去的波形如下:
在这里插入图片描述
发送CMD3命令后,调用CmdResp6Error()获取SDIO 状态寄存器 (SDIO_STA) Value,通过返回的状态Value来判断命令响应是否已经正确被接收。如果响应被正确被接受,通过访问SDIO 命令响应寄存器 (SDIO_RESPCMD)来获取Response Command Index。判断Response Command Index是否等于CMD3,然后访问SDIO 响应 1 寄存器 (SDIO_RESP1)来获取RCA的值。

static SD_Error CmdResp6Error(uint8_t cmd, uint16_t *prca)
{
    
    
  SD_Error errorstatus = SD_OK;
  uint32_t status;
  uint32_t response_r1;

  status = SDIO->STA;

  while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CTIMEOUT | SDIO_FLAG_CMDREND)))
  {
    
    
    status = SDIO->STA;
  }

  ...

  /*!< Check response received is of desired command */
  if (SDIO_GetCommandResponse() != cmd)
  {
    
    
    errorstatus = SD_ILLEGAL_CMD;
    return(errorstatus);
  }

  /*!< Clear all the static flags */
  SDIO_ClearFlag(SDIO_STATIC_FLAGS);

  /*!< We have received response, retrieve it.  */
  response_r1 = SDIO_GetResponse(SDIO_RESP1);

  if (SD_ALLZERO == (response_r1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED)))
  {
    
    
    *prca = (uint16_t) (response_r1 >> 16);
    return(errorstatus);
  }

  ...

  return(errorstatus);
}

从SD2.0协议里面可以了解到CMD3的response格式是R6,R6主要获取RCA和Card Status Bits的值。
在这里插入图片描述
在这里插入图片描述
逻辑分析仪抓取波形可以了解到 RCA = 0xAAAA,波形如下:
在这里插入图片描述

2.3 CMD9: SD_CMD_SEND_CSD

CMD9: SD_CMD_SEND_CSD主机发出SEND_CSD(CMD9)以获取与SD卡有关的数据(CSD寄存器),例如块长度、卡的储存容量等。

#define SD_CMD_SEND_CSD                            ((uint8_t)9)

/*!< Send CMD9 SEND_CSD with argument as card's RCA */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16); // RCA = 0xAAAA
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);

发送CMD9命令时,Argument需要填写RCA。前面已经获取到 RCA = 0xAAAA,所以实际发送的命令波形如下:
在这里插入图片描述
发送CMD9命令后,调用CmdResp2Error()获取SDIO 状态寄存器 (SDIO_STA) Value,通过返回的状态Value来判断命令响应是否已经正确被接收。如果响应被正确被接受,通过访问SDIO 响应 1…4 寄存器 (SDIO_RESPx)来获取CSD的值。

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);

从SD2.0协议里面可以了解到CMD2的response格式是R2,R2主要获取CID或者CSD值。
在这里插入图片描述
在这里插入图片描述
逻辑分析仪抓取波形如下:
在这里插入图片描述
从上面的波形可以获取到CSD值为:0x400E00325B590000EDC87F800A4040C3,关于CSD的表格如下:

Name Field Width Value Cell Type CID-slice
CSD structure CSD_STRUCTURE 2 01b R [127:126]
reserved - 6 00 0000b R [125:120]
data read access-time (TAAC) 8 0Eh R [119:112]
data read access-time
in CLK cycles (NSAC*100)
(NSAC) 8 00h R [111:104]
max. data transfer rate (TRAN_SPEED) 8 32h or 5Ah R [103:96]
card command classes CCC 12 010110110101b R [95:84]
max. read data block length (READ_BL_LEN) 4 9 R [83:80]
partial blocks for read allowed (READ_BL_PARTIAL) 1 0 R [79:79]
write block misalignment (WRITE_BLK_MISALIGN) 1 0 R [78:78]
read block misalignment (READ_BLK_MISALIGN) 1 0 R [77:77]
DSR implemented DSR_IMP 1 0 R [76:76]
reserved - 6 00 0000b R [75:70]
device size C_SIZE 22 00 EDC8h R [69:48]
reserved - 1 0 R [47:47]
erase single block enable (ERASE_BLK_EN) 1 1 R [46:46]
erase sector size (SECTOR_SIZE) 7 7Fh R [45:39]
write protect group size (WP_GRP_SIZE) 7 0000000b R [38:32]
write protect group enable (WP_GRP_ENABLE) 1 0 R [31:31]
reserved - 2 00b R [30:29]
write speed factor (R2W_FACTOR) 3 010b R [28:26]
max. write data block length (WRITE_BL_LEN) 4 9 R [25:22]
partial blocks for write allowed (WRITE_BL_PARTIAL) 1 0 R [21:21]
reserved - 5 00000b R [20:16]
File format group (FILE_FORMAT_GRP) 1 0 R [15:15]
copy flag (OTP) COPY 1 1 R/W(1) [14:14]
permanent write protection PERM_WRITE_PROTECT 1 0 R/W(1) [13:13]
temporary write protection TMP_WRITE_PROTECT 1 0 R/W [12:12]
File format (FILE_FORMAT) 2 00b R [11:10]
reserved - 2 00b R [9:8]
CRC CRC 7 110 0001b R/W [7:1]
not used, always’1’ - 1 1 - [0:0]
  • CSD_STRUCTURE
    CSD_STRUCTURE指示了CSD structure version,根据上面解析的数据,所以选择的是CSD Version 2.0。
    CSD_STRUCTURE

  • TRAN_SPEED
    下表定义了每条数据线的最大数据传输速率- TRAN_SPEED:
    在这里插入图片描述
    当时钟等于25MHz时,这个域总是0_0110_010b (032h)。如果时钟等于50MHz时,这个域总是0_1011_010b (05Ah)

  • READ_BL_LEN
    READ_BL_LEN最大读数据块长度计算公式为2READ_BL_LEN,最大块长度应该在512…2048个字节。注意,在SD存储卡的WRITE_BL_LEN总是等于READ_BL_LEN。根据上面数据的解析,所以Block Length的值为 29 = 512 Bytes
    在这里插入图片描述

3.SDIO_Init()

SDIO_Init()主要是配置SDIO时钟控制寄存器(SDIO_CLKCR)。因为接下来SD卡会进入传输模式,所以这里需要提高SDIO Clock,这里将SDIO_CK 频率设置为25MHz。

/** 
  * @brief  SDIO Data Transfer Frequency (25MHz max) 
  */
#define SDIO_TRANSFER_CLK_DIV            ((uint8_t)0x0)

/*!< Configure the SDIO peripheral */
/*!< SDIO_CK = SDIOCLK / (SDIO_TRANSFER_CLK_DIV + 2) */
/*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStructure);

在这里插入图片描述

名称 描述 Value 备注
CLKDIV 时钟分频系数 (Clock divide factor)
该字段定义输入时钟 (SDIOCLK) 与输出时钟 (SDIO_CK) 之间的分频系数:
SDIO_CK 频率 = SDIOCLK / [CLKDIV + 2]
0x00 SDIO_CK 频率 = SDIOCLK / [CLKDIV + 2]
24M = 48M / [0x00 + 2]

设置SDIO_CK之前,频率为400KHz左右,如下:
在这里插入图片描述
设置SDIO_CK之后,频率为25MHz左右,如下:
在这里插入图片描述

4.SD_GetCardInfo()

SD_GetCardInfo()主要作用是解析前面获取到CSD的值,具体可以参考上面的表格,这里不重复介绍了。

SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{
    
    
  SD_Error errorstatus = SD_OK;
  uint8_t tmp = 0;

  cardinfo->CardType = (uint8_t)CardType;
  cardinfo->RCA = (uint16_t)RCA;

  /*!< Byte 0 */
  tmp = (uint8_t)((CSD_Tab[0] & 0xFF000000) >> 24);
  cardinfo->SD_csd.CSDStruct = (tmp & 0xC0) >> 6;
  cardinfo->SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;
  cardinfo->SD_csd.Reserved1 = tmp & 0x03;

  /*!< Byte 1 */
  tmp = (uint8_t)((CSD_Tab[0] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.TAAC = tmp;

  /*!< Byte 2 */
  tmp = (uint8_t)((CSD_Tab[0] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.NSAC = tmp;

  /*!< Byte 3 */
  tmp = (uint8_t)(CSD_Tab[0] & 0x000000FF);
  cardinfo->SD_csd.MaxBusClkFrec = tmp;

  /*!< Byte 4 */
  tmp = (uint8_t)((CSD_Tab[1] & 0xFF000000) >> 24);
  cardinfo->SD_csd.CardComdClasses = tmp << 4;

  /*!< Byte 5 */
  tmp = (uint8_t)((CSD_Tab[1] & 0x00FF0000) >> 16);
  cardinfo->SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;
  cardinfo->SD_csd.RdBlockLen = tmp & 0x0F;

  /*!< Byte 6 */
  tmp = (uint8_t)((CSD_Tab[1] & 0x0000FF00) >> 8);
  cardinfo->SD_csd.PartBlockRead = (tmp & 0x80) >> 7;
  cardinfo->SD_csd.WrBlockMisalign = (tmp & 0x40) >> 6;
  cardinfo->SD_csd.RdBlockMisalign = (tmp & 0x20) >> 5;
  cardinfo->SD_csd.DSRImpl = (tmp & 0x10) >> 4;
  cardinfo->SD_csd.Reserved2 = 0; /*!< Reserved */
 
  ...

}

5.SD_SelectDeselect()

SD_SelectDeselect()主要作用是通过CMD7选择对应的RCA地址的SD卡进入传输模式,前面已经获取到RCA地址为 RCA = 0xAAAACMD7用于选择一张SD卡并将其置于传输状态,在同一时刻只能有一张卡处于传输状态。如果先前选择的卡处于传输状态,它与主机的连接将被释放,它将返回到 Stand-by 状态。

errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));  // RCA = 0xAAAA

-------------------------------------------------->

SD_Error SD_SelectDeselect(uint64_t addr)
{
    
    
  SD_Error errorstatus = SD_OK;

  /*!< Send CMD7 SDIO_SEL_DESEL_CARD */
  SDIO_CmdInitStructure.SDIO_Argument =  (uint32_t)addr;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEL_DESEL_CARD;
  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_SEL_DESEL_CARD);

  return(errorstatus);
}

实际发送出去的波形如下:
在这里插入图片描述
发送CMD7命令后,调用CmdResp1Error获取SDIO 状态寄存器 (SDIO_STA)来判断命令响应是否已经正确被接收。然后,通过函数SDIO_GetCommandResponse获取SDIO 命令响应寄存器 (SDIO_RESPCMD) Value来判断Host接收到的响应命令是否是刚刚发送的命令。最后,通过函数SDIO_GetResponse获取SDIO 响应 1寄存器 (SDIO_RESP1) SD卡的状态。

static SD_Error CmdResp1Error(uint8_t cmd)
{
    
    
  SD_Error errorstatus = SD_OK;
  uint32_t status;
  uint32_t response_r1;

  status = SDIO->STA;

  while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
  {
    
    
    status = SDIO->STA;
  }

  ...

  /*!< Check response received is of desired command */
  if (SDIO_GetCommandResponse() != cmd)
  {
    
    
    errorstatus = SD_ILLEGAL_CMD;
    return(errorstatus);
  }

  /*!< Clear all the static flags */
  SDIO_ClearFlag(SDIO_STATIC_FLAGS);

  /*!< We have received response, retrieve it for analysis  */
  response_r1 = SDIO_GetResponse(SDIO_RESP1);

  if ((response_r1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
  {
    
    
    return(errorstatus);
  }

  if (response_r1 & SD_OCR_ADDR_OUT_OF_RANGE)
  {
    
    
    return(SD_ADDR_OUT_OF_RANGE);
  }

  ...
  
  return(errorstatus);
}

从SD2.0协议里面可以了解到CMD7的response是R1b,R1b和R1功能完全相同,主要获取的Card Status。
在这里插入图片描述
在这里插入图片描述
通过逻辑分析仪抓取的波形, Card Status指示SD卡当前状态为Stand-by 状态, 如下:
在这里插入图片描述
在这里插入图片描述

6.SD_EnableWideBusOperation()

通过SD_EnableWideBusOperation(SDIO_BusWide_4b)设置总线宽度为4bit模式,首先需要获取SCR Register Value(FindSCR())判定SD卡是否支持4bit模式,然后发送ACMD6设置SD卡工作在4bit模式,同时host端STM32也设置为4bit模式。整体的思维导图如下:
在这里插入图片描述

6.1 CMD16:SD_CMD_SET_BLOCKLEN

FindSCR()函数中发送CMD16:SD_CMD_SET_BLOCKLEN来设置SD卡Block Size为8 Bytes

#define SD_CMD_SET_BLOCKLEN                        ((uint8_t)16)

/*!< Set Block Size To 8 Bytes */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)8;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
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_SET_BLOCKLEN);

在这里插入图片描述
实际发送出去波形如下:
在这里插入图片描述
然后SD卡处理完后,以R1的形式Response Card Status,波形如下:
在这里插入图片描述

6.2 SDIO_DataConfig()

SDIO_DataConfig()设置STM32 SDIO寄存器DLEN和DCTRL数据长度和块大小为8Bytes,并设置传输方向为:SD Card -> Host SDIO

  SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
  SDIO_DataInitStructure.SDIO_DataLength = 8;
  SDIO_DataInitStructure.SDIO_DataBlockSize = SDIO_DataBlockSize_8b;
  SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;
  SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;
  SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;
  SDIO_DataConfig(&SDIO_DataInitStructure);

6.3 ACMD51:SD_CMD_SD_APP_SEND_SCR

ACMD51:SD_CMD_SD_APP_SEND_SCR主要是读取配置寄存器 SCR的值,发送完这个命令后R1返回Card Status,然后在DATA0数据线上返回SCR的值。

#define SD_CMD_SD_APP_SEND_SCR                     ((uint8_t)51) /*!< For SD Card only */

/*!< Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
SDIO_CmdInitStructure.SDIO_Argument = 0x0;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_SEND_SCR;
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_SD_APP_SEND_SCR);

在这里插入图片描述
实际发送出去的波形如下:
在这里插入图片描述
然后SD卡处理完后,以R1的形式Response Card Status,波形如下:
在这里插入图片描述

6.4 SDIO_ReadData()

SDIO_ReadData()从SDIO FIFO中获取DATA0 SD卡返回的SCR Value:

  while (!(SDIO->STA & (SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR)))
  {
    
    
    if (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET)
    {
    
    
      *(tempscr + index) = SDIO_ReadData();
      index++;
    }
  }

在SDIO DATA0上面返回SCR Value为:0x0235804300000000,波形如下:
在这里插入图片描述
SCR Value为:0x0235804300000000对应SCR寄存器的表格如下:

Description Field Width Value Cell
Type
SCR
Slice
SCR Structure SCR_STRUCTURE 4 0000b R [63:60]
SD Memory Card - Spec. Version SD_SPEC 4 0010b R [59:56]
data_status_after erases DATA_STAT_AFTER_ERASE 1 0b R [55:55]
SD Security Support SD_SECURITY 3 011b R [54:52]
DAT Bus widths supported SD_BUS_WIDTHS 4 0101b R [51:48]
reserved - 16 R [47:32]
reserved for manufacturer usage - 32 R [31:0]
  • SCR_STRUCTURE
    在这里插入图片描述
  • SD_SPEC
    SD_SPEC描述了SD卡支持SD协议版本号。
    在这里插入图片描述
  • SD_SECURITY
    SD_SECURITY描述了Security Specification Version版本号。
    在这里插入图片描述
  • SD_BUS_WIDTHS
    SD_BUS_WIDTHS描述了SDIO总线的宽度,同时支持1bit和4bit。
    在这里插入图片描述

6.5 ACMD6:SD_CMD_APP_SD_SET_BUSWIDTH

ACMD6:SD_CMD_APP_SD_SET_BUSWIDTH 通过SCR Value判断SD卡支持4bit总线,并通过AMCD6设置SD卡总线宽度为4bit。

#define SD_CMD_APP_SD_SET_BUSWIDTH                 ((uint8_t)6)  /*!< For SD Card only */

/*!< Send ACMD6 APP_CMD with argument as 2 for wide bus mode */
SDIO_CmdInitStructure.SDIO_Argument = 0x2;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_SD_SET_BUSWIDTH;
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_SD_SET_BUSWIDTH);

在这里插入图片描述
实际发送出去的波形如下:
在这里插入图片描述

6.6 SDIO_Init()

SDIO_Init()配置STM32 SDIO时钟控制寄存器(SDIO_CLKCR):时钟为25MHz和总线宽度为4bit模式

/*!< Configure the SDIO peripheral */
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV; 
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_4b;
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStructure);

Note:到此SD_Init的整个SD卡初始化完成。

7. 参考资料

SDIO参考的资料如下:
在这里插入图片描述
下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/14975835

移植成功的完整代码下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/15265756

猜你喜欢

转载自blog.csdn.net/ZHONGCAI0901/article/details/113849280