相關文章
《【SDIO】SDIO、SD卡、FatFs檔案系統相關文章索引》
1.前言
本篇文章主要是介紹SD卡的讀寫測驗,包括:SD卡擦除測驗、SD卡單一塊讀寫測驗、SD卡多個塊讀寫測驗,這個3個測驗主要是呼叫了stm324x9i_eval_sdio_sd.c里面的相關API,下面會詳細的介紹這些API是如何實作的,SD卡在Transfer Mode階段的狀態圖如下:

SD卡的讀寫測驗的思維導圖如下,下面會詳細介紹這3個函式是如何實作的:

NOTE:閱讀下面分析時最好參考SD卡讀寫測驗的完整工程一起,這樣有助于理解,工程下載地址下面有貼出來,
2.SD_EraseTest()
SD_EraseTest()函式主要的流程是擦除指定地址塊的存盤,通過DMA的方式讀取這寫塊的資料,判斷是否等于0xFF或者0x00(默認情況下擦除的Flash都是0xFF,特殊的情況下也有0x00),SD_EraseTest()函式具體實作如下:

2.1 CMD32:SD_CMD_SD_ERASE_GRP_START
CMD32:SD_CMD_SD_ERASE_GRP_START該命令主要是作用是設定擦除的起始塊地址,
#define SD_CMD_SD_ERASE_GRP_START ((uint8_t)32) /*!< To set the address of the first write
/*!< Send CMD32 SD_ERASE_GRP_START with argument as addr */
SDIO_CmdInitStructure.SDIO_Argument =(uint32_t)startaddr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_START;
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_ERASE_GRP_START);

發送命令CMD32的Argument是 start data block address,SD_EraseTest()設定擦除地址是0 ~ 51200Bytes,所以這里填寫的是0x00 (0/512),實際發送出去的波形如下:

然后SD卡處理完后,以R1的形式Response Card Status,通過CmdResp1Error檢測CMD是否正確回應,并且判斷Card Status是否存在錯誤,Receive的波形如下:

Card Status = 0x00000900對應的表格如下:

2.2 CMD33:SD_CMD_SD_ERASE_GRP_END
CMD33:SD_CMD_SD_ERASE_GRP_END該命令主要是作用是設定擦除的結束塊地址,
#define SD_CMD_SD_ERASE_GRP_END ((uint8_t)33) /*!< To set the address of the last write block of the
/*!< Send CMD33 SD_ERASE_GRP_END with argument as addr */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)endaddr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_END;
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_ERASE_GRP_END);

發送命令CMD33的Argument是 end data block address,SD_EraseTest()設定擦除地址是0 ~ 51200Bytes,所以這里填寫的是0x64 (51200/512),實際發送出去的波形如下:

然后SD卡處理完后,以R1的形式Response Card Status,通過CmdResp1Error檢測CMD是否正確回應,并且判斷Card Status是否存在錯誤,Receive的波形如下:

備注:R1 Response Card Status的狀態值和CMD32一樣,參考上面的截圖分析,
2.3 CMD38:SD_CMD_ERASE
CMD38:SD_CMD_ERASE該命令主要是作用是擦除預先選定的塊,
#define SD_CMD_ERASE ((uint8_t)38)
/*!< Send CMD38 ERASE */
SDIO_CmdInitStructure.SDIO_Argument = 0;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ERASE;
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_ERASE);

因為發送命令CMD38的Argument是stuff bits,所以這里需要填寫0x00,實際發送出去的波形如下:

Host發送CMD38后,DATA0保持低電平,說明SD處于Busy狀態,CMD回應會以R1的形式Response Card Status,通過CmdResp1Error檢測CMD是否正確回應,并且判斷Card Status是否存在錯誤,Receive的波形如下:

Card Status = 0x00000800對應的表格如下:

