<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

【GD32F470紫藤派開發板使用手冊】第十二講 SDIO-SD卡讀寫實驗

聚沃科技 ? 2024-05-18 09:36 ? 次閱讀
wKgaomYwSqiAY_PQAAnl063z3JE116.png

12.1實驗內容

通過本實驗主要學習以下內容:

  • SDIO操作原理
  • SD卡讀寫實現

12.2實驗原理

SD卡是一種主要以Nand Flash作為存儲介質,具有體積小、數據傳輸速度快以及支持熱插拔的優點。如今,已被廣泛應用于數碼相機、便攜式移動設備以及手機等多種設備中。SD卡的驅動一般有SPI接口或SDIO接口,本例程介紹使用GD32F4xx的SDIO接口驅動SD卡的實現。

12.2.1SD卡基礎知識

SD卡:secure digital memory card是一種安全存儲器件。屬性是快閃存儲器(flash eeprom),功能用來存儲數據。

wKgaomZIBOOAW0SvAAdIqgQyiAM171.png

SD卡雖然是薄薄的一片,但是它并不是一個整體,而是由大量的集成電路組成。SD卡的內部結構如下圖所示,主要由信號端子,接口控制器和存儲區組成。

wKgZomZIBO-Af-2eAANX9e0f8TQ689.png

SD卡主要有兩種模式,SD模式和SPI模式。不同模式下,接口定義不同。下面是SD卡的引腳。

wKgZomZIBPqAUdemAAEl4DiwNvo259.png

兩種模式的接口定義如下

wKgaomZIBQ2ANbo3AABUvvoNqj0000.png

SD模式中,主要由VCC(電源),VSS(GND),CLK(時鐘,由主控提供),CMD(命令),DAT0-3(數據輸入輸出),由6線制組成進行通信。SPI模式,主要采用4線制通信,除了電源地外,由MISO,MOSI,CLK,CS組成。下面簡單介紹SD模式的操作。

要驅動SD卡工作,主要涉及兩個步驟。第一個步驟是SD卡的識別過程。第二個步驟是對SD卡進行讀寫過程,即主機控制器和SD卡之間進行數據傳輸的過程。
要使SD卡能正常工作,一是要給SD卡供給穩定的電壓,二是要SD卡按用戶規定的方式工作。這兩項工作的實現,都是主機控制器通過給SD卡發送控制命令來實現的。
主機(SDIO控制器)要驅動SD卡工作,要使用許多的命令,包括應用層命令ACMD和 通用命令CMD.主機(SDIO控制器)把命令發送給SD卡,SD卡會作出回應,這里的回應叫做響應,響應命令分為6類,分別是R1、R1b、R2、R3、R6、R7。主機(SDIO控制器)給SD卡發送命令之后,SD卡會作出響應,響應中包含主機(SDIO控制器)需要的數據,這些數據有SD的信息,容量,和存儲數據等等。上面已經提到了,SD卡工作,主要是識別和數據傳輸,它的識別過程有些復雜,寫代碼的時候,可以參考協議給的初始化流程圖。數據傳輸包括讀和寫,單字節和多字節讀寫。下兩節描述識別初始化流程圖和數據讀寫時序圖。

1、讀寫數據的時序圖

SDIO與SD卡通信一般以數據塊的形式進行傳輸,SDIO(多)數據塊讀操作,如下圖所示。

wKgZomZIBROAPfxhAADJJJ3oGpU355.png

SDIO(多)數據塊寫操作,如下圖所示。

wKgZomZIBR6AYuTMAAD10Do1lh0487.png

2、命令格式
SDIO所有的命令和響應都是在SDIO_CMD引腳上面傳輸的,命令長度固定為48位,SDIO命令格式如下表所示。

wKgaomZIBSqAJfA6AAF9fE5Zsr8990.png

3、寄存器
SDIO控制器的寄存器,主要設置SDIO控制器和命令的索引參數。SD卡有5個寄存器CID,RCA,CSD,SCR.OCR。SD卡的信息從SD卡寄存器中獲取。

SD卡正常工作,就是根據SD卡初始化流程圖,發送命令,收到回復,直到流程結束。傳輸數據,也是根據讀寫時序圖,將要發送的數據放進命令中發送出去。

12.2.2SDIO模塊原理

SDIO為安全的數字輸入輸出接口,可以用于驅動SD卡、EMMC等,主要特征如下:

