相關文章
《【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
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/264566.html
標籤:其他
上一篇:抖音為什么這么火