2.4 IsCardProgramming()
在SD_Erase()函式中,通過IsCardProgramming()函式回圈獲取SD卡Card Status,判斷并等待是否已經退出Programming State,
/*!< Wait till the card is in programming state */
errorstatus = IsCardProgramming(&cardstate);
delay = SD_DATATIMEOUT;
while ((delay > 0) && (errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate)))
{
errorstatus = IsCardProgramming(&cardstate);
delay--;
}
下面有貼出IsCardProgramming()函式的部分代碼,主要步驟如下:
- 發送CMD13:SD_CMD_SEND_STATUS獲取SD卡Card Status,
- 回圈獲取SDIO 狀態暫存器 (SDIO_STA),等待CMD13的Response被正確接收,
- 通過
SDIO_GetCommandResponse()獲取SDIO 命令回應暫存器 (SDIO_RESPCMD)來獲取Response Command Index,并且判斷是否等于CMD13(SD_CMD_SEND_STATUS), - 通過
SDIO_GetResponse(SDIO_RESP1)訪問SDIO 回應 1 暫存器 (SDIO_RESP1),來獲取Response Argument的引數,這個引數就是SD卡Card Status,然后回傳SD卡Current State(Card Status[12:9]),
static SD_Error IsCardProgramming(uint8_t *pstatus)
{
SD_Error errorstatus = SD_OK;
__IO uint32_t respR1 = 0, status = 0;
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) RCA << 16;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_STATUS;
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);
status = SDIO->STA;
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
{
status = SDIO->STA;
}
if (status & SDIO_FLAG_CTIMEOUT)
{
errorstatus = SD_CMD_RSP_TIMEOUT;
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
return(errorstatus);
}
else if (status & SDIO_FLAG_CCRCFAIL)
{
errorstatus = SD_CMD_CRC_FAIL;
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
return(errorstatus);
}
status = (uint32_t)SDIO_GetCommandResponse();
/*!< Check response received is of desired command */
if (status != SD_CMD_SEND_STATUS)
{
errorstatus = SD_ILLEGAL_CMD;
return(errorstatus);
}
/*!< Clear all the static flags */
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
/*!< We have received response, retrieve it for analysis */
respR1 = SDIO_GetResponse(SDIO_RESP1);
/*!< Find out card status */
*pstatus = (uint8_t) ((respR1 >> 9) & 0x0000000F);
if ((respR1 & SD_OCR_ERRORBITS) == SD_ALLZERO)
{
return(errorstatus);
}
...
}

發送CMD13:SD_CMD_SEND_STATUS的實際波形如下:

獲取CMD13的Response Card Status,通過Argument可以知道SD卡CURRENT_STATE = programming state,實際接收到的波形如下:

Card Status = 0x00000E00對應的表格如下:

經過一段時間,DATA0從Low Level跳轉到High Level,指示SD卡已經退出Busy狀態,然后發送CMD13來獲取Card Status,通過下面的波形我們可以知道Card Status = 0x00000900,說明SD卡已經退出programming state(CURRENT_STATE = transfer state),

3. SD_ReadMultiBlocks()
在SD_EraseTest()擦除測驗中有用到SD_ReadMultiBlocks(),該函式主要功能是通過DMA的方式讀取SD卡多個資料塊的資料,

3.1 SDIO_ITConfig()
SDIO_ITConfig()函式主要是配置SDIO 屏蔽暫存器 (SDIO_MASK),中斷屏蔽暫存器通過將對應的位置設定為 1 來確定哪一個狀態標志位可以產生中斷,,
SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);

| 名稱 | 描述 | Value | 備注 |
| DCRCFAILIE | 資料 CRC 失敗中斷使能 (Data CRC fail interrupt enable) 0:禁止資料 CRC 失敗中斷 1:使能資料 CRC 失敗中斷 | 1b | SDIO_IT_DCRCFAIL |
| DTIMEOUTIE | 資料超時中斷使能 (Data timeout interrupt enable) 0:禁止資料超時中斷 1:使能資料超時中斷 | 1b | SDIO_IT_DTIMEOUT |
| DATAENDIE | 資料結束中斷使能 (Data end interrupt enable) 0:禁止資料結束中斷 1:使能資料結束中斷 | 1b | SDIO_IT_DATAEND |
| RXOVERRIE | Rx FIFO 上溢錯誤中斷使能 (Rx FIFO overrun error interrupt enable) 0:禁止 Rx FIFO 上溢錯誤中斷 1:使能 Rx FIFO 上溢錯誤中斷 | 1b | SDIO_IT_RXOVERR |
| STBITERRIE | 起始位錯誤中斷使能 (Start bit error interrupt enable) 0:禁止起始位錯誤中斷 1:使能起始位錯誤中斷 | 1b | SDIO_IT_STBITERR |
3.2 SD_LowLevel_DMA_RxConfig()
DMA 簡介:直接存盤器訪問 (DMA) 用于在外設與存盤器之間以及存盤器與存盤器之間提供高速資料傳輸,可以在無需任何 CPU 操作的情況下通過 DMA 快速移動資料,這樣節省的 CPU 資源可供其它操作使用,主要的傳輸方式有3種:
- 外設到存盤器的傳輸
- 存盤器到外設的傳輸
- 存盤器到存盤器的傳輸