? MMC: 與多媒體卡系統規格書V4.2及之前的版本全兼容。有三種不同的數據總線模式:1位(默認)、4位和8位;
? SD卡: 與SD存儲卡規格版本2.0全兼容;
? SD I/O: 與SD I/O卡規格版本2.0全兼容,有兩種不同的數據總線模式:1位(默認)和4位;
? CE-ATA: 與CE-ATA數字協議版本1.1全兼容;
? 48MHz數據傳輸頻率和8位數據傳輸模式;
?中斷和DMA請求;
?完成信號使能和失能(CE-ATA)。

SDIO模塊結構框圖如下所示。主要包含兩大部分:SDIO適配器:由控制單元、命令單元和數據單元組成,控制單元管理時鐘信號,命令單元管理命令的傳輸,數據單元管理數據的傳輸;AHB接口:包括通過AHB總線訪問的寄存器、用于數據傳輸的FIFO單元以及產生中斷和DMA請求信號。

wKgaomZIBTaABdY_AAESRS7LgzA785.png

SDIO模塊可以實現對SD卡的完全驅動以及協議的實現,包括命令、響應等相關操作,本例程實現使用SDIO驅動SD卡初始化以及讀寫測試等相關操作,具體實現可以參考GD32F4xx用戶手冊以及代碼解析等。

12.3硬件設計

SD卡相關硬件電路如下圖所示,實驗板上具有SD卡卡座,信號線上有四根數據線,一根CMD命令線以及一根CLK時鐘線,所有信號線通過10K電阻進行上拉,電源地信號線具有10uf以及100nf電容,SD卡插入時,金屬接觸點朝下插入。

wKgaomZIBUGAXNK-AAHOxCpl4u8417.png

12.4代碼解析

12.4.1SDIO初始化配置函數

SDIO初始化配置在sd_io_init()函數中,其中包括sd_init()初始化、sd_card_information_get()SD卡信息獲取、sd_card_select_deselect()SD卡選擇、sd_cardstatus_get()SD卡狀態獲取、sd_bus_mode_config()SD卡總線寬度配置以及sd_transfer_mode_config()SD卡通信模式配置,歷程中選擇了4線查詢模式。

C
sd_error_enum sd_io_init(void)
{
sd_error_enum status = SD_OK;
uint32_t cardstate = 0;
status = sd_init();
if(SD_OK == status){
status = sd_card_information_get(&sd_cardinfo);
}
if(SD_OK == status){
status = sd_card_select_deselect(sd_cardinfo.card_rca);
}
status = sd_cardstatus_get(&cardstate);
if(cardstate & 0x02000000){
// printf("\r\n the card is locked!");
while (1){
}
}
if ((SD_OK == status) && (!(cardstate & 0x02000000)))
{
/* set bus mode */
status = sd_bus_mode_config(SDIO_BUSMODE_4BIT);
// status = sd_bus_mode_config( SDIO_BUSMODE_1BIT );
}
if (SD_OK == status)
{
/* set data transfer mode */
// status = sd_transfer_mode_config( SD_DMA_MODE );
status = sd_transfer_mode_config( SD_POLLING_MODE );
}
return status;
}

12.4.2獲取SD卡信息函數

獲取SD卡信息的函數如下所示,card_info_get()。

C
void card_info_get(void)
{
uint8_t sd_spec, sd_spec3, sd_spec4, sd_security;
uint32_t block_count, block_size;
uint16_t temp_ccc;
//printf("\r\n Card information:");
sd_spec = (sd_scr[1] & 0x0F000000) >> 24;
sd_spec3 = (sd_scr[1] & 0x00008000) >> 15;
sd_spec4 = (sd_scr[1] & 0x00000400) >> 10;
if(2 == sd_spec)
{
if(1 == sd_spec3)
{
if(1 == sd_spec4)
{
// printf("\r\n## Card version 4.xx ##");
}
else
{
// printf("\r\n## Card version 3.0x ##");
}
}
else
{
// printf("\r\n## Card version 2.00 ##");
}
}
else if(1 == sd_spec)
{
// printf("\r\n## Card version 1.10 ##");
}
else if(0 == sd_spec)
{
// printf("\r\n## Card version 1.0x ##");
}

sd_security = (sd_scr[1] & 0x00700000) >> 20;
if(2 == sd_security)
{
// printf("\r\n## SDSC card ##");
}
else if(3 == sd_security)
{
// printf("\r\n## SDHC card ##");
}
else if(4 == sd_security)
{
// printf("\r\n## SDXC card ##");
}

block_count = (sd_cardinfo.card_csd.c_size + 1)*1024;
block_size = 512;
// printf("\r\n## Device size is %dKB ##", sd_card_capacity_get());
// printf("\r\n## Block size is %dB ##", block_size);
// printf("\r\n## Block count is %d ##", block_count);

if(sd_cardinfo.card_csd.read_bl_partial){
// printf("\r\n## Partial blocks for read allowed ##" );
}
if(sd_cardinfo.card_csd.write_bl_partial){
// printf("\r\n## Partial blocks for write allowed ##" );
}
temp_ccc = sd_cardinfo.card_csd.ccc;
//printf("\r\n## CardCommandClasses is: %x ##", temp_ccc);
if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc)){
// printf("\r\n## Block operation supported ##");
}
if(SD_CCC_ERASE & temp_ccc){
// printf("\r\n## Erase supported ##");
}
if(SD_CCC_WRITE_PROTECTION & temp_ccc){
// printf("\r\n## Write protection supported ##");
}
if(SD_CCC_LOCK_CARD & temp_ccc){
// printf("\r\n## Lock unlock supported ##");
}
if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc){
// printf("\r\n## Application specific supported ##");
}
if(SD_CCC_IO_MODE & temp_ccc){
// printf("\r\n## I/O mode supported ##");
}
if(SD_CCC_SWITCH & temp_ccc){
// printf("\r\n## Switch function supported ##");
}
}

