SD卡(Secure Digital Memory Card)即:安全數(shù)字內(nèi)存卡,它是在MMC的基礎(chǔ)上發(fā)展而來(lái),是一種基于半導(dǎo)體快閃記憶器的新一代記憶設(shè)備,它被廣泛地于便攜式裝置上使用,例如數(shù)碼相機(jī)、個(gè)人數(shù)碼助理(PDA)和多媒體播放器等。SD卡由日本松下、東芝及美國(guó)SanDisk公司于1999年8月共同開(kāi)發(fā)研制。
- SD卡簡(jiǎn)介
SD非常小巧,可以嵌入到設(shè)備中,在嵌入式開(kāi)發(fā)中,產(chǎn)品需要存儲(chǔ)一些容量叫大的文件,就可能會(huì)運(yùn)用到SD卡。SD卡按容量分類(lèi),可以分為3類(lèi):SD卡、SDHC卡、SDXC卡,如下表所示。
容量大小不同的SD卡,其內(nèi)部的操作標(biāo)準(zhǔn)是不同的。很多外設(shè)會(huì)明確告訴用戶(hù)本設(shè)備最大能夠支持容量多大的外擴(kuò),不能無(wú)限制的擴(kuò)存,因?yàn)槿萘吭酱?,操作不同,?duì)控制器的要求比較高。當(dāng)前設(shè)備的控制器不足以支持大容量,所以有外擴(kuò)限制。
SD卡由9個(gè)引腳與外部通信,支持SPI和SDIO兩種模式,不同模式下,SD卡引腳功能描述如下表所示。
- SD卡的物理結(jié)構(gòu)
一張SD卡包括有存儲(chǔ)單元、存儲(chǔ)單元接口、電源檢測(cè)、卡及接口控制器和接口驅(qū)動(dòng)器5個(gè)部分。
存儲(chǔ)單元:是存儲(chǔ)數(shù)據(jù)部件,存儲(chǔ)單元通過(guò)存儲(chǔ)單元接口與卡控制單元進(jìn)行數(shù)據(jù)傳輸;
電源檢測(cè)單元:保證SD卡工作在合適的電壓下,如出現(xiàn)掉電或上狀態(tài)時(shí),它會(huì)使控制單元和存儲(chǔ)單元接口復(fù)位;
卡及接口控制單元:控制SD卡的運(yùn)行狀態(tài),它包括有8個(gè)寄存器;
接口驅(qū)動(dòng)器:控制SD卡引腳的輸入輸出。
- SD卡內(nèi)部寄存器
SD卡總共有8個(gè)寄存器,用于設(shè)定或表示SD卡信息。這些寄存器只能通過(guò)對(duì)應(yīng)的命令訪(fǎng)問(wèn),程序控制中只需要發(fā)送組合命令就可以實(shí)現(xiàn)SD卡的控制以及讀寫(xiě)操作。
- SDIO接口
SDIO全稱(chēng)是安全數(shù)字輸入/輸出接口,多媒體卡(MMC)、SD卡、SD I/O卡都有SDIO接口。STM32F407系列控制器有一個(gè)SDIO主機(jī)接口,它可以與MMC卡、SD卡、SD I/O卡以及CE-ATA設(shè)備進(jìn)行數(shù)據(jù)傳輸。也就是說(shuō)SDIO接口不僅僅只會(huì)操作SD卡,凡是符合SDIO接口通信的設(shè)備都可以被操作。
SDIO 具有以下特性:
完全兼容 多媒體卡系統(tǒng)規(guī)范版本 4.2??ㄖС秩N不同數(shù)據(jù)總線(xiàn)模式:1 位(默認(rèn))、4 位和 8 位
完全兼容先前版本的多媒體卡(向前兼容性)
完全兼容 SD 存儲(chǔ)卡規(guī)范版本2.0
完全兼容 SD I/O 卡規(guī)范版本 2.0 : 卡支持兩種不同數(shù)據(jù)總線(xiàn)模式:1 位(默認(rèn))和 4 位
完全支持 CE-ATA 功能(完全符合 CE-ATA 數(shù)字協(xié)議版本 1.1)
對(duì)于 8 位模式,數(shù)據(jù)傳輸高達(dá) 48 MHz
數(shù)據(jù)和命令輸出使能信號(hào),控制外部雙向驅(qū)動(dòng)程序。
SDIO 不具備兼容 SPI 的通信模式。
- SDIO組成
SDIO 適配器塊提供特定于 MMC/SD/SD I/O 卡的所有功能,如時(shí)鐘生成單元、命令和數(shù)據(jù)傳輸。
APB2 接口訪(fǎng)問(wèn) SDIO 適配器寄存器,并且生成中斷和 DMA 請(qǐng)求信號(hào)。
注:
1、默認(rèn)情況下,SDIO_D0用于數(shù)據(jù)傳輸。初始化后,主機(jī)可以更改數(shù)據(jù)總線(xiàn)寬度。
2、SD 卡連接到總線(xiàn),主機(jī)可以將數(shù)據(jù)傳輸配置為SDIO_D[3:0]
3、SDIO使用兩個(gè)時(shí)鐘信號(hào):SDIO適配器時(shí)鐘(SDIOCLK= 48 MHz)和APB2總線(xiàn)時(shí)鐘(PCLK2)。
4、卡時(shí)鐘(SDIO_CK):每個(gè)時(shí)鐘周期在命令和數(shù)據(jù)線(xiàn)上傳輸1位命令或數(shù)據(jù)。對(duì)于SD或SDI/O卡,時(shí)鐘頻率可以在0MHz至25MHz間變化,當(dāng)數(shù)據(jù)正式穩(wěn)定傳輸?shù)臅r(shí)候配置為24MHz。SDIO_CK計(jì)算公式:SDIO_CK=SDIOCLK/(2+CLKDIV)
5、SDIO適配器時(shí)鐘(SDIOCLK):該時(shí)鐘用于驅(qū)動(dòng)SDIO適配器,可用于產(chǎn)生SDIO_CK時(shí)鐘。對(duì)F4來(lái)說(shuō),SDIOCLK來(lái)自PLL48CK(48Mhz)。
6、F4:APB2總線(xiàn)接口時(shí)鐘(PCLK2):該時(shí)鐘用于驅(qū)動(dòng)SDIO的APB2總線(xiàn)接口,其頻率為PCLK2=84Mhz。
注意:在SD卡初始化時(shí),SDIO_CK不可以超過(guò)400Khz,初始化完成后,可以設(shè)置為最大頻率(但不可以超過(guò)SD卡最大操作頻率)。
該適配器由五個(gè)子單元組成:
1.適配器寄存器塊 :適配器寄存器模塊包含所有系統(tǒng)寄存器。
2.控制單元 : 控制單元包含電源管理功能和存儲(chǔ)卡時(shí)鐘的時(shí)鐘分頻器。
3.命令路徑 :命令路徑單元向卡發(fā)送命令并從卡接收響應(yīng)。
4.數(shù)據(jù)路徑 :數(shù)據(jù)路徑子單元負(fù)責(zé)與卡相互傳輸數(shù)據(jù)。
5.數(shù)據(jù) FIFO :數(shù)據(jù) FIFO(先進(jìn)先出)子單元是一個(gè)數(shù)據(jù)緩沖器,帶發(fā)送和接收單元。FIFO 包含一個(gè)寬度為 32 位且深度為 32 字的數(shù)據(jù)緩沖器和發(fā)送/接收邏輯。(一共32 個(gè)單元,一個(gè)單元一個(gè)字)。所有的數(shù)據(jù)傳輸都要經(jīng)過(guò)FIFO,便于管理。
- SDIO 命令簡(jiǎn)介
SD命令由主機(jī)發(fā)出,以廣播命令和尋址命令為例,廣播命令是針對(duì)與SD主機(jī)總線(xiàn)連接的所有從設(shè)備發(fā)送的,尋址命令是指定某個(gè)地址設(shè)備進(jìn)行命令傳輸。
SD命令格式固定為48bit,都是通過(guò)CMD線(xiàn)連續(xù)傳輸?shù)模瑪?shù)據(jù)線(xiàn)不參與。
SD命令的組成如下:
起始位和終止位:命令的主體包含在起始位與終止位之間,它們都只包含一個(gè)數(shù)據(jù)位,起始位為 0,終止位為 1。
傳輸標(biāo)志:用于區(qū)分傳輸方向,該位為 1 時(shí)表示命令,方向?yàn)橹鳈C(jī)傳輸?shù)?SD 卡,該位為 0時(shí)表示響應(yīng),方向?yàn)?SD卡傳輸?shù)街鳈C(jī)。
命令主體內(nèi)容包括命令、地址信息/參數(shù)和 CRC 校驗(yàn)三個(gè)部分。
命令號(hào):它固定占用 6bit,所以總共有 64個(gè)命令(代號(hào):CMD0~CMD63),每個(gè)命令都有特定的用途,部分命令不適用于 SD 卡操作,只是專(zhuān)門(mén)用于 MMC卡或者SD I/O卡。
地址/參數(shù):每個(gè)命令有 32bit地址信息/參數(shù)用于命令附加內(nèi)容,例如,廣播命令沒(méi)有地址信息,這 32bit用于指定參數(shù),而尋址命令這 32bit用于指定目標(biāo) SD卡的地址。
CRC7 校驗(yàn):長(zhǎng)度為 7bit的校驗(yàn)位用于驗(yàn)證命令傳輸內(nèi)容正確性,如果發(fā)生外部干擾導(dǎo)致傳輸數(shù)據(jù)個(gè)別位狀態(tài)改變將導(dǎo)致校準(zhǔn)失敗,也意味著命令傳輸失敗,SD卡不執(zhí)行命令。
SD命令有4種類(lèi)型:
1.無(wú)響應(yīng)廣播命令(bc),發(fā)送到所有卡,不返回任務(wù)響應(yīng);
2.帶響應(yīng)廣播命令(bcr),發(fā)送到所有卡,同時(shí)接收來(lái)自所有卡響應(yīng);
3.尋址命令(ac),發(fā)送到選定卡,DAT線(xiàn)無(wú)數(shù)據(jù)傳輸;
5.尋址數(shù)據(jù)傳輸命令(adtc),發(fā)送到選定卡,DAT線(xiàn)有數(shù)據(jù)傳輸。
在標(biāo)準(zhǔn)中定義了兩種類(lèi)型的通用命令:特定應(yīng)用命令(ACMD)和常規(guī)命令(GEN_CMD),也就是說(shuō)在64個(gè)命令作為常規(guī)命令的基礎(chǔ)上加了特定的命令
要使用SD卡制造商特定的ACMD命令如ACMD6,需要在發(fā)送該命令之前無(wú)發(fā)送CMD55命令,告知SD卡接下來(lái)的命令為特定應(yīng)用命令。CMD55命令只對(duì)緊接的第一個(gè)命令有效,SD卡如果檢測(cè)到CMD55之后的第一條命令為ACMD則執(zhí)行其特定應(yīng)用功能,如果檢測(cè)發(fā)現(xiàn)不是ACMD命令,則執(zhí)行標(biāo)準(zhǔn)命令。
SD命令響應(yīng)由SD卡向主機(jī)發(fā)出,部分命令要求SD卡作出響應(yīng),這些響應(yīng)多用于反饋SD卡的狀態(tài)。基本特性如下:
lSDIO總共有7個(gè)響應(yīng)類(lèi)型(代號(hào):R1~R7),其中SD卡沒(méi)有R4、R5類(lèi)型響應(yīng)。特定的命令對(duì)應(yīng)有特定的響應(yīng)類(lèi)型,比如當(dāng)主機(jī)發(fā)送CMD3命令時(shí),可以得到響應(yīng)R6。與命令一樣,SD卡的響應(yīng)也是通過(guò)CMD線(xiàn)連續(xù)傳輸?shù)摹8鶕?jù)響應(yīng)內(nèi)容大小可以分為短響應(yīng)和長(zhǎng)響應(yīng)。短響應(yīng)是48bit長(zhǎng)度,只有R2類(lèi)型是長(zhǎng)響應(yīng),其長(zhǎng)度為136bit。
SDIO讀數(shù)據(jù)
單個(gè)塊讀操作與多個(gè)塊的讀操作除命令不同外,還體現(xiàn)在讀操作結(jié)束時(shí),單個(gè)塊讀取一個(gè)塊自動(dòng)結(jié)束,而多個(gè)塊還需要主機(jī)發(fā)送停止命令。寫(xiě)操作類(lèi)似,也要多發(fā)一個(gè)結(jié)束命令,只不過(guò)寫(xiě)操作寫(xiě)數(shù)據(jù)前需要檢查卡的狀態(tài)是否為忙狀態(tài)。
SDIO寫(xiě)數(shù)據(jù)
- SD卡操作模式
SD卡有多個(gè)版本,STM32控制器目前最高支持《Physical Layer SimplifiedSpecification V2.0》定義的SD卡,STM32控制器對(duì)SD卡進(jìn)行數(shù)據(jù)讀寫(xiě)之前需要識(shí)別卡的種類(lèi):V1.0標(biāo)準(zhǔn)卡、V2.0標(biāo)準(zhǔn)卡、V2.0高容量卡或者不被識(shí)別卡。
SD卡系統(tǒng)定義了兩種操作模式:卡識(shí)別模式和數(shù)據(jù)傳輸模式。
在系統(tǒng)復(fù)位后,主機(jī)處于卡識(shí)別模式,尋找總線(xiàn)上可用的SDIO設(shè)備;同時(shí),SD卡也處于卡識(shí)別模式,直到被主機(jī)識(shí)別到,即當(dāng)SD卡接收到SEND_RCA(CMD3)命令后,SD卡就會(huì)進(jìn)入數(shù)據(jù)傳輸模式,而主機(jī)在總線(xiàn)上所有卡被識(shí)別后也進(jìn)入數(shù)據(jù)傳輸模式。
每個(gè)不同的操作模式下,SD卡都有不同狀態(tài),通過(guò)命令控制實(shí)現(xiàn)卡狀態(tài)的切換,在不同的狀態(tài)下做不同的事,比如在發(fā)送數(shù)據(jù)前需要SD卡處于傳輸狀態(tài),發(fā)送數(shù)據(jù)時(shí),SD卡處于接收狀態(tài)。
- 卡識(shí)別模式
①上電后,主機(jī)發(fā)送CMD0讓所有卡軟復(fù)位從而進(jìn)入空閑狀態(tài)。
②主機(jī)發(fā)送CMD8確定卡的電壓范圍,并識(shí)別是否為2.0的卡
③主機(jī)發(fā)送ACMD41識(shí)別或拒絕不匹配它的電壓范圍的卡,SD卡需要工作在特定的電壓范圍之內(nèi)
④主機(jī)發(fā)送CMD2來(lái)控制所有卡返回它們的卡識(shí)別號(hào)CID(128位)
⑤主機(jī)發(fā)送CMD3命令,讓卡推薦一個(gè)RCA(16)地址作為以后通信的標(biāo)識(shí),之后都以RCA值作為身份標(biāo)識(shí)進(jìn)行信息交互。
注:在卡識(shí)別過(guò)程中,要求SD卡工作在識(shí)別時(shí)鐘頻率FOD的狀態(tài)下,在SD卡初始化時(shí),SDIO_CK不可以超過(guò)400Khz
- 數(shù)據(jù)傳輸模式
只有SD卡系統(tǒng)處于數(shù)據(jù)傳輸模式下才可以進(jìn)行數(shù)據(jù)讀寫(xiě)操作。數(shù)據(jù)傳輸模式下可以將主機(jī)SD時(shí)鐘頻率設(shè)置為FPP,默認(rèn)最高為25MHz,頻率切換可以通過(guò)CMD4命令來(lái)實(shí)現(xiàn)。通過(guò)CMD7命令加上RCA值來(lái)選定指定的卡,選中后SD卡進(jìn)入數(shù)據(jù)傳輸狀態(tài),就可以發(fā)送CMD17讀單個(gè)塊,CMD18讀多個(gè)塊,讀多個(gè)塊時(shí)只有發(fā)送CMD12命令才會(huì)停止。SD卡再次進(jìn)入傳輸狀態(tài),若不想對(duì)卡有任何操作可以再次發(fā)送CMD7命令加上RCA值來(lái)取消指定的卡,寫(xiě)操作與上述原理相同。
- SD卡普通模式操作實(shí)例
實(shí)驗(yàn)內(nèi)容:向SD卡寫(xiě)入數(shù)據(jù)后讀出
實(shí)驗(yàn)步驟:
1.配置RCC,與以往不同的是SDIO適配器的時(shí)鐘是單獨(dú)配置的,需要專(zhuān)用的SDIOCLK,標(biāo)準(zhǔn)工作在48MHz
2.配置SDIO
3.編寫(xiě)代碼
//mian.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "sdio.h"
#include "usart.h"
#include "gpio.h"
#define SDBUF_SIZE 1024
uint8_t SDBUF_TX[SDBUF_SIZE],SDBUF_RX[SDBUF_SIZE];//數(shù)據(jù)傳輸?shù)腷uf,一個(gè)用于傳輸,一個(gè)用于接收
//定義全局變量,最好不定義局部變量,防止因過(guò)大造成棧溢出
int main(void)
{
uint32_t i;
HAL_SD_CardInfoTypeDef pCardInfo;//定義結(jié)構(gòu)體用來(lái)接收卡信息
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
printf("this is sd testn");
//卡識(shí)別結(jié)束后就可以調(diào)用HAL_SD_GetCardInfo()函數(shù)獲取卡信息并打印
HAL_SD_GetCardInfo(&hsd, &pCardInfo);
printf("pCardInfo.CardType = %un",pCardInfo.CardType);
printf("pCardInfo.CardVersion = %un",pCardInfo.CardVersion);//版本
printf("pCardInfo.BlockNbr = %un",pCardInfo.BlockNbr);//SD卡塊數(shù)
printf("pCardInfo.BlockSize = %un",pCardInfo.BlockSize);//每一塊大小
/*--------------------SD卡寫(xiě)測(cè)試----------------------------------*/
memset(SDBUF_TX, 0x8, SDBUF_SIZE); /、填充TXbuf為0x8
/**
//函數(shù)功能及參數(shù)描述
*HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData,
*uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
* @param hsd Pointer to SD handle
* @param pData pointer to the buffer that will contain the data to transmit
* @param BlockAdd Block Address where data will be written,從哪一個(gè)塊開(kāi)始寫(xiě)
* @param NumberOfBlocks Number of SD blocks to write 寫(xiě)幾個(gè)塊
* @param Timeout Specify timeout value 超時(shí)時(shí)間
* @retval HAL status
if( HAL_SD_WriteBlocks(&hsd, SDBUF_TX, 0 , 2, 1000) == HAL_OK)
{
while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);//處于傳輸狀態(tài)退出
printf("WriteBlocks Successfullyn");
for(i=0; i< SDBUF_SIZE; i++)
{
printf("%d ",SDBUF_TX[i]);
}
printf("rn");
}
else
{
printf("WriteBlocks Failedn");
}
/*--------------------SD 卡讀測(cè)試----------------------------------*/
//與HAL_SD_WriteBlocks函數(shù)的參數(shù)功能相同
if( HAL_SD_ReadBlocks(&hsd, SDBUF_RX , 0, 2, 1000) == HAL_OK)
{
while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);//返回到傳輸狀態(tài)退出
printf("ReadBlocks Successfullyn");
for(i=0; i< SDBUF_SIZE; i++)
{
printf("%d ",SDBUF_RX[i]);
}
printf("rn");
}
else
{
printf("ReadBlocks Failedn");
}
/*--------------------SD 擦除測(cè)試----------------------------------*/
if (HAL_SD_Erase(&hsd, 0, 1) == HAL_OK )
{
while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);
printf("SD_Erase Successfullyn");
}
else
{
printf("SD_Erase Failedn");
}
/*--------------------SD 卡讀測(cè)試----------------------------------*/
if( HAL_SD_ReadBlocks(&hsd, SDBUF_RX , 0, 2, 1000) == HAL_OK)
{
while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER);
printf("ReadBlocks Successfullyn");
for(i=0; i< SDBUF_SIZE; i++)
{
printf("%d ",SDBUF_RX[i]);
}
printf("rn");
}
else
{
printf("ReadBlocks Failedn");
}
while (1)
{
}
}
//sdio.c
//此代碼為工程自動(dòng)生成,非用戶(hù)編寫(xiě),這里只做分析
#include "sdio.h"
#include "gpio.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
SD_HandleTypeDef hsd;
/* SDIO init function */
void MX_SDIO_SD_Init(void) //初始化配置
{
hsd.Instance = SDIO; //SDIO句柄,整個(gè)系統(tǒng)中只有這一個(gè)
hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
hsd.Init.BusWide = SDIO_BUS_WIDE_1B; //初始化時(shí)設(shè)置數(shù)據(jù)寬度為1位
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 0;
//HAL_SD_Init()函數(shù)內(nèi)部做了很多事去識(shí)別SD卡,具體的卡識(shí)別代碼分析在下方
if (HAL_SD_Init(&hsd) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
//初始化結(jié)束后重新配置數(shù)據(jù)寬度為4位
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
//卡識(shí)別代碼如下
HAL_StatusTypeDef HAL_SD_InitCard(SD_HandleTypeDef *hsd)
{
uint32_t errorstate = HAL_SD_ERROR_NONE;
SD_InitTypeDef Init;
/* Default SDIO peripheral configuration for SD card initialization */
//完成卡識(shí)別
Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
Init.BusWide = SDIO_BUS_WIDE_1B;
Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
Init.ClockDiv = SDIO_INIT_CLK_DIV;
//SDIO_CK卡識(shí)別階段要求時(shí)鐘小于400KHz,宏定義
//SDIO_CK計(jì)算公式:SDIO_CK=SDIOCLK/(2+CLKDIV)
/* SDIO Initialization Frequency (400KHz max) */
/*#define SDIO_INIT_CLK_DIV ((uint8_t)0x76)*/
/* Initialize SDIO peripheral interface with default configuration */
SDIO_Init(hsd- >Instance, Init);
/* Disable SDIO Clock */
__HAL_SD_DISABLE(hsd);
/* Set Power State to ON 對(duì)SD卡進(jìn)行上電 */
SDIO_PowerState_ON(hsd- >Instance);
/* Enable SDIO Clock */
__HAL_SD_ENABLE(hsd);
/* Required power up waiting time before starting the SD initialization
sequence */
HAL_Delay(2U);
/* Identify card operating voltage */
errorstate = SD_PowerON(hsd);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd- >State = HAL_SD_STATE_READY;
hsd- >ErrorCode |= errorstate;
return HAL_ERROR;
}
/* Card initialization */
errorstate = SD_InitCard(hsd);
if(errorstate != HAL_SD_ERROR_NONE)
{
hsd- >State = HAL_SD_STATE_READY;
hsd- >ErrorCode |= errorstate;
return HAL_ERROR;
}
return HAL_OK;
}
- SD卡DMA模式操作實(shí)例
當(dāng)SD卡中有大量的音視頻需要讀取時(shí),整個(gè)過(guò)程需要CPU干預(yù),這樣CPU的利用率就會(huì)降低,因此大量數(shù)據(jù)的傳輸最好啟用DMA。
實(shí)驗(yàn)內(nèi)容:向SD卡寫(xiě)入數(shù)據(jù)后讀出。
實(shí)驗(yàn)步驟:工程的時(shí)鐘配置和SDIO配置與普通模式相同,只有一點(diǎn)不同需要打開(kāi)SDIO的全局中斷,因?yàn)镾DIO發(fā)送與接收完成后都需要中斷去生成DMA請(qǐng)求。設(shè)置SDIO全局中斷優(yōu)先級(jí)更高一些,因?yàn)樗鼉?nèi)部還有很多其他中斷,發(fā)生錯(cuò)誤時(shí)更需要處理。
配置DMA
編寫(xiě)代碼:
//mian.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "dma.h"
#include "sdio.h"
#include "usart.h"
#include "gpio.h"
#define SDBUF_SIZE 1024
uint8_t SDBUF_TX[SDBUF_SIZE],SDBUF_RX[SDBUF_SIZE];//數(shù)據(jù)傳輸?shù)腷uf,一個(gè)用于傳輸,一個(gè)用于接收
//定義全局變量,最好不定義局部變量,防止因過(guò)大造成棧溢出
uint8_t DMA_SEND_OK, DMA_RCV_OK;
int main(void)
{
uint32_t i;
HAL_SD_CardInfoTypeDef pCardInfo;//定義結(jié)構(gòu)體用來(lái)接收卡信息
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
printf("this is sd testn");
//卡識(shí)別結(jié)束后就可以調(diào)用HAL_SD_GetCardInfo()函數(shù)獲取卡信息并打印
HAL_SD_GetCardInfo(&hsd, &pCardInfo);
printf("pCardInfo.CardType = %un",pCardInfo.CardType);
printf("pCardInfo.CardVersion = %un",pCardInfo.CardVersion);//版本
printf("pCardInfo.BlockNbr = %un",pCardInfo.BlockNbr);//SD卡塊數(shù)
printf("pCardInfo.BlockSize = %un",pCardInfo.BlockSize);//每一塊大小
/*------------------- SD DMA 寫(xiě)測(cè)試-------------------------------------*/
memset(SDBUF_TX, 0x2, SDBUF_SIZE );
DMA_SEND_OK = 0;//設(shè)置發(fā)送完成標(biāo)志位為0,完成時(shí)為1
/**
//函數(shù)原型
*HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData,
uint32_t BlockAdd, uint32_t NumberOfBlocks)
* @param hsd Pointer to SD handle
* @param pData Pointer to the buffer that will contain the data to transmit
* @param BlockAdd Block Address where data will be written 從哪個(gè)塊開(kāi)始寫(xiě)
* @param NumberOfBlocks Number of blocks to write寫(xiě)幾個(gè)塊
* @retval HAL status
*/
if( HAL_SD_WriteBlocks_DMA(&hsd, SDBUF_TX, 0, 1) == HAL_OK )
{
//等待DMA傳輸完成,并且SD卡狀態(tài)為傳輸狀態(tài)
while( (DMA_SEND_OK ==0 ) || (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER));
printf("WriteBlocks Successfullyn");
for(i=0; i< SDBUF_SIZE; i++)
{
printf("%d ",SDBUF_TX[i]);
}
printf("rn");
}
else
{
printf("WriteBlocks Failedn");
}
/*------------------- SD DMA 讀測(cè)試-------------------------------------*/
DMA_RCV_OK = 0;//設(shè)置讀取完成標(biāo)志位為0,完成時(shí)為1
if(HAL_SD_ReadBlocks_DMA(&hsd, SDBUF_RX, 0, 1) == HAL_OK)
{
while( (DMA_RCV_OK ==0) || (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER));
printf("ReadBlocks Successfullyn");
for(i=0; i< SDBUF_SIZE; i++)
{
printf("%d ",SDBUF_RX[i]);
}
printf("rn");
}
else
{
printf("ReadBlocks Failedn");
}
while (1){}
}
//sdio.c
extern uint8_t DMA_SEND_OK, DMA_RCV_OK;
//發(fā)送完成中斷處理
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
DMA_SEND_OK = 1;
}
//接收完成中斷處理
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
DMA_RCV_OK = 1;
}
-
控制器
+關(guān)注
關(guān)注
112文章
16039瀏覽量
176746 -
嵌入式系統(tǒng)
+關(guān)注
關(guān)注
41文章
3534瀏覽量
128995 -
適配器
+關(guān)注
關(guān)注
8文章
1901瀏覽量
67786 -
SD卡
+關(guān)注
關(guān)注
2文章
555瀏覽量
63685 -
FIFO存儲(chǔ)
+關(guān)注
關(guān)注
0文章
103瀏覽量
5953
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論