STM32F4xx 系列資源豐富,具有兩個 DMA 控制器,同時外設繁多,為實作正常傳輸,DMA需要通道選擇控制,每個 DMA控制器具有8個資料流,每個資料流對應 8個外設請求,在實作 DMA 傳輸之前,DMA控制器會通過 DMA資料流 x 配置暫存器 DMA_SxCR(x為 0~7,對應 8 個 DMA 資料流)的 CHSEL[2:0]位選擇對應的通道作為該資料流的目標外設,
外設通道選擇主要是為了選擇哪一個外設作為該資料流的源地址或者目標地址,

我們這里使用的是SDIO外設,在DMA2的映射表中可以找到,我們有2個可以選擇:
- 通道4 & 資料流3
- 通道4 & 資料流6
SD_LowLevel_DMA_RxConfig()具體代碼如下:
/**
* @brief SD SDIO configration parameter
*
*/
#define SD_SDIO_DMA DMA2
#define SD_SDIO_DMA_CLK RCC_AHB1Periph_DMA2
#define SD_SDIO_DMA_STREAM DMA2_Stream3
#define SD_SDIO_DMA_CHANNEL DMA_Channel_4
#define SD_SDIO_DMA_FLAG_FEIF DMA_FLAG_FEIF3
#define SD_SDIO_DMA_FLAG_DMEIF DMA_FLAG_DMEIF3
#define SD_SDIO_DMA_FLAG_TEIF DMA_FLAG_TEIF3
#define SD_SDIO_DMA_FLAG_HTIF DMA_FLAG_HTIF3
#define SD_SDIO_DMA_FLAG_TCIF DMA_FLAG_TCIF3
#define SD_SDIO_DMA_IRQn DMA2_Stream3_IRQn
#define SD_SDIO_DMA_IRQHANDLER DMA2_Stream3_IRQHandler
/**
* @brief Configures the DMA2 Channel4 for SDIO Rx request.
* @param BufferDST: pointer to the destination buffer
* @param BufferSize: buffer size
* @retval None
*/
void SD_LowLevel_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize)
{
DMA_InitTypeDef SDDMA_InitStructure;
DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_FEIF | SD_SDIO_DMA_FLAG_DMEIF | SD_SDIO_DMA_FLAG_TEIF | SD_SDIO_DMA_FLAG_HTIF | SD_SDIO_DMA_FLAG_TCIF);
/* DMA2 Stream3 or Stream6 disable */
DMA_Cmd(SD_SDIO_DMA_STREAM, DISABLE);
/* DMA2 Stream3 or Stream6 Config */
DMA_DeInit(SD_SDIO_DMA_STREAM);
SDDMA_InitStructure.DMA_Channel = SD_SDIO_DMA_CHANNEL;
SDDMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;
SDDMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)BufferDST;
SDDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
SDDMA_InitStructure.DMA_BufferSize = 1;
SDDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
SDDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
SDDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
SDDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
SDDMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
SDDMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
SDDMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
SDDMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
SDDMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_INC4;
SDDMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_INC4;
DMA_Init(SD_SDIO_DMA_STREAM, &SDDMA_InitStructure);
DMA_ITConfig(SD_SDIO_DMA_STREAM, DMA_IT_TC, ENABLE);
DMA_FlowControllerConfig(SD_SDIO_DMA_STREAM, DMA_FlowCtrl_Peripheral);
/* DMA2 Stream3 or Stream6 enable */
DMA_Cmd(SD_SDIO_DMA_STREAM, ENABLE);
}
具體分析如下:
- DMA_ClearFlag():清除DMA中斷相關標志位,
- DMA_Init():初始化DMA相關暫存器,涉及到暫存器有:
- DMA 資料流 x 配置暫存器 (DMA_SxCR) (x = 0…7)
- DMA 資料流 x FIFO 控制暫存器 (DMA_SxFCR) (x = 0…7)
- DMA 資料流 x 資料項數暫存器 (DMA_SxNDTR) (x = 0…7)
- DMA 資料流 x 外設地址暫存器 (DMA_SxPAR) (x = 0…7)
- DMA 資料流 x 存盤器 0 地址暫存器 (DMA_SxM0AR) (x = 0…7)
- DMA_ITConfig():配置DMA相關中斷暫存器,涉及到暫存器有:
- DMA 資料流 x 配置暫存器 (DMA_SxCR) (x = 0…7)
- DMA 資料流 x FIFO 控制暫存器 (DMA_SxFCR) (x = 0…7)
- DMA_FlowControllerConfig():配置DMA相關流控制暫存器,涉及到暫存器有:
- DMA 資料流 x 配置暫存器 (DMA_SxCR) (x = 0…7)
- DMA_Cmd():配置DMA相關資料流通道Enable Or Disabled,涉及到暫存器有:
- DMA 資料流 x 配置暫存器 (DMA_SxCR) (x = 0…7)