12.4.3SD卡數據塊寫入函數

SD卡數據塊寫入函數如下所示,通過該函數可實現SD卡數據塊的數據寫入。

C
sd_error_enum sd_block_write(uint32_t *pwritebuffer, uint32_t writeaddr, uint16_t blocksize)
{
/* initialize the variables */
sd_error_enum status = SD_OK;
uint8_t cardstate = 0;
uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = pwritebuffer;
uint32_t transbytes = 0, restwords = 0, response = 0;
__IO uint32_t timeout = 0;

if(NULL == pwritebuffer){
status = SD_PARAMETER_INVALID;
return status;
}

transerror = SD_OK;
transend = 0;
totalnumber_bytes = 0;
/* clear all DSM configuration */
sdio_data_config(0, 0, SDIO_DATABLOCKSIZE_1BYTE);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
sdio_dsm_disable();
sdio_dma_disable();

/* check whether the card is locked */
if(sdio_response_get(SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED){
status = SD_LOCK_UNLOCK_FAILED;
return status;
}

/* blocksize is fixed in 512B for SDHC card */
if(SDIO_HIGH_CAPACITY_SD_CARD == cardtype){
blocksize = 512;
writeaddr /= 512;
}

align = blocksize & (blocksize - 1);
if((blocksize > 0) && (blocksize <= 2048) && (0 == align)){
datablksize = sd_datablocksize_get(blocksize);
/* send CMD16(SET_BLOCKLEN) to set the block length */
sdio_command_response_config(SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();

/* check if some error occurs */
status = r1_error_check(SD_CMD_SET_BLOCKLEN);
if(SD_OK != status){
return status;
}
}else{
status = SD_PARAMETER_INVALID;
return status;
}

/* send CMD13(SEND_STATUS), addressed card sends its status registers */
sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_SEND_STATUS);
if(SD_OK != status){
return status;
}

response = sdio_response_get(SDIO_RESPONSE0);
timeout = 100000;

while((0 == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0)){
/* continue to send CMD13 to polling the state of card until buffer empty or timeout */
--timeout;
/* send CMD13(SEND_STATUS), addressed card sends its status registers */
sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_SEND_STATUS);
if(SD_OK != status){
return status;
}
response = sdio_response_get(SDIO_RESPONSE0);
}
if(0 == timeout){
return SD_ERROR;
}

/* send CMD24(WRITE_BLOCK) to write a block */
sdio_command_response_config(SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_WRITE_BLOCK);
if(SD_OK != status){
return status;
}

stopcondition = 0;
totalnumber_bytes = blocksize;

/* configure the SDIO data transmission */
sdio_data_config(SD_DATATIMEOUT, totalnumber_bytes, datablksize);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
sdio_dsm_enable();

if(SD_POLLING_MODE == transmode){
/* polling mode */
while(!sdio_flag_get(SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_TXURE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_STBITE)){
if(RESET != sdio_flag_get(SDIO_FLAG_TFH)){
/* at least 8 words can be written into the FIFO */
if((totalnumber_bytes - transbytes) < SD_FIFOHALF_BYTES){
restwords = (totalnumber_bytes - transbytes)/4 + (((totalnumber_bytes - transbytes)%4 == 0) ? 0 : 1);
for(count = 0; count < restwords; count++){
sdio_data_write(*ptempbuff);
++ptempbuff;
transbytes += 4;
}
}else{
for(count = 0; count < SD_FIFOHALF_WORDS; count++){
sdio_data_write(*(ptempbuff + count));
}
/* 8 words(32 bytes) has been transferred */
ptempbuff += SD_FIFOHALF_WORDS;
transbytes += SD_FIFOHALF_BYTES;
}
}
}

/* whether some error occurs and return it */
if(RESET != sdio_flag_get(SDIO_FLAG_DTCRCERR)){
status = SD_DATA_CRC_ERROR;
sdio_flag_clear(SDIO_FLAG_DTCRCERR);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_DTTMOUT)){
status = SD_DATA_TIMEOUT;
sdio_flag_clear(SDIO_FLAG_DTTMOUT);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_TXURE)){
status = SD_TX_UNDERRUN_ERROR;
sdio_flag_clear(SDIO_FLAG_TXURE);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_STBITE)){
status = SD_START_BIT_ERROR;
sdio_flag_clear(SDIO_FLAG_STBITE);
return status;
}
}else if(SD_DMA_MODE == transmode){
/* DMA mode */
/* enable the SDIO corresponding interrupts and DMA */
sdio_interrupt_enable(SDIO_INT_DTCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_TXURE | SDIO_INT_DTEND | SDIO_INT_STBITE);
dma_transfer_config(pwritebuffer, blocksize);
sdio_dma_enable();

timeout = 100000;
while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)){
timeout--;
if(0 == timeout){
return SD_ERROR;
}
}
while ((0 == transend) && (SD_OK == transerror)){
}

