1、準(zhǔn)備材料
正點(diǎn)原子stm32f407探索者開發(fā)板V2.4
STM32CubeMX軟件(Version 6.10.0)
keil μVision5 IDE(MDK-Arm)
ST-LINK/V2驅(qū)動
邏輯分析儀nanoDLA
野火DAP仿真器
XCOM V2.6串口助手
2、實(shí)驗(yàn)?zāi)繕?biāo)
使用STM32CubeMX軟件配置STM32F407開發(fā)板SDIO讀寫4線SD卡,實(shí)現(xiàn)輪詢方式讀寫SD卡、以中斷方式讀取SD卡和以DMA方式讀取SD卡
3、輪詢方式讀取SD卡流程
3.0、前提知識
安全數(shù)碼卡(Secure Digital Memory Card),簡稱SD卡,是嵌入式設(shè)備上常用的一種存儲介質(zhì),通??梢詫D卡分為標(biāo)準(zhǔn)SD卡、miniSD卡和microSD卡(TF卡)三種類型,每種卡形狀大小不一,除標(biāo)準(zhǔn)SD卡卡身上擁有一個寫保護(hù)開關(guān)外,其他的功能三張卡一致,如今miniSD卡正逐漸被microSD卡所取代,如下圖所示為三種不同類型SD卡形狀 (注釋1)
按照SD卡容量大小的不同可以將其分為SD、SDHC、SDXC等型號,按照SD卡讀寫機(jī)制速度的不同又可以將其分為Standard、High-speed、UHS-I等型號,具體如下表所示
STM32F407提供了一個SDIO接口可以直接通過HAL庫來驅(qū)動1/4位總線寬度的SD卡或1/4/8位總線寬度的多媒體卡,其完全兼容SD卡規(guī)范版本2.0,但只支持高速SD卡,也即與SD卡進(jìn)行數(shù)據(jù)傳輸最大速度為25MHz
SDIO由APB2接口和SDIO適配器兩部分組成,SDIO適配器提供了驅(qū)動SD/MMC卡的全部功能,APB2接口則可以訪問SDIO適配器寄存器在適當(dāng)時候向內(nèi)核發(fā)起中斷/DMA請求
SDIO適配器由48MHz的SDIOCLK驅(qū)動,根據(jù)SDIOCLK時鐘頻率、 SDIO Clock divider bypass 參數(shù)和 SDIOCLK clock divide factor 參數(shù)就可以確定與SD卡通信時SDIO_CLK的時鐘頻率,當(dāng)時鐘分頻器旁路使能時,SDIO_CLK=SDIOCLK;當(dāng)時鐘分頻器旁路不使能時,SDIO_CLK=SDIOCLK / (2+時鐘分頻因子);
根據(jù)上面的描述,由于STM32F407的SDIO只支持高速SD卡,因此時鐘分頻器旁路常常不使能,這樣當(dāng)時鐘分頻因子為0時,SDIO_CLK則達(dá)到最大速度48MHz / 2 = 24Mhz,但在實(shí)際的使用中往往稍微降低該時鐘頻率,否則可能會出現(xiàn)讀寫SD卡失敗的現(xiàn)象
另外值得提醒的是SD卡初始化的時候應(yīng)該以不超過400KHz的速率,1位總線寬度進(jìn)行初始化,否則將初始化失敗
如下圖所示為STM32F407內(nèi)部的SDIO接口結(jié)構(gòu)框圖 (注釋2)
筆者使用的開發(fā)板上SD卡槽設(shè)計為了4位總線寬度,在硬件設(shè)計時需要注意MCU與SD卡通信的1/4根數(shù)據(jù)線SDIO_D0/1/2/3和命令線SDIO_CMD均需外部上拉,硬件原理圖如下圖所示
3.1、CubeMX相關(guān)配置
3.1.0、工程基本配置
打開STM32CubeMX軟件,單擊ACCESS TO MCU SELECTOR選擇開發(fā)板MCU(選擇你使用開發(fā)板的主控MCU型號),選中MCU型號后單擊頁面右上角Start Project開始工程,具體如下圖所示
開始工程之后在配置主頁面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具體如下圖所示
詳細(xì)工程建立內(nèi)容讀者可以閱讀“STM32CubeMX教程1 工程建立”
3.1.1、時鐘樹配置
當(dāng)在STM32CubeMX中啟用SDIO功能后,時鐘樹中48MHz時鐘便可以進(jìn)行調(diào)節(jié),該時鐘一般如其名字一樣配置為48MHz即可,也即將Main PLL(主鎖相環(huán))的Q參數(shù)調(diào)節(jié)為7即可,其他HCLK、PCLK1和PCLK2時鐘仍然設(shè)置為STM32F407能達(dá)到的最高時鐘頻率,具體如下圖所示
3.1.2、外設(shè)參數(shù)配置
本實(shí)驗(yàn)需要初始化開發(fā)板上WK_UP、KEY2、KEY1和KEY0用戶按鍵,具體配置步驟請閱讀“STM32CubeMX教程3 GPIO輸入 - 按鍵響應(yīng)”
本實(shí)驗(yàn)需要初始化USART1作為輸出信息渠道,具體配置步驟請閱讀“STM32CubeMX教程9 USART/UART 異步通信”
單擊Pinout & Configuration頁面左邊功能分類欄目Connectivity/SDIO,將其模式選擇為4位寬總線SD卡
Clock transition on which the bit capture is made (時鐘跳變沿捕獲數(shù)據(jù)配置):數(shù)據(jù)捕獲邊沿設(shè)置,可設(shè)置為上升沿/下降沿
SDIO Clock divider bypass (時鐘分頻器旁路使能):使能該參數(shù)時,SDIO_CLK=SDIOCLK;否則SDIO_CLK頻率由時鐘分頻因子決定
SDIO Clock output enable when the bus is idle (空閑模式時鐘輸出使能):節(jié)能模式,此實(shí)驗(yàn)不使能
SDIO hardware flow control (硬件流控):設(shè)置是否使能SDIO的硬件流控,此處不使能
SDIOCLK clock divide factor (時鐘分頻因子):當(dāng)不使能時鐘分頻器旁路時,SDIO_CLK=SDIOCLK / (2+時鐘分頻因子)
SDIO驅(qū)動4位寬總線SD卡的參數(shù)配置大多按照默認(rèn)參數(shù)配置即可,但是要注意SD卡讀寫頻率過高可能會導(dǎo)致讀寫失敗,因此這里設(shè)置SD_CLK頻率為8MHz,另外需要注意默認(rèn)的SDIO復(fù)用引腳和開發(fā)板上的實(shí)際控制SD的引腳是否一致,具體配置如下圖所示
3.1.3、外設(shè)中斷配置
輪詢方式讀寫SD卡無需配置中斷
3.2、生成代碼
3.2.0、配置Project Manager頁面
單擊進(jìn)入Project Manager頁面,在左邊Project分欄中修改工程名稱、工程目錄和工具鏈,然后在Code Generator中勾選“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后單擊頁面右上角GENERATE CODE生成工程,具體如下圖所示
詳細(xì)Project Manager配置內(nèi)容讀者可以閱讀“STM32CubeMX教程1 工程建立”實(shí)驗(yàn)3.4.3小節(jié)
3.2.1、外設(shè)初始化調(diào)用流程
在main.c文件main()函數(shù)中調(diào)用MX_SDIO_SD_Init()對SDIO參數(shù)配置,并調(diào)用HAL_SD_Init()函數(shù)對SD卡初始化,最后將SD卡切換到4位寬總線模式
在stm32f4xx_hal_sd.c文件HAL_SD_Init()中調(diào)用HAL_SD_MspInit()函數(shù)對SDIO時鐘使能和所使用到的引腳功能復(fù)用,如果配置了中斷或DMA,該函數(shù)中還會相應(yīng)的出現(xiàn)NVIC/DMA相關(guān)配置,最后在真正的SD卡初始化函數(shù)HAL_SD_InitCard()中對SD卡初始化完畢
具體外設(shè)初始化函數(shù)調(diào)用流程如下圖所示
初始化配置中時鐘分頻因子為4,SD_CLK=8MHz,為什么SD卡還可以初始化成功?
這里讀者需要搞清楚真正對SD卡初始化時使用的參數(shù)配置是不是我們設(shè)置的參數(shù),上面提到真正的SD卡初始化函數(shù)為HAL_SD_InitCard(),進(jìn)入該函數(shù)發(fā)現(xiàn)實(shí)際初始化SD卡時用到的并不是用戶配置的參數(shù),而是使用的默認(rèn)初始化參數(shù),這里時鐘分頻因子被設(shè)置為了0x76,也即118,根據(jù)上面提到的公式計算可知48MHz / (118 + 2) = 400KHz,滿足SD卡的初始化頻率,具體如下圖所示
3.2.2、外設(shè)中斷調(diào)用流程
輪詢方式讀寫SD卡無配置中斷
3.2.3、添加其他必要代碼
筆者使用的STM32CubeMX版本為6.10.0,在生成的SDIO初始化函數(shù)MX_SDIO_SD_Init()中需要將參數(shù)配置中的SD卡數(shù)據(jù)總線寬度從默認(rèn)的4位手動修改為1位(STM32CubeMX軟件BUG?),在SD卡初始化時應(yīng)該以不超過400KHz的速率,1位總線寬度進(jìn)行初始化,如果不修改這里SD卡將無法成功初始化,如下圖所示
在sdio.c中添加SD卡讀、寫、擦除和輸出SD卡信息測試函數(shù)
/*顯示SD卡的信息*/
void SDCard_ShowInfo(void)
{
//SD卡信息結(jié)構(gòu)體變量
HAL_SD_CardInfoTypeDef cardInfo;
HAL_StatusTypeDef res = HAL_SD_GetCardInfo(&hsd, &cardInfo);
if(res!=HAL_OK)
{
printf("HAL_SD_GetCardInfo() error\r\n");
return;
}
printf("\r\n*** HAL_SD_GetCardInfo() info ***\r\n");
printf("Card Type= %d\r\n", cardInfo.CardType);
printf("Card Version= %d\r\n", cardInfo.CardVersion);
printf("Card Class= %d\r\n", cardInfo.Class);
printf("Relative Card Address= %d\r\n", cardInfo.RelCardAdd);
printf("Block Count= %d\r\n", cardInfo.BlockNbr);
printf("Block Size(Bytes)= %d\r\n", cardInfo.BlockSize);
printf("LogiBlockCount= %d\r\n", cardInfo.LogBlockNbr);
printf("LogiBlockSize(Bytes)= %d\r\n", cardInfo.LogBlockSize);
printf("SD Card Capacity(MB)= %d\r\n", cardInfo.BlockNbr>>1>>10);
}
//獲取SD卡當(dāng)前狀態(tài)
void SDCard_ShowStatus(void)
{
//SD卡狀態(tài)結(jié)構(gòu)體變量
HAL_SD_CardStatusTypeDef cardStatus;
HAL_StatusTypeDef res = HAL_SD_GetCardStatus(&hsd, &cardStatus);
if(res!=HAL_OK)
{
printf("HAL_SD_GetCardStatus() error\r\n");
return;
}
printf("\r\n*** HAL_SD_GetCardStatus() info ***\r\n");
printf("DataBusWidth= %d\r\n", cardStatus.DataBusWidth);
printf("CardType= %d\r\n", cardStatus.CardType);
printf("SpeedClass= %d\r\n", cardStatus.SpeedClass);
printf("AllocationUnitSize= %d\r\n", cardStatus.AllocationUnitSize);
printf("EraseSize= %d\r\n", cardStatus.EraseSize);
printf("EraseTimeout= %d\r\n", cardStatus.EraseTimeout);
}
/*SD卡擦除測試*/
void SDCard_EraseBlocks(void)
{
uint32_t BlockAddrStart=0;
uint32_t BlockAddrEnd=10;
printf("\r\n*** Erasing blocks ***\r\n");
if(HAL_SD_Erase(&hsd, BlockAddrStart, BlockAddrEnd)==HAL_OK)
printf("Erasing blocks,OK\r\n");
else
printf("Erasing blocks,fail\r\n");
HAL_SD_CardStateTypeDef cardState=HAL_SD_GetCardState(&hsd);
printf("GetCardState()= %d\r\n", cardState);
while(cardState != HAL_SD_CARD_TRANSFER)
{
HAL_Delay(1);
cardState=HAL_SD_GetCardState(&hsd);
}
printf("Blocks 0-10 is erased.\r\n");
}
/*SD卡寫入測試函數(shù)*/
void SDCard_TestWrite(void)
{
printf("\r\n*** Writing blocks ***\r\n");
// BLOCKSIZE為512,在stm32f4xx_hal_sd.h中被定義
uint8_t pData[BLOCKSIZE]="Hello, welcome to UPC\0";
uint32_t BlockAddr=5;
uint32_t BlockCount=1;
uint32_t TimeOut=1000;
if(HAL_SD_WriteBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut) == HAL_OK)
{
printf("Write to block 5, OK\r\n");
printf("The string is: %s\r\n", pData);
}
else
{
printf("Write to block 5, fail ***\r\n");
return;
}
for(uint16_t i=0;i<BLOCKSIZE; i++)
pData[i]=i;
BlockAddr=6;
if(HAL_SD_WriteBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut) == HAL_OK)
{
printf("Write block 6, OK\r\n");
printf("Data in [10:15] is: ");
for (uint16_t j=11; j<=15;j++)
{
printf("%d,", pData[j]);
}
printf("\r\n");
}
else
printf("Write to block 6, fail ***\r\n");
}
/*SD卡讀取測試函數(shù)*/
void SDCard_TestRead(void)
{
printf("\r\n*** Reading blocks ***\r\n");
uint8_t pData[BLOCKSIZE];
uint32_t BlockAddr=5;
uint32_t BlockCount=1;
uint32_t TimeOut=1000;
if(HAL_SD_ReadBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut) == HAL_OK)
//if(HAL_SD_ReadBlocks_IT(&hsd,pData,BlockAddr,BlockCount) == HAL_OK)
{
printf("Read block 5, OK\r\n");
printf("The string is: %s\r\n", pData);
}
else
{
printf("Read block 5, fail ***\r\n");
return;
}
BlockAddr=6;
if(HAL_SD_ReadBlocks(&hsd,pData,BlockAddr,BlockCount,TimeOut)== HAL_OK)
//if(HAL_SD_ReadBlocks_IT(&hsd,pData,BlockAddr,BlockCount) == HAL_OK)
{
printf("Read block 6, OK\r\n");
printf("Data in [10:15] is: ");
for (uint16_t j=11; j<=15;j++)
{
printf("%d,", pData[j]);
}
printf("\r\n");
}
}
在sdio.h中聲明定義的這些測試函數(shù)
/*在sdio.h中聲明*/
void SDCard_TestRead(void);
void SDCard_TestWrite(void);
void SDCard_ShowInfo(void);
void SDCard_EraseBlocks(void);
在main.c文件主循環(huán)中添加按鍵邏輯控制程序,WK_UP按鍵按下輸出SD卡信息,KEY2按鍵按下擦除SD卡塊0-10,KEY1按鍵按下測試SD卡寫功能,KEY0按鍵按下測試SD卡讀功能
具體源代碼如下所示
/*WK_UP按鍵按下*/
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == GPIO_PIN_SET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin) == GPIO_PIN_SET)
{
SDCard_ShowInfo();
while(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin));
}
}
/*KEY2按鍵按下*/
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == GPIO_PIN_RESET)
{
SDCard_EraseBlocks();
while(!HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin));
}
}
/*KEY1按鍵按下*/
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == GPIO_PIN_RESET)
{
SDCard_TestWrite();
while(!HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin));
}
}
/*KEY0按鍵按下*/
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == GPIO_PIN_RESET)
{
HAL_Delay(50);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == GPIO_PIN_RESET)
{
SDCard_TestRead();
while(!HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin));
}
}
4、燒錄驗(yàn)證
燒錄程序,開發(fā)板復(fù)位后按下WK_UP按鍵會輸出SD卡信息,按下KEY2按鍵會擦除SD卡的塊0-10數(shù)據(jù),按下KEY0按鍵會讀取SD卡塊5和塊6的數(shù)據(jù),按下KEY1按鍵會寫入一段字符串到SD卡塊5,寫入塊6從1-256整形數(shù)字,具體串口輸出信息如下圖所示
5、中斷方式讀取SD卡流程簡述
5.1、CubeMX相關(guān)配置
工程、時鐘樹、外設(shè)參數(shù)等配置與輪詢方式讀取SD卡一致,中斷方式讀取SD卡只需要在CubeMX軟件中啟動SDIO的全局中斷
在Pinout & Configuration頁面左邊System Core/NVIC中勾選SDIO全局中斷,然后選擇合適的中斷優(yōu)先級即可,如下圖所示
5.2、生成代碼
修改STM32CubeMX工程重新生成工程代碼后,讀者應(yīng)注意再次手動修改MX_SDIO_SD_Init()函數(shù)中SD卡數(shù)據(jù)總線寬度從默認(rèn)的4位手動修改為1位
在sdio.c中增加以中斷方式讀寫SD卡的測試函數(shù),具體代碼如下所示
/*SD卡中斷寫入測試函數(shù)*/
void SDCard_TestWrite_IT(void)
{
printf("\r\n*** IT Writing blocks ***\r\n");
uint32_t BlockCount=1;
uint16_t BlockAddr=5;
HAL_SD_WriteBlocks_IT(&hsd, TX, BlockAddr, BlockCount);
}
/*SD卡中斷讀取測試函數(shù)*/
void SDCard_TestRead_IT(void)
{
printf("\r\n*** IT Reading blocks ***\r\n");
uint32_t BlockCount=1;
uint16_t BlockAddr=5;
HAL_SD_ReadBlocks_IT(&hsd, RX, BlockAddr, BlockCount);
}
在sdio.c中新增加SD卡Tx/Rx傳輸完成回調(diào)函數(shù)HAL_SD_TxCpltCallback()和HAL_SD_RxCpltCallback(),具體代碼如下所示
/*SD Tx傳輸完成回調(diào)*/
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
printf("IT Write to block 5, OK\r\n");
printf("The string is: %s\r\n", TX);
}
/*SD Rx傳輸完成回調(diào)*/
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
printf("IT Read block 5, OK\r\n");
printf("The string is: %s\r\n", RX);
}
在sdio.c中定義全部變量發(fā)送緩存數(shù)組TX和接收緩存數(shù)組RX,并在sdio.h中聲明修改后的中斷方式的SD卡寫入測試函數(shù)和SD卡讀取測試函數(shù),源代碼如下
/*sdio.c中定義的發(fā)送、接收緩存數(shù)組*/
uint8_t TX[BLOCKSIZE] = "Hello, welcome to UPC\0";
uint8_t RX[BLOCKSIZE];
/*sdio.h中對函數(shù)聲明*/
void SDCard_TestRead_IT(void);
void SDCard_TestWrite_IT(void);
最后在main.c文件主循環(huán)中實(shí)現(xiàn)與輪詢讀寫SD時一致的按鍵邏輯程序,并用修改后的以中斷方式讀寫SD卡的函數(shù)替換以輪詢方式讀寫SD卡的函數(shù)即可
5.3、燒錄驗(yàn)證
燒錄程序,開發(fā)板復(fù)位后按下WK_UP按鍵會輸出SD卡信息,按下KEY2按鍵會擦除SD卡的塊0-10數(shù)據(jù),與輪詢方式讀寫SD卡時現(xiàn)象一致
按下KEY0按鍵以中斷方式讀取SD卡的塊5數(shù)據(jù),讀取完成后會進(jìn)入Rx傳輸完成回調(diào)中,在該回調(diào)函數(shù)中會從串口輸出讀取到的SD卡塊5的數(shù)據(jù)
按下KEY1按鍵會以中斷方式寫入一段字符串到SD卡塊5,寫入完成后會進(jìn)入Tx傳輸完成回調(diào)中,在該回調(diào)函數(shù)中會從串口輸出寫入到SD卡塊5中的數(shù)據(jù)
具體串口輸出信息如下圖所示
6、DMA方式讀取SD卡流程簡述
6.1、CubeMX相關(guān)配置
工程、時鐘樹、外設(shè)參數(shù)等配置與輪詢方式讀取SD卡一致,以DMA方式讀取SD卡只需要在CubeMX軟件中增加SDIO的DMA請求即可
在Pinout & Configuration頁面單擊Connectivity/SDIO頁面,在Configuration配置頁面中點(diǎn)擊DMA Settings選項(xiàng)卡對SDIO的DMA進(jìn)行配置,單擊ADD增加SDIO的RX/TX兩個DMA請求,SDIO的兩個DMA請求除了內(nèi)存地址遞增可以設(shè)置外,其他的包括Mode、Use Fifo、Data Width和Burst Size等參數(shù)都不可以設(shè)置
對DMA參數(shù)不理解的可以閱讀”STM32CubeMX教程12 DMA 直接內(nèi)存讀取“實(shí)驗(yàn),SDIO的具體DMA配置參數(shù)如下圖所示
在System Core/NVIC中勾選SDIO全局中斷、DMA2 stream3 全局中斷和 DMA2 stream6 全局中斷,然后選擇合適的中斷優(yōu)先級即可,如下圖所示
6.2、生成代碼
修改STM32CubeMX工程重新生成工程代碼后,讀者應(yīng)注意再次手動修改MX_SDIO_SD_Init()函數(shù)中SD卡數(shù)據(jù)總線寬度從默認(rèn)的4位手動修改為1位
在sdio.c中增加以DMA方式讀寫SD卡的測試函數(shù),具體代碼如下所示
/*SD卡DMA寫入測試函數(shù)*/
void SDCard_TestWrite_DMA(void)
{
printf("\r\n*** DMA Writing blocks ***\r\n");
uint32_t BlockCount=1;
uint16_t BlockAddr=6;
for(uint16_t i=0;i<BLOCKSIZE; i++)
TX[i]=i;
HAL_SD_WriteBlocks_DMA(&hsd, TX, BlockAddr, BlockCount);
}
/*SD卡DMA讀取測試函數(shù)*/
void SDCard_TestRead_DMA(void)
{
printf("\r\n*** DMA Reading blocks ***\r\n");
uint32_t BlockCount=1;
uint16_t BlockAddr=6;
HAL_SD_ReadBlocks_DMA(&hsd, RX, BlockAddr, BlockCount);
}
在sdio.h中對增加的函數(shù)聲明
/*sdio.h中對函數(shù)聲明*/
void SDCard_TestWrite_DMA(void);
void SDCard_TestRead_DMA(void);
DMA的回調(diào)函數(shù)使用的是外設(shè)的中斷回調(diào)函數(shù)
當(dāng)啟用了SDIO TX DMA請求和SDIO全局中斷,并以 HAL_SD_WriteBlocks_DMA() 寫入SD卡塊數(shù)據(jù)完成之后,會調(diào)用傳輸完成回調(diào) HAL_SD_TxCpltCallback()
當(dāng)啟用了SDIO RX DMA請求和SDIO全局中斷,并以 HAL_SD_ReadBlocks_DMA() 從SD卡塊讀取數(shù)據(jù)完畢之后,會調(diào)用讀取完成回調(diào)函數(shù) HAL_SD_RxCpltCallback()
故直接重新實(shí)現(xiàn)HAL_SD_RxCpltCallback/HAL_SD_TxCpltCallback兩個函數(shù)即可,源代碼如下所示
/*DMA Tx傳輸完成回調(diào)*/
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
{
printf("DMA Write to block 6, OK\r\n");
printf("Data in [10:15] is: ");
for (uint16_t j=10; j<=15;j++)
{
printf("%d,", TX[j]);
}
printf("\r\n");
}
/*DMA Rx傳輸完成回調(diào)*/
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
{
printf("DMA Read block 6, OK\r\n");
printf("Data in [10:15] is: ");
for (uint16_t j=10; j<=15;j++)
{
printf("%d,", RX[j]);
}
printf("\r\n");
}
最后在main.c文件主循環(huán)中實(shí)現(xiàn)與輪詢讀寫SD時一致的按鍵邏輯程序,并用修改后的以DMA方式讀寫SD卡的函數(shù)替換以中斷方式讀寫SD卡的函數(shù)即可
6.3、實(shí)驗(yàn)現(xiàn)象
燒錄程序,開發(fā)板復(fù)位后按下WK_UP按鍵會輸出SD卡信息,按下KEY2按鍵會擦除SD卡的塊0-10數(shù)據(jù),與輪詢方式讀寫SD卡時現(xiàn)象一致
按下KEY0按鍵以DMA的方式讀取SD卡塊6數(shù)據(jù),讀取完成后會進(jìn)入Rx傳輸完成回調(diào)中,在該回調(diào)函數(shù)中會從串口輸出讀取到的SD卡塊6的數(shù)據(jù)
按下KEY1按鍵會以DMA的方式寫入1-256的數(shù)字到SD卡塊6(一個字節(jié)寫入一個數(shù)字),寫入完成后會進(jìn)入Tx傳輸完成回調(diào)中,在該回調(diào)函數(shù)中會從串口輸出寫入到SD卡塊6中的數(shù)據(jù)
具體串口輸出信息如下圖所示
7、常用函數(shù)
/*讀塊*/
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
/*寫塊*/
HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
/*擦除塊*/
HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd)
/*獲取SD卡信息*/
HAL_StatusTypeDef HAL_SD_GetCardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypeDef *pCardInfo)
/*獲取SD卡狀態(tài)*/
HAL_StatusTypeDef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypeDef *pStatus)
/*以中斷方式讀塊*/
HAL_StatusTypeDef HAL_SD_ReadBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
/*以中斷方式寫塊*/
HAL_StatusTypeDef HAL_SD_WriteBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
/*以DMA方式讀塊*/
HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
/*以DMA方式寫塊*/
HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks)
/*SD卡Tx傳輸完成回調(diào)*/
void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd)
/*SD卡Rx傳輸完成回調(diào)*/
void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd)
8、注釋詳解
注釋1:圖片來源自 維基百科-SD卡
注釋2:圖片來源自 STM32F407中文參考手冊 RM009文章來源:http://www.zghlxwxcb.cn/news/detail-825225.html
參考資料
STM32Cube高效開發(fā)教程(高級篇)文章來源地址http://www.zghlxwxcb.cn/news/detail-825225.html
到了這里,關(guān)于STM32CubeMX教程27 SDIO - 讀寫SD卡的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!