| 名稱 | 描述 | Value | 備注 |
| CHSEL[2:0] | 通道選擇 (Channel selection) 000:選擇通道 0 001:選擇通道 1 010:選擇通道 2 011:選擇通道 3 100:選擇通道 4 101:選擇通道 5 110:選擇通道 6 111:選擇通道 7 | 100b | DMA_Channel_4 |
| MBURST[1:0] | 存盤器突發傳輸配置 (Memory burst transfer configuration) 00:單次傳輸 01:INCR4(4 個節拍的增量突發傳輸) 10:INCR8(8 個節拍的增量突發傳輸) 11:INCR16(16 個節拍的增量突發傳輸) | 01b | DMA_MemoryBurst_INC4 |
| PBURST[1:0] | 外設突發傳輸配置 (Peripheral burst transfer configuration) 00:單次傳輸 01:INCR4(4 個節拍的增量突發傳輸) 10:INCR8(8 個節拍的增量突發傳輸) 11:INCR16(16 個節拍的增量突發傳輸) | 01b | DMA_PeripheralBurst_INC4 |
| PL[1:0] | 優先級 (Priority level) 00:低 01:中 10:高 11:非常高 | 11b | DMA_Priority_VeryHigh |
| MSIZE[1:0] | 存盤器資料大小 (Memory data size) 00:位元組(8 位) 01:半字(16 位) 10:字(32 位) 11:保留 | 10b | DMA_MemoryDataSize_Word |
| PSIZE[1:0] | 外設資料大小 (Peripheral data size) 00:位元組(8 位) 01:半字(16 位) 10:字(32 位) 11:保留 | 10b | DMA_MemoryDataSize_Word |
| MINC | 存盤器遞增模式 (Memory increment mode) 0:存盤器地址指標固定 1:每次資料傳輸后,存盤器地址指標遞增(增量為 MSIZE 值) | 1b | DMA_MemoryInc_Enable |
| PINC | 外設遞增模式 (Peripheral increment mode) 0:外設地址指標固定 1:每次資料傳輸后,外設地址指標遞增(增量為 PSIZE 值) | 0b | DMA_PeripheralInc_Disable |
| DIR[1:0] | 資料傳輸方向 (Data transfer direction) 00:外設到存盤器 01:存盤器到外設 10:存盤器到存盤器 | 00b | DMA_DIR_PeripheralToMemory |
| PFCTRL | 外設流控制器 (Peripheral flow controller) 0:DMA 是流控制器 1:外設是流控制器 | 0b | DMA_FlowCtrl_Peripheral |
| TCIE | 傳輸完成中斷使能 (Transfer complete interrupt enable) 0:禁止 TC 中斷 1:使能 TC 中斷 | 1b | DMA_IT_TC |
| EN | 資料流使能/讀作低電平時資料流就緒標志 (Stream enable / flag stream ready when read low) 0:禁止資料流 1:使能資料流 | 1b | DMA_SxCR_EN |

| 名稱 | 描述 | Value | 備注 |
| DMDIS | 直接模式禁止 (Direct mode disable) 0:使能直接模式 1:禁止直接模式 | 1b | DMA_FIFOMode_Enable |
| FTH[1:0] | FIFO 閾值選擇 (FIFO threshold selection) 00:FIFO 容量的 1/4 01:FIFO 容量的 1/2 10:FIFO 容量的 3/4 11:FIFO 完整容量 | 11b | DMA_FIFOThreshold_Full |