if(SD_OK != transerror){
return transerror;
}
}else{
status = SD_PARAMETER_INVALID;
return status;
}

/* clear the SDIO_INTC flags */
sdio_flag_clear(SDIO_MASK_INTC_FLAGS);
/* get the card state and wait the card is out of programming and receiving state */
status = sd_card_state_get(&cardstate);
while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))){
status = sd_card_state_get(&cardstate);
}
return status;
}

12.4.4SD卡數據塊讀取函數

SD卡數據塊讀取函數如下所示。

C
sd_error_enum sd_block_read(uint32_t *preadbuffer, uint32_t readaddr, uint16_t blocksize)
{
/* initialize the variables */
sd_error_enum status = SD_OK;
uint32_t count = 0, align = 0, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = preadbuffer;
__IO uint32_t timeout = 0;

if(NULL == preadbuffer){
status = SD_PARAMETER_INVALID;
return status;
}

transerror = SD_OK;
transend = 0;
totalnumber_bytes = 0;
/* clear all DSM configuration */
sdio_data_config(0, 0, SDIO_DATABLOCKSIZE_1BYTE);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
sdio_dsm_disable();
sdio_dma_disable();

/* check whether the card is locked */
if(sdio_response_get(SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED){
status = SD_LOCK_UNLOCK_FAILED;
return status;
}

/* blocksize is fixed in 512B for SDHC card */
if(SDIO_HIGH_CAPACITY_SD_CARD == cardtype){
blocksize = 512;
readaddr /= 512;
}

align = blocksize & (blocksize - 1);
if((blocksize > 0) && (blocksize <= 2048) && (0 == align)){
datablksize = sd_datablocksize_get(blocksize);
/* send CMD16(SET_BLOCKLEN) to set the block length */
sdio_command_response_config(SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();

/* check if some error occurs */
status = r1_error_check(SD_CMD_SET_BLOCKLEN);
if(SD_OK != status){
return status;
}
}else{
status = SD_PARAMETER_INVALID;
return status;
}

stopcondition = 0;
totalnumber_bytes = blocksize;

/* configure SDIO data transmission */
sdio_data_config(SD_DATATIMEOUT, totalnumber_bytes, datablksize);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOSDIO);
sdio_dsm_enable();

/* send CMD17(READ_SINGLE_BLOCK) to read a block */
sdio_command_response_config(SD_CMD_READ_SINGLE_BLOCK, (uint32_t)readaddr, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_READ_SINGLE_BLOCK);
if(SD_OK != status){
return status;
}

if(SD_POLLING_MODE == transmode){
/* polling mode */
while(!sdio_flag_get(SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_RXORE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_STBITE)){
if(RESET != sdio_flag_get(SDIO_FLAG_RFH)){
/* at least 8 words can be read in the FIFO */
for(count = 0; count < SD_FIFOHALF_WORDS; count++){
*(ptempbuff + count) = sdio_data_read();
}
ptempbuff += SD_FIFOHALF_WORDS;
}
}

/* whether some error occurs and return it */
if(RESET != sdio_flag_get(SDIO_FLAG_DTCRCERR)){
status = SD_DATA_CRC_ERROR;
sdio_flag_clear(SDIO_FLAG_DTCRCERR);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_DTTMOUT)){
status = SD_DATA_TIMEOUT;
sdio_flag_clear(SDIO_FLAG_DTTMOUT);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_RXORE)){
status = SD_RX_OVERRUN_ERROR;
sdio_flag_clear(SDIO_FLAG_RXORE);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_STBITE)){
status = SD_START_BIT_ERROR;
sdio_flag_clear(SDIO_FLAG_STBITE);
return status;
}
while(RESET != sdio_flag_get(SDIO_FLAG_RXDTVAL)){
*ptempbuff = sdio_data_read();
++ptempbuff;
}
/* clear the SDIO_INTC flags */
sdio_flag_clear(SDIO_MASK_INTC_FLAGS);
}else if(SD_DMA_MODE == transmode){
/* DMA mode */
/* enable the SDIO corresponding interrupts and DMA function */
sdio_interrupt_enable(SDIO_INT_CCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_RXORE | SDIO_INT_DTEND | SDIO_INT_STBITE);
sdio_dma_enable();
dma_receive_config(preadbuffer, blocksize);
timeout = 100000;
while((RESET == dma_flag_get(DMA1, DMA_CH3, DMA_FLAG_FTF)) && (timeout > 0)){
timeout--;
if(0 == timeout){
return SD_ERROR;
}
}
}else{
status = SD_PARAMETER_INVALID;
}
return status;
}

