23.1實驗內容
通過本實驗主要學習以下內容:
23.2實驗原理
SD卡是一種主要以Nand Flash作為存儲介質,具有體積小、數據傳輸速度快以及支持熱插拔的優點。如今,已被廣泛應用于數碼相機、便攜式移動設備以及手機等多種設備中。SD卡的驅動一般有SPI接口或SDIO接口,本例程介紹使用GD32F303的SDIO接口驅動SD卡的實現。
23.2.1SD卡基礎知識
SD卡:secure digital memory card是一種安全存儲器件。屬性是快閃存儲器(flash eeprom),功能用來存儲數據。
![wKgaomZIBOOAW0SvAAdIqgQyiAM171.png](https://file1.elecfans.com/web2/M00/E7/85/wKgaomZIBOOAW0SvAAdIqgQyiAM171.png)
SD卡雖然是薄薄的一片,但是它并不是一個整體,而是由大量的集成電路組成。SD卡的內部結構如下圖所示,主要由信號端子,接口控制器和存儲區組成。
![wKgZomZIBO-Af-2eAANX9e0f8TQ689.png](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBO-Af-2eAANX9e0f8TQ689.png)
SD卡主要有兩種模式,SD模式和SPI模式。不同模式下,接口定義不同。下面是SD卡的引腳。
![wKgZomZIBPqAUdemAAEl4DiwNvo259.png](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBPqAUdemAAEl4DiwNvo259.png)
兩種模式的接口定義如下
![wKgaomZIBQ2ANbo3AABUvvoNqj0000.png](https://file1.elecfans.com/web2/M00/E7/85/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](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBROAPfxhAADJJJ3oGpU355.png)
SDIO(多)數據塊寫操作,如下圖所示。
![wKgZomZIBR6AYuTMAAD10Do1lh0487.png](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBR6AYuTMAAD10Do1lh0487.png)
2、命令格式
SDIO所有的命令和響應都是在SDIO_CMD引腳上面傳輸的,命令長度固定為48位,SDIO命令格式如下表所示。
![wKgaomZIBSqAJfA6AAF9fE5Zsr8990.png](https://file1.elecfans.com/web2/M00/E7/85/wKgaomZIBSqAJfA6AAF9fE5Zsr8990.png)
3、寄存器
SDIO控制器的寄存器,主要設置SDIO控制器和命令的索引與參數。SD卡有5個寄存器CID,RCA,CSD,SCR.OCR。SD卡的信息從SD卡寄存器中獲取。
SD卡正常工作,就是根據SD卡初始化流程圖,發送命令,收到回復,直到流程結束。傳輸數據,也是根據讀寫時序圖,將要發送的數據放進命令中發送出去。
23.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](https://file1.elecfans.com/web2/M00/E7/85/wKgaomZIBTaABdY_AAESRS7LgzA785.png)
SDIO模塊可以實現對SD卡的完全驅動以及協議的實現,包括命令、響應等相關操作,本例程實現使用SDIO驅動SD卡初始化以及讀寫測試等相關操作,具體實現可以參考GD32F303用戶手冊以及代碼解析等。
23.3硬件設計
SD卡相關硬件電路如下圖所示,實驗板上具有SD卡卡座,信號線上有四根數據線,一根CMD命令線以及一根CLK時鐘線,所有信號線通過10K電阻進行上拉,電源地信號線具有10uf以及100nf電容,SD卡插入時,金屬接觸點朝下插入。
![wKgZomZ3jEOAN55jAAHxfCvJUGI690.png](https://file1.elecfans.com/web2/M00/F2/28/wKgZomZ3jEOAN55jAAHxfCvJUGI690.png)
23.4代碼解析
23.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; } |
23.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 ##"); } } |
23.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; } |
23.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; } |
23.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; } |
23.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; } |
23.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(); bsp_uart_init(&BOARD_UART); /* initialize the card */ do{ sd_error = sd_io_init(); }while((SD_OK != sd_error) && (--i)); if(i){ printf("\r\n Card init success!\r\n"); }else{ printf("\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("\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("\r\n Block write fail!"); while (1){ } }else{ printf("\r\n Block write success!"); } sd_error = sd_block_read(buf_read, 100*512, 512); if(SD_OK != sd_error){ printf("\r\n Block read fail!"); while (1){ } }else{ //printf("\r\n Block read success!"); #ifdef DATA_PRINT pdata = (uint8_t *)buf_read; /* print data by USART */ printf("\r\n"); for(i = 0; i < 128; i++){ printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); pdata += 4; if(0 == (i + 1) % 4){ printf("\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("\r\n Lock failed!"); while (1){ } }else{ printf("\r\n The card is locked!"); } sd_error = sd_erase(100*512, 101*512); if(SD_OK != sd_error){ printf("\r\n Erase failed!"); }else{ __NOP(); printf("\r\n Erase success!"); } /* unlock the card */ sd_error = sd_lock_unlock(SD_UNLOCK); if(SD_OK != sd_error){ printf("\r\n Unlock failed!"); while (1){ } }else{ printf("\r\n The card is unlocked!"); } sd_error = sd_erase(100*512, 101*512); if(SD_OK != sd_error){ printf("\r\n Erase failed!"); }else{ printf("\r\n Erase success!"); } sd_error = sd_block_read(buf_read, 100*512, 512); if(SD_OK != sd_error){ printf("\r\n Block read fail!"); while (1){ } }else{ printf("\r\n Block read success!"); #ifdef DATA_PRINT pdata = (uint8_t *)buf_read; /* print data by USART */ printf("\r\n"); for(i = 0; i < 128; i++){ printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); pdata += 4; if(0 == (i + 1) % 4){ printf("\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("\r\n Multiple block write fail!"); while (1){ } }else{ printf("\r\n Multiple block write success!"); } sd_error = sd_multiblocks_read(buf_read, 200*512, 512, 3); if(SD_OK != sd_error){ printf("\r\n Multiple block read fail!"); while (1){ } }else{ printf("\r\n Multiple block read success!"); #ifdef DATA_PRINT pdata = (uint8_t *)buf_read; /* print data by USART */ printf("\r\n"); for(i = 0; i < 512; i++){ printf(" %3d %3d %3d %3d ", *pdata, *(pdata+1), *(pdata+2), *(pdata+3)); pdata += 4; if(0 == (i + 1) % 4){ printf("\r\n"); } } #endif /* DATA_PRINT */ } while (1){ } } |
23.5實驗結果
將SD卡讀寫實驗例程燒錄到紅楓派開發板中,并在卡槽中插入SD卡,打開對應串口復位芯片,將會觀察到SD卡相關操作結果。
![wKgZomZ3jNmAanvFAACpvj8BAmQ928.png](https://file1.elecfans.com/web2/M00/F2/28/wKgZomZ3jNmAanvFAACpvj8BAmQ928.png)
-
單片機
+關注
關注
6043文章
44622瀏覽量
638518 -
mcu
+關注
關注
146文章
17317瀏覽量
352630 -
SD卡
+關注
關注
2文章
566瀏覽量
64107 -
開發板
+關注
關注
25文章
5121瀏覽量
98189
發布評論請先 登錄
相關推薦
【星空派GD32F303開發板試用體驗】開箱+環境搭建
【星空派GD32F303開發板試用體驗】開箱+環境搭建
【星空派GD32F303開發板試用體驗】+板卡概覽
【星空派GD32F303開發板試用體驗】文件讀寫與數碼相框的實現 (兼結題報告)
第二十三講 異步計數器
![<b class='flag-5'>第二十三講</b> 異步計數器](https://file1.elecfans.com//web2/M00/A4/AE/wKgZomUMNUKAQczOAAAM_AEmfRU869.gif)
【正點原子FPGA連載】第二十三章RGB-LCD字符和圖片顯示實驗 -摘自【正點原子】新起點之FPGA開發指南_V2.1
![【正點原子FPGA連載】<b class='flag-5'>第二十三</b>章RGB-LCD字符和圖片顯示<b class='flag-5'>實驗</b> -摘自【正點原子】新起點之FPGA<b class='flag-5'>開發</b>指南_V2.1](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
【GD32F303紅楓派開發板使用手冊】第二講 GPIO-流水燈實驗
![【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第二</b>講 GPIO-流水燈<b class='flag-5'>實驗</b>](https://file1.elecfans.com/web2/M00/EA/0A/wKgZomZWjIGAa8HvAAAfwpvxoD4203.png)
【GD32H757Z海棠派開發板使用手冊】第十二講 SDIO-SD卡讀寫實驗
![【<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><b class='flag-5'>讀寫實驗</b>](https://file1.elecfans.com/web2/M00/E6/A0/wKgZomZIBiaAKDTYAACMnCUwRmY025.png)
【GD32F303紅楓派開發板使用手冊】第二十講 SPI-SPI NAND FLASH讀寫實驗
![【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第二十</b>講 SPI-SPI NAND FLASH<b class='flag-5'>讀寫實驗</b>](https://file1.elecfans.com/web2/M00/F1/AD/wKgaomZzisiAamI-AABGtAQwDgo073.png)
評論