| 名稱 | 描述 | Value | 備注 |
| NDT[15:0] | 要傳輸的資料項數目 (Number of data items to transfer) 要傳輸的資料項數目(0 到 65535),只有在禁止資料流時,才能向此暫存器執行寫操作,使能資料流后,此暫存器為只讀,用于指示要傳輸的剩余資料項數,每次 DMA 傳輸后,此暫存器將遞減, | 1 |

| 名稱 | 描述 | Value | 備注 |
| PAR[31:0] | 外設地址 (Peripheral address) 讀/寫資料的外設資料暫存器的基址, | 0x40012C80 | SDIO_FIFO_ADDRESS: SDIO 資料 FIFO 暫存器 (SDIO_FIFO)的地址 |

| 名稱 | 描述 | Value | 備注 |
| M0A[31:0] | 存盤器 0 地址 (Memory 0 address) 讀/寫資料的存盤區 0 的基址, | * | BufferDST: 存放資料的記憶體地址 |
3.3 CMD16:SD_CMD_SET_BLOCKLEN
CMD16:SD_CMD_SET_BLOCKLEN該命令主要是作用是設定塊命令的長度,
#define SD_CMD_SET_BLOCKLEN ((uint8_t)16)
/*!< Set Block Size for Card */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
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);

發送命令CMD16的Argument是 block size,SD2.0協議規定了SDIO_HIGH_CAPACITY_SD_CARD的block size = 512Bytes,所以這里填寫的是0x200 (512),實際發送出去的波形如下:

然后SD卡處理完后,以R1的形式Response Card Status,通過CmdResp1Error檢測CMD是否正確回應,并且判斷Card Status是否存在錯誤,Receive的波形如下:

Card Status = 0x00000900對應的表格如下:

3.4 SDIO_DataConfig()
SDIO_DataConfig()函式主要的功能是配置傳輸資料的長度、傳輸超時、傳輸方向和傳輸模式等,涉及到的SDIO暫存器如下:
- SDIO 資料定時器暫存器 (SDIO_DTIMER)
- SDIO 資料長度暫存器 (SDIO_DLEN)
- SDIO 資料控制暫存器 (SDIO_DCTRL)
SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;
SDIO_DataInitStructure.SDIO_DataLength = NumberOfBlocks * BlockSize;
SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;
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);

| 名稱 | 描述 | Value | 備注 |
| DATATIME | 資料超時周期 (Data timeout period) 以卡總線時鐘周期表示的資料超時周期, | 0xFFFFFFFF | SD_DATATIMEOUT |

| 名稱 | 描述 | Value | 備注 |
| DATALENGTH | 資料長度值 (Data length value) 要傳輸的資料位元組數量, | 0xC800(100 * 512) | NumberOfBlocks * BlockSize |

| 名稱 | 描述 | Value | 備注 |
| DBLOCKSIZE | 資料塊大小 (Data block size) 0000:(十進制數 0)塊長度 = 20 = 1 位元組 0001:(十進制數 1)塊長度 = 21 = 2 位元組 0010:(十進制數 2)塊長度 = 22 = 4 位元組 0011:(十進制數 3)塊長度 = 23 = 8 位元組 0100:(十進制數 4)塊長度 = 24 = 16 位元組 0101:(十進制數 5)塊長度 = 25 = 32 位元組 0110:(十進制數 6)塊長度 = 26 = 64 位元組 0111:(十進制數 7)塊長度 = 27 = 128 位元組 1000:(十進制數 8)塊長度 = 28 = 256 位元組 1001:(十進制數 9)塊長度 = 29 = 512 位元組 1010:(十進制數 10)塊長度 = 210 = 1024 位元組 1011:(十進制數 11)塊長度 = 211 = 2048 位元組 1100:(十進制數 12)塊長度 = 212 = 4096 位元組 1101:(十進制數 13)塊長度 = 213 = 8192 位元組 1110:(十進制數 14)塊長度 = 214 = 16384 位元組 1111:(十進制數 15)保留 | 9 | 9 << 4 |
| DTMODE | 資料傳輸模式選擇 (Data transfer mode selection) 0:塊資料傳輸 1:流或 SDIO 多位元組資料傳輸 | 0 | SDIO_TransferMode_Block |
| DTDIR | 資料傳輸方向選擇 (Data transfer direction selection) 0:從控制器到卡, 1:從卡到控制器, | 0 | SDIO_TransferDir_ToSDIO |
| DTEN | 資料傳輸使能位 (Data transfer enabled bit) 如果 1 寫入到 DTEN 位,則資料傳輸開始, | 1 | SDIO_DPSM_Enable |
3.5 CMD18:SD_CMD_READ_MULT_BLOCK
CMD18:SD_CMD_READ_MULT_BLOCK該命令主要是作用是從指定地址連續從 SD 卡讀取資料塊,
#define SD_CMD_READ_MULT_BLOCK ((uint8_t)18)
/*!< Send CMD18 READ_MULT_BLOCK with argument data address */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_MULT_BLOCK;
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_READ_MULT_BLOCK);

