相关文章
《【SDIO】SDIO、SD卡、FatFs文件系统相关文章索引》
1. 前言
本篇文章主要是介绍stm324x9i_eval_sdio_sd.c
里面SD_Init()函数完整的过程。它主要是实现了SDIO的初始化、SD卡的Power UP、SD卡的初始化和获取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、R7 和 SDIO_RESP1…4 这2个概率容易弄混:
R1、R2、R3、R6、R7
:这个是SD2.0《Physical Specification Version 2.00》 协议规定CMD响应命令格式。SDIO_RESP1..4
:这个是STM32寄存器存放命令响应参数的值。
逻辑分析仪抓取波形如下:
从上面的波形可以获取到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。
-
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 = 0xAAAA。CMD7用于选择一张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