12.4.5SD卡lock和unlock配置函數

SD卡lock和unlock配置函數如下所示。通過形參實現對SD卡的lock和unlock,若希望lock SD卡,lcokstate配置為SD_LOCK;若希望unlock SD卡,lockstate配置為SD_UNLOCK.

C
sd_error_enum sd_lock_unlock(uint8_t lockstate)
{
sd_error_enum status = SD_OK;
uint8_t cardstate = 0, tempbyte = 0;
uint32_t pwd1 = 0, pwd2 = 0, response = 0;
__IO uint32_t timeout = 0;
uint16_t tempccc = 0;

/* get the card command classes from CSD */
tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_24_31BITS) >> 24);
tempccc = (uint16_t)((uint16_t)tempbyte << 4);
tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_16_23BITS) >> 16);
tempccc |= (uint16_t)((uint16_t)(tempbyte & 0xF0) >> 4);

if(0 == (tempccc & SD_CCC_LOCK_CARD)){
/* don't support the lock command */
status = SD_FUNCTION_UNSUPPORTED;
return status;
}
/* password pattern */
pwd1 = (0x01020600|lockstate);
pwd2 = 0x03040506;

/* clear all DSM configuration */
sdio_data_config(0, 0, SDIO_DATABLOCKSIZE_1BYTE);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
sdio_dsm_disable();
sdio_dma_disable();

/* send CMD16(SET_BLOCKLEN) to set the block length */
sdio_command_response_config(SD_CMD_SET_BLOCKLEN, (uint32_t)8, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_SET_BLOCKLEN);
if(SD_OK != status){
return status;
}

/* send CMD13(SEND_STATUS), addressed card sends its status register */
sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_SEND_STATUS);
if(SD_OK != status){
return status;
}

response = sdio_response_get(SDIO_RESPONSE0);
timeout = 100000;
while((0 == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0)){
/* continue to send CMD13 to polling the state of card until buffer empty or timeout */
--timeout;
/* send CMD13(SEND_STATUS), addressed card sends its status registers */
sdio_command_response_config(SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_SEND_STATUS);
if(SD_OK != status){
return status;
}
response = sdio_response_get(SDIO_RESPONSE0);
}
if(0 == timeout){
return SD_ERROR;
}

/* send CMD42(LOCK_UNLOCK) to set/reset the password or lock/unlock the card */
sdio_command_response_config(SD_CMD_LOCK_UNLOCK, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_LOCK_UNLOCK);
if(SD_OK != status){
return status;
}

response = sdio_response_get(SDIO_RESPONSE0);

/* configure the SDIO data transmission */
sdio_data_config(SD_DATATIMEOUT, (uint32_t)8, SDIO_DATABLOCKSIZE_8BYTES);
sdio_data_transfer_config(SDIO_TRANSMODE_BLOCK, SDIO_TRANSDIRECTION_TOCARD);
sdio_dsm_enable();

/* write password pattern */
sdio_data_write(pwd1);
sdio_data_write(pwd2);