發送命令CMD18的Argument是 start read data block address,ReadAddr被設定為0,實際發送出去的波形如下:

然后SD卡處理完后,以R1的形式Response Card Status,通過CmdResp1Error檢測CMD是否正確回應,并且判斷Card Status是否存在錯誤,Receive的波形如下:

3.6 SD_WaitReadOperation()
SD_WaitReadOperation()這個函式主要的功能是等待SDIO DMA資料傳輸完成,通過DMA中斷函式SD_ProcessDMAIRQ()來設定DMAEndOfTransfer標志,下面有介紹,
SD_Error SD_WaitReadOperation(void)
{
SD_Error errorstatus = SD_OK;
uint32_t timeout;
timeout = SD_DATATIMEOUT;
while ((DMAEndOfTransfer == 0x00) && (TransferEnd == 0) && (TransferError == SD_OK) && (timeout > 0))
{
timeout--;
}
DMAEndOfTransfer = 0x00;
timeout = SD_DATATIMEOUT;
while(((SDIO->STA & SDIO_FLAG_RXACT)) && (timeout > 0))
{
timeout--;
}
if (StopCondition == 1)
{
errorstatus = SD_StopTransfer();
StopCondition = 0;
}
...
}
SD_ProcessDMAIRQ()這個函式是DMA中斷函式,當SDIO DMA傳輸完成后會將DMAEndOfTransfer 設定為0x01,
void SD_ProcessDMAIRQ(void)
{
if(DMA2->LISR & SD_SDIO_DMA_FLAG_TCIF)
{
DMAEndOfTransfer = 0x01;
DMA_ClearFlag(SD_SDIO_DMA_STREAM, SD_SDIO_DMA_FLAG_TCIF|SD_SDIO_DMA_FLAG_FEIF);
}
}
在等待中,我們可以通過波形看到傳輸的資料都是0x00,說明SD_EraseTest()成功,

4.驗證測驗結果
測驗代碼如下:
static void SD_EraseTest(void)
{
printf("\r\n---->Erase test is starting...\r\n");
/*------------------- Block Erase ------------------------------------------*/
if (Status == SD_OK)
{
/* Erase NumberOfBlocks Blocks of WRITE_BL_LEN(512 Bytes) */
Status = SD_Erase(0x00, (BLOCK_SIZE * NUMBER_OF_BLOCKS));
}
if (Status == SD_OK)
{
Status = SD_ReadMultiBlocks(aBuffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
/* Check if the Transfer is finished */
Status = SD_WaitReadOperation();
/* Wait until end of DMA transfer */
while(SD_GetStatus() != SD_TRANSFER_OK);
}
/* Check the correctness of erased blocks */
if (Status == SD_OK)
{
EraseStatus = eBuffercmp(aBuffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);
}
if(EraseStatus == PASSED)
{
LED1(ON);
printf("\tThe earase is successful.\r\n");
}
else
{
LED1(OFF);
LED3(ON);
printf("\tThe earase is fail!!!\r\n");
}
printf("<----Erase test is end.\r\n");
}
驗證測驗結果成功:

5. 參考資料
SDIO參考的資料如下:

下載地址如下:
https://download.csdn.net/download/ZHONGCAI0901/14975835
移植成功的完整代碼下載地址如下:
https://download.csdn.net/download/ZHONGCAI0901/15265756
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/267437.html
標籤:其他
