12.1實驗內(nèi)容
通過本實驗主要學習以下內(nèi)容:
SDIO操作原理
SD卡讀寫實現(xiàn)
12.2實驗原理
SD卡是一種主要以Nand Flash作為存儲介質,具有體積小、數(shù)據(jù)傳輸速度快以及支持熱插拔的優(yōu)點。如今,已被廣泛應用于數(shù)碼相機、便攜式移動設備以及手機等多種設備中。SD卡的驅動一般有SPI接口或SDIO接口,本例程介紹使用GD32F4xx的SDIO接口驅動SD卡的實現(xiàn)。
12.2.1SD卡基礎知識
SD卡:secure digital memory card是一種安全存儲器件。屬性是快閃存儲器(flash eeprom),功能用來存儲數(shù)據(jù)。
SD卡雖然是薄薄的一片,但是它并不是一個整體,而是由大量的集成電路組成。SD卡的內(nèi)部結構如下圖所示,主要由信號端子,接口控制器和存儲區(qū)組成。
SD卡主要有兩種模式,SD模式和SPI模式。不同模式下,接口定義不同。下面是SD卡的引腳。
兩種模式的接口定義如下
SD模式中,主要由VCC(電源),VSS(GND),CLK(時鐘,由主控提供),CMD(命令),DAT0-3(數(shù)據(jù)輸入輸出),由6線制組成進行通信。SPI模式,主要采用4線制通信,除了電源地外,由MISO,MOSI,CLK,CS組成。下面簡單介紹SD模式的操作。
要驅動SD卡工作,主要涉及兩個步驟。第一個步驟是SD卡的識別過程。第二個步驟是對SD卡進行讀寫過程,即主機控制器和SD卡之間進行數(shù)據(jù)傳輸?shù)倪^程。
要使SD卡能正常工作,一是要給SD卡供給穩(wěn)定的電壓,二是要SD卡按用戶規(guī)定的方式工作。這兩項工作的實現(xiàn),都是主機控制器通過給SD卡發(fā)送控制命令來實現(xiàn)的。
主機(SDIO控制器)要驅動SD卡工作,要使用許多的命令,包括應用層命令ACMD和 通用命令CMD.主機(SDIO控制器)把命令發(fā)送給SD卡,SD卡會作出回應,這里的回應叫做響應,響應命令分為6類,分別是R1、R1b、R2、R3、R6、R7。主機(SDIO控制器)給SD卡發(fā)送命令之后,SD卡會作出響應,響應中包含主機(SDIO控制器)需要的數(shù)據(jù),這些數(shù)據(jù)有SD的信息,容量,和存儲數(shù)據(jù)等等。上面已經(jīng)提到了,SD卡工作,主要是識別和數(shù)據(jù)傳輸,它的識別過程有些復雜,寫代碼的時候,可以參考協(xié)議給的初始化流程圖。數(shù)據(jù)傳輸包括讀和寫,單字節(jié)和多字節(jié)讀寫。下兩節(jié)描述識別初始化流程圖和數(shù)據(jù)讀寫時序圖。
1、讀寫數(shù)據(jù)的時序圖
SDIO與SD卡通信一般以數(shù)據(jù)塊的形式進行傳輸,SDIO(多)數(shù)據(jù)塊讀操作,如下圖所示。
SDIO(多)數(shù)據(jù)塊寫操作,如下圖所示。
2、命令格式
SDIO所有的命令和響應都是在SDIO_CMD引腳上面?zhèn)鬏數(shù)?,命令長度固定為48位,SDIO命令格式如下表所示。
3、寄存器
SDIO控制器的寄存器,主要設置SDIO控制器和命令的索引與參數(shù)。SD卡有5個寄存器CID,RCA,CSD,SCR.OCR。SD卡的信息從SD卡寄存器中獲取。
SD卡正常工作,就是根據(jù)SD卡初始化流程圖,發(fā)送命令,收到回復,直到流程結束。傳輸數(shù)據(jù),也是根據(jù)讀寫時序圖,將要發(fā)送的數(shù)據(jù)放進命令中發(fā)送出去。
12.2.2SDIO模塊原理
SDIO為安全的數(shù)字輸入輸出接口,可以用于驅動SD卡、EMMC等,主要特征如下:
? e*MMC: 與多媒體卡系統(tǒng)規(guī)格書V4.2及之前的版本全兼容。有三種不同的數(shù)據(jù)總線模式:1位(默認)、4位和8位;
? SD卡: 與SD存儲卡規(guī)格版本3.0全兼容;
? SD I/O: 與SD I/O卡規(guī)格版本3.0全兼容,有兩種不同的數(shù)據(jù)總線模式:1位(默認)和4位(包括SDR和DDR);
? 104MHz數(shù)據(jù)傳輸頻率和8位數(shù)據(jù)傳輸模式;
?中斷和DMA請求;
?數(shù)據(jù)傳輸支持DDR模式。
SDIO模塊結構框圖如下所示。主要包括以下三個部分:SDIO適配器:由控制單元、命令單元和數(shù)據(jù)單元組成,控制單元管理時鐘信號,命令單元管理命令的傳輸,數(shù)據(jù)單元管理數(shù)據(jù)的傳輸;AHB接口:包括通過AHB總線訪問的寄存器、用于數(shù)據(jù)傳輸?shù)腇IFO單元以及產(chǎn)生中斷和DMA請求信號; 內(nèi)部DMA(IDMA)以及AHB主機接口 。
SDIO模塊可以實現(xiàn)對SD卡的完全驅動以及協(xié)議的實現(xiàn),包括命令、響應等相關操作,本例程實現(xiàn)使用SDIO驅動SD卡初始化以及讀寫測試等相關操作,具體實現(xiàn)可以參考GD32H7用戶手冊以及代碼解析等。
12.3硬件設計
SD卡相關硬件電路如下圖所示,實驗板上具有SD卡卡座,信號線上有四根數(shù)據(jù)線,一根CMD命令線以及一根CLK時鐘線,所有信號線通過10K電阻進行上拉,電源地信號線具有10uf以及100nf電容,SD卡插入時,金屬接觸點朝下插入。
12.4代碼解析
12.4.1SDIO初始化配置函數(shù)
SDIO初始化配置在sd_io_init()函數(shù)中,其中包括sd_init()初始化、sd_card_information_get()SD卡信息獲取、sd_card_select_deselect()SD卡選擇、sd_cardstatus_get()SD卡狀態(tài)獲取、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_log('rn the card is locked!'); status = sd_lock_unlock(SD_UNLOCK); if(status != SD_OK) { return SD_LOCK_UNLOCK_FAILED; } else { printf_log('rn the card is unlocked successfully!'); } } if((SD_OK == status) && (!(cardstate & 0x02000000))) { /* set bus mode */ #if (SDIO_BUSMODE == BUSMODE_4BIT) status = sd_bus_mode_config(SDIO_BUSMODE_4BIT, SDIO_SPEEDMODE); #else status = sd_bus_mode_config(SDIO_BUSMODE_1BIT, SDIO_SPEEDMODE); #endif } #ifdef USE_18V_SWITCH if(SD_OK == status) { /* UHS-I Hosts can perform sampling point tuning using tuning command */ status = sd_tuning(); } #endif /* USE_18V_SWITCH */ if(SD_OK == status) { /* set data transfer mode */ /* if use 1.8V high speed mode, please select the DMA mode */ status = sd_transfer_mode_config(SDIO_DTMODE); } return status; }
12.4.2獲取SD卡信息函數(shù)
獲取SD卡信息的函數(shù)如下所示,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_log('rn 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_log('rn## Card version 4.xx ##'); } else { printf_log('rn## Card version 3.0x ##'); } } else { printf_log('rn## Card version 2.00 ##'); } } else if(1 == sd_spec) { printf_log('rn## Card version 1.10 ##'); } else if(0 == sd_spec) { printf_log('rn## Card version 1.0x ##'); } sd_security = (sd_scr[1] & 0x00700000) >> 20; if(2 == sd_security) { printf_log('rn## security v1.01 ##'); } else if(3 == sd_security) { printf_log('rn## security v2.00 ##'); } else if(4 == sd_security) { printf_log('rn## security v3.00 ##'); } block_count = (sd_cardinfo.card_csd.c_size + 1) * 1024; block_size = 512; printf_log('rn## Device size is %dKB ##', sd_card_capacity_get()); printf_log('rn## Block size is %dB ##', block_size); printf_log('rn## Block count is %d ##', block_count); if(sd_cardinfo.card_csd.read_bl_partial) { printf_log('rn## Partial blocks for read allowed ##'); } if(sd_cardinfo.card_csd.write_bl_partial) { printf_log('rn## Partial blocks for write allowed ##'); } temp_ccc = sd_cardinfo.card_csd.ccc; printf_log('rn## CardCommandClasses is: %x ##', temp_ccc); if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc)) { printf_log('rn## Block operation supported ##'); } if(SD_CCC_ERASE & temp_ccc) { printf_log('rn## Erase supported ##'); } if(SD_CCC_WRITE_PROTECTION & temp_ccc) { printf_log('rn## Write protection supported ##'); } if(SD_CCC_LOCK_CARD & temp_ccc) { printf_log('rn## Lock unlock supported ##'); } if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc) { printf_log('rn## Application specific supported ##'); } if(SD_CCC_IO_MODE & temp_ccc) { printf_log('rn## I/O mode supported ##'); } if(SD_CCC_SWITCH & temp_ccc) { printf_log('rn## Switch function supported ##'); } }
12.4.3SD卡數(shù)據(jù)塊寫入函數(shù)
SD卡數(shù)據(jù)塊寫入函數(shù)如下所示,通過該函數(shù)可實現(xiàn)SD卡數(shù)據(jù)塊的數(shù)據(jù)寫入。
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 = 0U; uint32_t count = 0U, align = 0U, datablksize = SDIO_DATABLOCKSIZE_1BYTE, *ptempbuff = pwritebuffer; uint32_t transbytes = 0U, restwords = 0U, response = 0U; __IO uint32_t timeout = 0U; if(NULL == pwritebuffer) { status = SD_PARAMETER_INVALID; return status; } transerror = SD_OK; transend = 0U; totalnumber_bytes = 0U; /* clear all DSM configuration */ sdio_data_config(SDIO, 0U, 0U, SDIO_DATABLOCKSIZE_1BYTE); sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD); sdio_dsm_disable(SDIO); sdio_idma_disable(SDIO); /* check whether the card is locked */ if(sdio_response_get(SDIO, 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) { writeaddr *= 512U; } else { blocksize = 512U; } align = blocksize & (blocksize - 1U); if((blocksize > 0U) && (blocksize <= 2048U) && (0U == align)) { datablksize = sd_datablocksize_get(blocksize); /* send CMD16(SET_BLOCKLEN) to set the block length */ sdio_command_response_config(SDIO, SD_CMD_SET_BLOCKLEN, (uint32_t)blocksize, SDIO_RESPONSETYPE_SHORT); sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO); sdio_csm_enable(SDIO); /* 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(SDIO, SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT); sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO); sdio_csm_enable(SDIO); /* check if some error occurs */ status = r1_error_check(SD_CMD_SEND_STATUS); if(SD_OK != status) { return status; } response = sdio_response_get(SDIO, SDIO_RESPONSE0); timeout = 100000U; while((0U == (response & SD_R1_READY_FOR_DATA)) && (timeout > 0U)) { /* 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(SDIO, SD_CMD_SEND_STATUS, (uint32_t)sd_rca << SD_RCA_SHIFT, SDIO_RESPONSETYPE_SHORT); sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO); sdio_csm_enable(SDIO); /* check if some error occurs */ status = r1_error_check(SD_CMD_SEND_STATUS); if(SD_OK != status) { return status; } response = sdio_response_get(SDIO, SDIO_RESPONSE0); } if(0U == timeout) { return SD_ERROR; } stopcondition = 0U; totalnumber_bytes = blocksize; /* configure the SDIO data transmisson */ sdio_data_config(SDIO, SD_DATATIMEOUT, totalnumber_bytes, datablksize); sdio_data_transfer_config(SDIO, SDIO_TRANSMODE_BLOCKCOUNT, SDIO_TRANSDIRECTION_TOCARD); sdio_trans_start_enable(SDIO); if(SD_POLLING_MODE == transmode) { /* send CMD24(WRITE_BLOCK) to write a block */ sdio_command_response_config(SDIO, SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT); sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO); sdio_csm_enable(SDIO); /* check if some error occurs */ status = r1_error_check(SD_CMD_WRITE_BLOCK); if(SD_OK != status) { return status; } /* polling mode */ while(!sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR | SDIO_FLAG_DTTMOUT | SDIO_FLAG_TXURE | SDIO_FLAG_DTBLKEND | SDIO_FLAG_DTEND)) { if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_TFH)) { /* at least 8 words can be written into the FIFO */ if((totalnumber_bytes - transbytes) < SD_FIFOHALF_BYTES) { restwords = (totalnumber_bytes - transbytes) / 4U + (((totalnumber_bytes - transbytes) % 4U == 0U) ? 0U : 1U); for(count = 0U; count < restwords; count++) { sdio_data_write(SDIO, *ptempbuff); ++ptempbuff; transbytes += 4U; } } else { for(count = 0U; count < SD_FIFOHALF_WORDS; count++) { sdio_data_write(SDIO, *(ptempbuff + count)); } /* 8 words(32 bytes) has been transferred */ ptempbuff += SD_FIFOHALF_WORDS; transbytes += SD_FIFOHALF_BYTES; } } } sdio_trans_start_disable(SDIO); /* whether some error occurs and return it */ if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTCRCERR)) { status = SD_DATA_CRC_ERROR; sdio_flag_clear(SDIO, SDIO_FLAG_DTCRCERR); return status; } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_DTTMOUT)) { status = SD_DATA_TIMEOUT; sdio_flag_clear(SDIO, SDIO_FLAG_DTTMOUT); return status; } else if(RESET != sdio_flag_get(SDIO, SDIO_FLAG_TXURE)) { status = SD_TX_UNDERRUN_ERROR; sdio_flag_clear(SDIO, SDIO_FLAG_TXURE); return status; } else { /* if else end */ } } else if(SD_DMA_MODE == transmode) { /* DMA mode */ /* enable the SDIO corresponding interrupts and DMA */ sdio_interrupt_enable(SDIO, SDIO_INT_DTCRCERR | SDIO_INT_DTTMOUT | SDIO_INT_TXURE | SDIO_INT_DTEND); dma_config(pwritebuffer, (uint32_t)(blocksize >> 5)); sdio_idma_enable(SDIO); /* send CMD24(WRITE_BLOCK) to write a block */ sdio_command_response_config(SDIO, SD_CMD_WRITE_BLOCK, writeaddr, SDIO_RESPONSETYPE_SHORT); sdio_wait_type_set(SDIO, SDIO_WAITTYPE_NO); sdio_csm_enable(SDIO); /* check if some error occurs */ status = r1_error_check(SD_CMD_WRITE_BLOCK); if(SD_OK != status) { return status; } while((0U == transend) && (SD_OK == transerror)) { } if(SD_OK != transerror) { return transerror; } } else { status = SD_PARAMETER_INVALID; return status; } /* clear the DATA_FLAGS flags */ sdio_flag_clear(SDIO, SDIO_MASK_DATA_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; }
上一篇:基于GD32F427和GD32E505的直流充電樁解決方案
下一篇:【GD32H757Z海棠派開發(fā)板使用手冊】第二講 GPIO-按鍵查詢檢測實驗
推薦閱讀最新更新時間:2025-04-25 11:29