/* whether some error occurs and return it */
if(RESET != sdio_flag_get(SDIO_FLAG_DTCRCERR)){
status = SD_DATA_CRC_ERROR;
sdio_flag_clear(SDIO_FLAG_DTCRCERR);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_DTTMOUT)){
status = SD_DATA_TIMEOUT;
sdio_flag_clear(SDIO_FLAG_DTTMOUT);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_TXURE)){
status = SD_TX_UNDERRUN_ERROR;
sdio_flag_clear(SDIO_FLAG_TXURE);
return status;
}else if(RESET != sdio_flag_get(SDIO_FLAG_STBITE)){
status = SD_START_BIT_ERROR;
sdio_flag_clear(SDIO_FLAG_STBITE);
return status;
}

/* clear the SDIO_INTC flags */
sdio_flag_clear(SDIO_MASK_INTC_FLAGS);
/* get the card state and wait the card is out of programming and receiving state */
status = sd_card_state_get(&cardstate);
while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))){
status = sd_card_state_get(&cardstate);
}
return status;
}

12.4.6SD卡erase擦除操作函數

SD卡擦除操作函數如下,其形參為擦除起始地址以及結束地址。

C
sd_error_enum sd_erase(uint32_t startaddr, uint32_t endaddr)
{
/* initialize the variables */
sd_error_enum status = SD_OK;
uint32_t count = 0, clkdiv = 0;
__IO uint32_t delay = 0;
uint8_t cardstate = 0, tempbyte = 0;
uint16_t tempccc = 0;

/* get the card command classes from CSD */
tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_24_31BITS) >> 24);
tempccc = (uint16_t)((uint16_t)tempbyte << 4);
tempbyte = (uint8_t)((sd_csd[1] & SD_MASK_16_23BITS) >> 16);
tempccc |= (uint16_t)((uint16_t)(tempbyte & 0xF0) >> 4);
if(0 == (tempccc & SD_CCC_ERASE)){
/* don't support the erase command */
status = SD_FUNCTION_UNSUPPORTED;
return status;
}
clkdiv = (SDIO_CLKCTL & SDIO_CLKCTL_DIV);
clkdiv += ((SDIO_CLKCTL & SDIO_CLKCTL_DIV8)>>31)*256;
clkdiv += 2;
delay = 120000 / clkdiv;

/* check whether the card is locked */
if (sdio_response_get(SDIO_RESPONSE0) & SD_CARDSTATE_LOCKED){
status = SD_LOCK_UNLOCK_FAILED;
return(status);
}

/* blocksize is fixed in 512B for SDHC card */
if (SDIO_HIGH_CAPACITY_SD_CARD == cardtype){
startaddr /= 512;
endaddr /= 512;
}

if((SDIO_STD_CAPACITY_SD_CARD_V1_1 == cardtype) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == cardtype) ||
(SDIO_HIGH_CAPACITY_SD_CARD == cardtype)){
/* send CMD32(ERASE_WR_BLK_START) to set the address of the first write block to be erased */
sdio_command_response_config(SD_CMD_ERASE_WR_BLK_START, startaddr, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_ERASE_WR_BLK_START);
if(SD_OK != status){
return status;
}

/* send CMD33(ERASE_WR_BLK_END) to set the address of the last write block of the continuous range to be erased */
sdio_command_response_config(SD_CMD_ERASE_WR_BLK_END, endaddr, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_ERASE_WR_BLK_END);
if(SD_OK != status){
return status;
}
}

/* send CMD38(ERASE) to set the address of the first write block to be erased */
sdio_command_response_config(SD_CMD_ERASE, (uint32_t)0x0, SDIO_RESPONSETYPE_SHORT);
sdio_wait_type_set(SDIO_WAITTYPE_NO);
sdio_csm_enable();
/* check if some error occurs */
status = r1_error_check(SD_CMD_ERASE);
if(SD_OK != status){
return status;
}
/* loop until the counter is reach to the calculated time */
for(count = 0; count < delay; count++){
}
/* get the card state and wait the card is out of programming and receiving state */
status = sd_card_state_get(&cardstate);
while((SD_OK == status) && ((SD_CARDSTATE_PROGRAMMING == cardstate) || (SD_CARDSTATE_RECEIVING == cardstate))){
status = sd_card_state_get(&cardstate);
}
return status;
}

12.4.7主函數

SD卡主函數如下,可實現對SD卡的擦寫讀以及加鎖解鎖操作。

