12.1實(shí)驗(yàn)內(nèi)容
通過本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容:
SDIO操作原理
SD卡讀寫實(shí)現(xiàn)
12.2實(shí)驗(yàn)原理
SD卡是一種主要以Nand Flash作為存儲(chǔ)介質(zhì),具有體積小、數(shù)據(jù)傳輸速度快以及支持熱插拔的優(yōu)點(diǎn)。如今,已被廣泛應(yīng)用于數(shù)碼相機(jī)、便攜式移動(dòng)設(shè)備以及手機(jī)等多種設(shè)備中。SD卡的驅(qū)動(dòng)一般有SPI接口或SDIO接口,本例程介紹使用GD32F4xx的SDIO接口驅(qū)動(dòng)SD卡的實(shí)現(xiàn)。
12.2.1SD卡基礎(chǔ)知識(shí)
SD卡:secure digital memory card是一種安全存儲(chǔ)器件。屬性是快閃存儲(chǔ)器(flash eeprom),功能用來存儲(chǔ)數(shù)據(jù)。
SD卡雖然是薄薄的一片,但是它并不是一個(gè)整體,而是由大量的集成電路組成。SD卡的內(nèi)部結(jié)構(gòu)如下圖所示,主要由信號(hào)端子,接口控制器和存儲(chǔ)區(qū)組成。
SD卡主要有兩種模式,SD模式和SPI模式。不同模式下,接口定義不同。下面是SD卡的引腳。
兩種模式的接口定義如下
SD模式中,主要由VCC(電源),VSS(GND),CLK(時(shí)鐘,由主控提供),CMD(命令),DAT0-3(數(shù)據(jù)輸入輸出),由6線制組成進(jìn)行通信。SPI模式,主要采用4線制通信,除了電源地外,由MISO,MOSI,CLK,CS組成。下面簡(jiǎn)單介紹SD模式的操作。
要驅(qū)動(dòng)SD卡工作,主要涉及兩個(gè)步驟。第一個(gè)步驟是SD卡的識(shí)別過程。第二個(gè)步驟是對(duì)SD卡進(jìn)行讀寫過程,即主機(jī)控制器和SD卡之間進(jìn)行數(shù)據(jù)傳輸?shù)倪^程。
要使SD卡能正常工作,一是要給SD卡供給穩(wěn)定的電壓,二是要SD卡按用戶規(guī)定的方式工作。這兩項(xiàng)工作的實(shí)現(xiàn),都是主機(jī)控制器通過給SD卡發(fā)送控制命令來實(shí)現(xiàn)的。
主機(jī)(SDIO控制器)要驅(qū)動(dòng)SD卡工作,要使用許多的命令,包括應(yīng)用層命令A(yù)CMD和 通用命令CMD.主機(jī)(SDIO控制器)把命令發(fā)送給SD卡,SD卡會(huì)作出回應(yīng),這里的回應(yīng)叫做響應(yīng),響應(yīng)命令分為6類,分別是R1、R1b、R2、R3、R6、R7。主機(jī)(SDIO控制器)給SD卡發(fā)送命令之后,SD卡會(huì)作出響應(yīng),響應(yīng)中包含主機(jī)(SDIO控制器)需要的數(shù)據(jù),這些數(shù)據(jù)有SD的信息,容量,和存儲(chǔ)數(shù)據(jù)等等。上面已經(jīng)提到了,SD卡工作,主要是識(shí)別和數(shù)據(jù)傳輸,它的識(shí)別過程有些復(fù)雜,寫代碼的時(shí)候,可以參考協(xié)議給的初始化流程圖。數(shù)據(jù)傳輸包括讀和寫,單字節(jié)和多字節(jié)讀寫。下兩節(jié)描述識(shí)別初始化流程圖和數(shù)據(jù)讀寫時(shí)序圖。
1、讀寫數(shù)據(jù)的時(shí)序圖
SDIO與SD卡通信一般以數(shù)據(jù)塊的形式進(jìn)行傳輸,SDIO(多)數(shù)據(jù)塊讀操作,如下圖所示。
SDIO(多)數(shù)據(jù)塊寫操作,如下圖所示。
2、命令格式
SDIO所有的命令和響應(yīng)都是在SDIO_CMD引腳上面?zhèn)鬏數(shù)?,命令長(zhǎng)度固定為48位,SDIO命令格式如下表所示。
3、寄存器
SDIO控制器的寄存器,主要設(shè)置SDIO控制器和命令的索引與參數(shù)。SD卡有5個(gè)寄存器CID,RCA,CSD,SCR.OCR。SD卡的信息從SD卡寄存器中獲取。
SD卡正常工作,就是根據(jù)SD卡初始化流程圖,發(fā)送命令,收到回復(fù),直到流程結(jié)束。傳輸數(shù)據(jù),也是根據(jù)讀寫時(shí)序圖,將要發(fā)送的數(shù)據(jù)放進(jìn)命令中發(fā)送出去。
12.2.2SDIO模塊原理
SDIO為安全的數(shù)字輸入輸出接口,可以用于驅(qū)動(dòng)SD卡、EMMC等,主要特征如下:
? MMC: 與多媒體卡系統(tǒng)規(guī)格書V4.2及之前的版本全兼容。有三種不同的數(shù)據(jù)總線模式:1位(默認(rèn))、4位和8位;
? SD卡: 與SD存儲(chǔ)卡規(guī)格版本2.0全兼容;
? SD I/O: 與SD I/O卡規(guī)格版本2.0全兼容,有兩種不同的數(shù)據(jù)總線模式:1位(默認(rèn))和4位;
? CE-ATA: 與CE-ATA數(shù)字協(xié)議版本1.1全兼容;
? 48MHz數(shù)據(jù)傳輸頻率和8位數(shù)據(jù)傳輸模式;
?中斷和DMA請(qǐng)求;
?完成信號(hào)使能和失能(CE-ATA)。
SDIO模塊結(jié)構(gòu)框圖如下所示。主要包含兩大部分:SDIO適配器:由控制單元、命令單元和數(shù)據(jù)單元組成,控制單元管理時(shí)鐘信號(hào),命令單元管理命令的傳輸,數(shù)據(jù)單元管理數(shù)據(jù)的傳輸;AHB接口:包括通過AHB總線訪問的寄存器、用于數(shù)據(jù)傳輸?shù)腇IFO單元以及產(chǎn)生中斷和DMA請(qǐng)求信號(hào)。
SDIO模塊可以實(shí)現(xiàn)對(duì)SD卡的完全驅(qū)動(dòng)以及協(xié)議的實(shí)現(xiàn),包括命令、響應(yīng)等相關(guān)操作,本例程實(shí)現(xiàn)使用SDIO驅(qū)動(dòng)SD卡初始化以及讀寫測(cè)試等相關(guān)操作,具體實(shí)現(xiàn)可以參考GD32F4xx用戶手冊(cè)以及代碼解析等。
12.3硬件設(shè)計(jì)
SD卡相關(guān)硬件電路如下圖所示,實(shí)驗(yàn)板上具有SD卡卡座,信號(hào)線上有四根數(shù)據(jù)線,一根CMD命令線以及一根CLK時(shí)鐘線,所有信號(hào)線通過10K電阻進(jìn)行上拉,電源地信號(hào)線具有10uf以及100nf電容,SD卡插入時(shí),金屬接觸點(diǎn)朝下插入。
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('rn 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卡信息函數(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('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('rn## Card version 4.xx ##'); } else { // printf('rn## Card version 3.0x ##'); } } else { // printf('rn## Card version 2.00 ##'); } } else if(1 == sd_spec) { // printf('rn## Card version 1.10 ##'); } else if(0 == sd_spec) { // printf('rn## Card version 1.0x ##'); } sd_security = (sd_scr[1] & 0x00700000) >> 20; if(2 == sd_security) { // printf('rn## SDSC card ##'); } else if(3 == sd_security) { // printf('rn## SDHC card ##'); } else if(4 == sd_security) { // printf('rn## SDXC card ##'); } block_count = (sd_cardinfo.card_csd.c_size + 1)*1024; block_size = 512; // printf('rn## Device size is %dKB ##', sd_card_capacity_get()); // printf('rn## Block size is %dB ##', block_size); // printf('rn## Block count is %d ##', block_count); if(sd_cardinfo.card_csd.read_bl_partial){ // printf('rn## Partial blocks for read allowed ##' ); } if(sd_cardinfo.card_csd.write_bl_partial){ // printf('rn## Partial blocks for write allowed ##' ); } temp_ccc = sd_cardinfo.card_csd.ccc; //printf('rn## CardCommandClasses is: %x ##', temp_ccc); if((SD_CCC_BLOCK_READ & temp_ccc) && (SD_CCC_BLOCK_WRITE & temp_ccc)){ // printf('rn## Block operation supported ##'); } if(SD_CCC_ERASE & temp_ccc){ // printf('rn## Erase supported ##'); } if(SD_CCC_WRITE_PROTECTION & temp_ccc){ // printf('rn## Write protection supported ##'); } if(SD_CCC_LOCK_CARD & temp_ccc){ // printf('rn## Lock unlock supported ##'); } if(SD_CCC_APPLICATION_SPECIFIC & temp_ccc){ // printf('rn## Application specific supported ##'); } if(SD_CCC_IO_MODE & temp_ccc){ // printf('rn## I/O mode supported ##'); } if(SD_CCC_SWITCH & temp_ccc){ // printf('rn## Switch function supported ##'); } } |
12.4.3SD卡數(shù)據(jù)塊寫入函數(shù)
SD卡數(shù)據(jù)塊寫入函數(shù)如下所示,通過該函數(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 = 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卡數(shù)據(jù)塊讀取函數(shù)
上一篇:【GD32H757Z海棠派開發(fā)板使用手冊(cè)】第六講 TIMER_3路PWM輸出實(shí)驗(yàn)
下一篇:【GD32H757Z海棠派開發(fā)板使用手冊(cè)】第七講 FWDG-看門狗實(shí)驗(yàn)
設(shè)計(jì)資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級(jí)數(shù)字信號(hào)控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠(yuǎn)距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進(jìn)行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲(chǔ)html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測(cè)試
- T12智能恒溫焊臺(tái)V2
- LTM4650IY-1A 1.2V 和 1V 輸出跟蹤的典型應(yīng)用電路
- 遠(yuǎn)程文字圖形顯示器
- LTC1550LCS8-2 1mVP-P 紋波、-2V 輸出 GaAs FET 偏置發(fā)生器的典型應(yīng)用電路
- 使用 NXP Semiconductors 的 ISP1705 的參考設(shè)計(jì)
- LPC32x0 電源域設(shè)計(jì),適用于低功耗、高性能應(yīng)用的嵌入式 MCU 系列
- 基于 ADG904-R 的中頻帶通濾波器組切換網(wǎng)絡(luò),用于無線基礎(chǔ)設(shè)施
- FS1.1s雙面HUB
- DC489A-B,使用 LTC5507ES6 HF 至 UHF 頻率射頻功率檢測(cè)器的演示板
- XRP7714EVB-DEMO-3,基于XRP7714的四通道數(shù)字PWM演示板
- 知名機(jī)構(gòu)發(fā)布全球ADAS激光雷達(dá)排名 華為等中國玩家上榜
- 知名機(jī)構(gòu)發(fā)布全球ADAS激光雷達(dá)排名 華為等中國玩家上榜
- 谷歌Android 12L已經(jīng)支持在WebView中長(zhǎng)截圖
- Teledyne e2v目前正在交付其宇航級(jí)DDR4內(nèi)存解決方案
- 2025年中國AI芯片市場(chǎng)規(guī)或達(dá)1740億元,芯片制造環(huán)節(jié)瓶頸突出
- 廣汽埃安動(dòng)力電池試制線正式開建,預(yù)計(jì)年底投入運(yùn)營
- 基于單片機(jī)的智能心率體溫檢測(cè)系統(tǒng)設(shè)計(jì)
- "智能汽車芯片大戰(zhàn)升級(jí):高通最新方案為何獲中國車企追捧?
- 電壓精度0.5% @25°C!思瑞浦發(fā)布全新車規(guī)并聯(lián)基準(zhǔn)芯片TPR43xQ系列產(chǎn)品
- AI技術(shù)在方便面生產(chǎn)質(zhì)量監(jiān)控中的應(yīng)用
- 潤(rùn)石科技推出RS3215-Q1系列低壓差線性穩(wěn)壓器
- CANape 23開啟智能測(cè)試新時(shí)代(下)
- 軟件定義汽車電源管理設(shè)計(jì):NXP的PMIC選型攻略解析
- 深度測(cè)評(píng)時(shí)空壺X1同聲傳譯器:全球最先進(jìn)AI同傳設(shè)備的非凡實(shí)力
- 作為領(lǐng)先的垂直整合制造商(IDM),英飛凌在 300mm氮化鎵生產(chǎn)路線圖方面取得突破
- 鐵威馬F6-424 Max:六盤位擴(kuò)容+國產(chǎn)系統(tǒng)兼容,小白也能玩轉(zhuǎn)NAS
- 開關(guān)電源給鉛酸電池恒流恒壓充電的電流跳動(dòng)問題解析
- AMD否認(rèn)與中國不正當(dāng)?shù)毓蚕鞢PU技術(shù)
- 電動(dòng)汽車上的“全SiC”功率器件,系關(guān)鍵要素
- 外媒:中美貿(mào)易戰(zhàn)休兵 未必能給經(jīng)濟(jì)前景帶來光明
- 劉揚(yáng)偉上任!鴻海啟動(dòng)了轉(zhuǎn)型半導(dǎo)體新的時(shí)代?
- 外媒:中美重新回到協(xié)商桌,仍有漫長(zhǎng)談判路
- 哈曼Ignite安全云方案為汽車制造商帶來新服務(wù)和創(chuàng)收機(jī)遇
- CES首日:中國家電仍被海外集團(tuán)領(lǐng)先一個(gè)身位
- 一面墻的電視?CES上的這些電視顛覆想象!
- “第五大家電”炒作背后:只是忽悠消費(fèi)者的噱頭
- CES黑科技:用AI將任何視頻內(nèi)容轉(zhuǎn)化到8K分辨率