設計資源 培訓 開發(fā)板 精華推薦
- TRK-KEA64: 配備256B EEPROM的Kinetis KEA64 StarterTRAK
- 使用 ROHM Semiconductor 的 BD4849 的參考設計
- SPC56系列微控制器的評估主板
- 5V UPS核心板
- LT4256-1 演示板,具有閂鎖功能的正高壓熱插拔控制器 (-1)
- 面向采用MMA8652FC、FXAS21002C和MAG3110傳感器的9軸解決方案的傳感器工具箱開發(fā)板
- PTN5100 USB Type-C Power Delivery PHY 的典型應用
- 100WLED驅動
- STEVAL-TDR013V1,使用 PD84002 用于 UHF RFID 閱讀器的演示板
- 紅外避障模塊-IR333-PT333
- 大眾汽車宣布明年起其所有電動車型全面轉向磷酸鐵鋰電池,升級至MEB Plus平臺
- 總產(chǎn)值破2000億,深圳要做“機器人第一城”?
- 鴻道Intewell操作系統(tǒng) 人形機器人底層操作系統(tǒng)
- 如何定位國產(chǎn)智駕芯片的終局價值?
- 新一代車規(guī)級數(shù)字功放電感VSAD-T系列 為汽車音響注入高保真基因
- 蜂巢能源快充電池突破:15分鐘充至滿電,提升30%效率
- 整車操作系統(tǒng)何以躋身智能汽車三大件?
- 人形機器人如何做到“手眼”協(xié)同+“大小腦”協(xié)同?
- 中國電池公司獲英國政府10億英鎊支持!
- 從游戲到智能駕駛,英偉達有哪些技術升級?
- 免費試用eZ430-RF2500開發(fā)套件!
- 搶樓有禮:看直播,深入了解ST最新 MEMS氣壓計原理、操作、防水結構設計
- 有獎國產(chǎn)芯直播:先楫800MHz RISC-V MCU高能秀,豈止控4只伺服電機,干貨多多
- TI有獎直播|精密 ADC 在變送器中的應用
- MPS 隔離式穩(wěn)壓 DCDC 模塊——MIE系列,小且不凡!痛點討論|你理想中的電源模塊是怎樣的?
- 下載有好禮!超多精美禮品等您拿!
- 福祿克專家級熱像儀震撼上市,參與問答贏精美好禮!
- 免費測評|ESP32-S2-Kaluga-1新型多媒體開發(fā)板,靈活拆裝,滿足多種需求
- 2021年STM32中國峰會暨粉絲狂歡節(jié) 報名啦!