C
int main(void)
{
sd_error_enum sd_error;
uint16_t i = 5;
#ifdef DATA_PRINT
uint8_t *pdata;
#endif /* DATA_PRINT */

/* configure the NVIC, USART and LED */
nvic_config();

driver_init();

bsp_uart_init(&BOARD_UART);

/* initialize the card */
do{
sd_error = sd_io_init();
}while((SD_OK != sd_error) && (--i));

if(i){
printf_log("\r\n Card init success!\r\n");
}else{
printf_log("\r\n Card init failed!\r\n");
while (1){
}
}

/* get the information of the card and print it out by USART */
card_info_get();

/* init the write buffer */
for(i=0; i<512; i++){
buf_write[i] = i;
}

printf_log("\r\n\r\n Card test:");

/* single block operation test */
sd_error = sd_block_write(buf_write, 100*512, 512);
if(SD_OK != sd_error){

printf_log("\r\n Block write fail!");
while (1){
}
}else{
printf_log("\r\n Block write success!");
}
sd_error = sd_block_read(buf_read, 100*512, 512);
if(SD_OK != sd_error){
printf_log("\r\n Block read fail!");

while (1){
}
}else{
//printf_log("\r\n Block read success!");
#ifdef DATA_PRINT
pdata = (uint8_t *)buf_read;
/* print data by USART */
printf_log("\r\n");
for(i = 0; i < 128; i++){
printf_log(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
pdata += 4;
if(0 == (i + 1) % 4){
printf_log("\r\n");
}
}
#endif /* DATA_PRINT */
}

/* lock and unlock operation test */
if(SD_CCC_LOCK_CARD & sd_cardinfo.card_csd.ccc){
/* lock the card */
sd_error = sd_lock_unlock(SD_LOCK);
if(SD_OK != sd_error){
printf_log("\r\n Lock failed!");
while (1){
}
}else{
printf_log("\r\n The card is locked!");
}
sd_error = sd_erase(100*512, 101*512);
if(SD_OK != sd_error){
printf_log("\r\n Erase failed!");
}else{
__NOP();
printf_log("\r\n Erase success!");
}

/* unlock the card */
sd_error = sd_lock_unlock(SD_UNLOCK);
if(SD_OK != sd_error){
printf_log("\r\n Unlock failed!");
while (1){
}
}else{
printf_log("\r\n The card is unlocked!");
}
sd_error = sd_erase(100*512, 101*512);
if(SD_OK != sd_error){
printf_log("\r\n Erase failed!");
}else{
printf_log("\r\n Erase success!");
}

sd_error = sd_block_read(buf_read, 100*512, 512);
if(SD_OK != sd_error){
printf_log("\r\n Block read fail!");
while (1){
}
}else{
printf_log("\r\n Block read success!");
#ifdef DATA_PRINT
pdata = (uint8_t *)buf_read;
/* print data by USART */
printf_log("\r\n");
for(i = 0; i < 128; i++){
printf_log(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
pdata += 4;
if(0 == (i + 1) % 4){
printf_log("\r\n");
}
}
#endif /* DATA_PRINT */
}
}

/* multiple blocks operation test */
sd_error = sd_multiblocks_write(buf_write, 200*512, 512, 3);
if(SD_OK != sd_error){
printf_log("\r\n Multiple block write fail!");
while (1){
}
}else{
printf_log("\r\n Multiple block write success!");
}
sd_error = sd_multiblocks_read(buf_read, 200*512, 512, 3);
if(SD_OK != sd_error){
printf_log("\r\n Multiple block read fail!");

while (1){
}
}else{
printf_log("\r\n Multiple block read success!");
#ifdef DATA_PRINT
pdata = (uint8_t *)buf_read;
/* print data by USART */
printf_log("\r\n");
for(i = 0; i < 512; i++){
printf_log(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3));
pdata += 4;
if(0 == (i + 1) % 4){
printf_log("\r\n");
}
}
#endif /* DATA_PRINT */
}

while (1){
}
}

12.5實驗結果

將SD卡讀寫實驗例程燒錄到紫藤派開發板中,并在卡槽中插入SD卡,在液晶屏上,將會觀察到SD卡相關操作結果。

wKgZomZIBdGAId3KACPZCp4SNRM111.png

教程GD32 MCU方案商聚沃科技原創發布,了解更多GD32 MCU教程,關注聚沃科技官網

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6008

    文章

    44087

    瀏覽量

    623172
  • SD卡
    +關注

    關注

    2

    文章

    542

    瀏覽量

    63145
  • 開發板
    +關注

    關注

    25

    文章

    4560

    瀏覽量

    94924
  • SDIO
    +關注

    關注

    2

    文章

    62

    瀏覽量

    19195
  • GD32
    +關注

    關注

    7

    文章

    357

    瀏覽量

    23797
收藏 人收藏

    評論

    相關推薦

    GD32F470紫藤開發板使用手冊】第九講 USART-printf打印實驗

    通過本實驗主要學習以下內容: 串口簡介 GD32F470串口工作原理 使用printf打印信息
    的頭像 發表于 05-13 10:14 ?722次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b>派<b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第九講  USART-printf打印<b class='flag-5'>實驗</b>

    GD32F470紫藤開發板使用手冊第十一講 SPI-SPI NOR FLASH讀寫實驗

    通過本實驗主要學習以下內容: ?SPI簡介 ?GD32F470 SPI簡介 ?SPI NOR FLASH——GD25Q32ESIGR簡介 ?使用GD32F470 SPI接口實現對
    的頭像 發表于 05-17 09:57 ?749次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b>派<b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第十</b>一講 SPI-SPI NOR FLASH<b class='flag-5'>讀寫實驗</b>

    GD32H757Z海棠派開發板使用手冊第十三講 SDIO-SD讀寫實驗

    通過本實驗主要學習以下內容: ?USB協議基本原理 ?GD32H7xx USBHS的使用 ?虛擬鍵盤的協議原理及使用
    的頭像 發表于 06-06 11:26 ?668次閱讀
    【<b class='flag-5'>GD</b>32H757Z海棠派<b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第十</b>三講 <b class='flag-5'>SDIO-SD</b>卡<b class='flag-5'>讀寫實驗</b>

    使用GD32F470編譯drv_adc.c時報錯怎么解決?

    使用GD32F470芯片,編譯drv_adc.c時報錯好幾個編譯錯誤,可能是適配GD32F470芯片沒有適配好。 編譯問題如下圖:
    發表于 02-23 06:55

    這是DE2開發板使用手冊

    DE2開發板使用手冊,有興趣的人可以下載看一下
    發表于 06-03 17:58

    QC-CPLD開發板快速使用手冊

    `QC-CPLD開發板快速使用手冊.pdf`
    發表于 10-06 08:11

    FPGA開發板快速使用手冊

    QC-FPGA-C1開發板快速使用手冊.pdf感興趣的可以看看0
    發表于 10-07 09:24

    眾想科技-劉洋邊講邊寫STM32視頻教程 15.RS232串口通訊實驗

    彩色液晶屏顯示漢字、英文、數字 買免費 第二十一講 SD存儲工作原理 買免費 第二十二
    發表于 10-12 11:16

    【HAL庫每天一例】第043例: SDIO-SD讀寫

    /1i574oPv 密碼:r3s3(硬石YS-F1Pro開發板HAL庫例程持續更新\1. 軟件設計之基本裸機例程(HAL庫版本)YSF1_HAL-043. SDIO-SD
    發表于 06-17 08:54

    【星空GD32F303開發板試用體驗】文件讀寫與數碼相框的實現 (兼結題報告)

    本帖最后由 jinglixixi 于 2021-11-27 01:23 編輯 星空開發板是旗點科技推出的一款以GD32F303ZET6為核心的開發板,該
    發表于 11-26 12:05

    迅為iMX6ULL開發板使用手冊資料下載

    的知識點,它都有!《嵌入式Linux開發指南》+《開發板使用手冊》+《裸機使用手冊》鏈接:https://pan.baidu.com/s/1Xat4C-cDa2Gi1UwNckNRTw
    發表于 12-02 14:13

    星空GD32F303開發板的相關資料下載

    一、開發板介紹星空GD開發板是由旗點科技推出的一款GD32開發板,板載
    發表于 12-10 08:27

    現有的BSP工程可以直接在GD32F470上進行開發

    大家好:有關于GD32F470的BSP工程的問題咨詢,我在GD官網上查照資料了解470和450是很相似的,目前因為項目需要使用的470芯片,想使用rt-thread的操作系統,但是不知
    發表于 08-01 10:39

    YL-51開發板使用手冊

    YL-51開發板使用手冊,YL-51開發板使用手冊YL-51開發板使用手冊YL-51
    發表于 05-10 16:31 ?18次下載

    GD32F470紫藤開發板使用手冊】第八講 ADC-規則組多通道采樣實驗

    通過本實驗主要學習以下內容: ?ADC的簡介 ?GD32F470 ADC工作原理 ?DMA原理 ?規則組多通道循環采樣
    的頭像 發表于 05-12 10:00 ?178次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b>派<b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】第八講 ADC-規則組多通道采樣<b class='flag-5'>實驗</b>
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>