日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

SDIO读写SD卡

發(fā)布時(shí)間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SDIO读写SD卡 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

平臺(tái):STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口線

工程介紹:主要文件在USER組中,bsp_sdio_sdcard.c,bsp_sdio_sdcard.h和main.c,另外FatFs是用來后面移植文件系統(tǒng)使用的,對(duì)于本節(jié)內(nèi)容暫時(shí)不需要。bsp_sdio_sdcard.c和bsp_sdio_sdcard.h文件主要參考教材《STM32庫(kù)開發(fā)實(shí)戰(zhàn)指南——基于STM32F03》。教材中部分省略內(nèi)容來自于其他網(wǎng)友總結(jié),在此表示感謝。

本文想大概講一下SD卡讀寫實(shí)驗(yàn)的具體步驟,以及最重要的是一個(gè)細(xì)節(jié)問題,它使我在這個(gè)問題上耗了兩天的時(shí)間。

大概流程如下:

1.硬件設(shè)計(jì):

因?yàn)樵谠撈脚_(tái)的板子上已經(jīng)存在了一個(gè)SD卡接口,因此,不需要額外的連線,只需要一條串口連接線連接到電腦上輸出調(diào)試信息即可。

2.軟件設(shè)計(jì):

操作的大致流程:

1》初始化相關(guān)的GPIO及SDIO外設(shè);

2》配置SDIO基本通信環(huán)境進(jìn)入卡識(shí)別模式,通過幾個(gè)命令處理得到卡類型;

3》如果是可用卡就進(jìn)入數(shù)據(jù)傳輸模式,接下來可以進(jìn)行讀寫和擦差操作。

具體的步驟:

因?yàn)楣俜焦碳?kù)有實(shí)現(xiàn)的案例,所以我們不妨”拿來主義“。其實(shí)bsp_sdio_sdcard.c和bsp_sdio_sdcard.h就是對(duì)stm32_eval_sdio_sd.c和stm32_eval_sdio_sd.h文件的修改和借鑒。我是直接把名字改了,然后在源文件的基礎(chǔ)上做了修改。

2.1 GPIO的初始化和DMA配置(以下函數(shù)位于bsp_sdio_sdcard.c和bsp_sdio_sdcard.h文件中,其大部分內(nèi)容來自于上面固件庫(kù)的例程stm32_eval_sdio_sd.c和stm32_eval_sdio_sd.h的修改和添加

//宏定義 //SDIO_FIOF地址=SDIO地址+0x80至SDIO地址+0xfc #define SDIO_FIFO_ADDRESS ((uint32_t) 0x40018080)//SDIO初始化時(shí)鐘頻率,最大400kHz #define SDIO_INIT_CLK_DIV ((uint8_t) 0xB2)//數(shù)據(jù)傳輸時(shí)鐘頻率,最大25MHz #define SDIO_TRANSFER_CLK_DIV ((uint8_t) 0x02)//數(shù)據(jù)讀寫速率//SDIO傳輸使用的模式,可選DMA模式或者普通模式 #define SD_DMA_MODE ((uint32_t) 0x00000000) //#define SD_POLLING_MODE ((uint32_t) 0x00000002)//SD卡檢測(cè)GPIO引腳 #define SD_DETECT_GPIO_PORT GPIOC #define SD_DETECT_PIN GPIO_Pin_13

//GPIO初始化,開啟時(shí)鐘 static void GPIO_Configuration() {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);//開啟時(shí)鐘//配置PC8/9/10/11/12引腳(D0/1/2/3和CLK)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//設(shè)置復(fù)用模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);//配置PD2為CMD引腳 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_Init(GPIOD, &GPIO_InitStructure);//使能SDIO AHB時(shí)鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);//使能DMA時(shí)鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); } //DMA傳輸配置,接收數(shù)據(jù) void SD_DMA_RxConfig(uint32_t* BufferDST, uint32_t BufferSize) {DMA_InitTypeDef DMA_InitStructure;//清除DMA標(biāo)志位DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);//配置前禁止DMADMA_Cmd(DMA2_Channel4, DISABLE);//DMA傳輸配置//外設(shè)地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;//目標(biāo)地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferDST;//外設(shè)為源地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//除以4,把字轉(zhuǎn)換成字節(jié)單位DMA_InitStructure.DMA_BufferSize = BufferSize / 4;//外設(shè)地址不增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//存儲(chǔ)目標(biāo)地址DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//外設(shè)數(shù)據(jù)大小為字DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//存儲(chǔ)數(shù)據(jù)大小DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//不循環(huán),一次DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//通道優(yōu)先級(jí)為高DMA_InitStructure.DMA_Priority = DMA_Priority_High;//非存儲(chǔ)器至存儲(chǔ)器模式DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//初始化DMADMA_Init(DMA2_Channel4, &DMA_InitStructure);//使能DMA通道DMA_Cmd(DMA2_Channel4, ENABLE); } //為SDIO發(fā)送數(shù)據(jù)配置DMA2的通道2的請(qǐng)求 void SD_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize) {DMA_InitTypeDef DMA_InitStructure;//清除DMA標(biāo)志位DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);//配置前禁止DMADMA_Cmd(DMA2_Channel4, DISABLE);//DMA傳輸配置//外設(shè)地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;//存儲(chǔ)地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferSRC;//外設(shè)為目的地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//除以4,把字轉(zhuǎn)換成字節(jié)單位DMA_InitStructure.DMA_BufferSize = BufferSize / 4;//外設(shè)地址不增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//存儲(chǔ)目標(biāo)地址DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//外設(shè)數(shù)據(jù)大小為字DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//存儲(chǔ)數(shù)據(jù)大小DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//不循環(huán),一次DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//通道優(yōu)先級(jí)為高DMA_InitStructure.DMA_Priority = DMA_Priority_High;//非存儲(chǔ)器至存儲(chǔ)器模式DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//初始化DMADMA_Init(DMA2_Channel4, &DMA_InitStructure);//使能DMA通道DMA_Cmd(DMA2_Channel4, ENABLE); } //配置中斷控制器 void SDIO_NVIC_Configuration() { NVIC_InitTypeDef NVIC_InitStructure; //優(yōu)先級(jí)組選擇 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //選擇USART的中斷源 NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn; //配置搶占優(yōu)先級(jí) NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //配置子優(yōu)先級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //使能中斷 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //初始化配置 NVIC_Init(&NVIC_InitStructure); } 2.2 SDIO初始化

/*** @brief Initializes the SD Card and put it into StandBy State (Ready for data * transfer).* @param None* @retval SD_Error: SD Card Error code.*/ SD_Error SD_Init(void) {SD_Error errorstatus = SD_OK;//配置SDIO中斷優(yōu)先級(jí)SDIO_NVIC_Configuration();//SDIO外設(shè)底層引腳初始化GPIO_Configuration();//對(duì)SDIO所有的寄存器進(jìn)行復(fù)位SDIO_DeInit();//上電,并進(jìn)行卡識(shí)別流程,確認(rèn)卡的操作電壓errorstatus = SD_PowerON();//識(shí)別不成功if (errorstatus != SD_OK){/*!< CMD Response TimeOut (wait for CMDSENT flag) */return(errorstatus);}//識(shí)別成功,對(duì)SD卡進(jìn)行初始化errorstatus = SD_InitializeCards();//初始化失敗if (errorstatus != SD_OK){/*!< CMD Response TimeOut (wait for CMDSENT flag) */return(errorstatus);}//進(jìn)入數(shù)據(jù)傳輸模式,提高讀寫速度/*!< Configure the SDIO peripheral *//*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) *//*!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz */ SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV; SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;SDIO_Init(&SDIO_InitStructure);if (errorstatus == SD_OK){/*----------------- Read CSD/CID MSD registers ------------------*/errorstatus = SD_GetCardInfo(&SDCardInfo);}if (errorstatus == SD_OK){/*----------------- Select Card --------------------------------*/errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));}if (errorstatus == SD_OK){//為了提高讀寫,開啟四位模式errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);} return(errorstatus); } 與之相對(duì)的還有一個(gè)SD_DeInit()函數(shù),復(fù)位寄存器。

void SD_LowLevel_DeInit(void) {GPIO_InitTypeDef GPIO_InitStructure;/*!< Disable SDIO Clock */SDIO_ClockCmd(DISABLE);/*!< Set Power State to OFF */SDIO_SetPowerState(SDIO_PowerState_OFF);/*!< DeInitializes the SDIO peripheral */SDIO_DeInit();/*!< Disable the SDIO AHB Clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, DISABLE);/*!< Configure PC.08, PC.09, PC.10, PC.11, PC.12 pin: D0, D1, D2, D3, CLK pin */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOC, &GPIO_InitStructure);/*!< Configure PD.02 CMD line */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_Init(GPIOD, &GPIO_InitStructure); } //對(duì)SDIO所有的寄存器進(jìn)行復(fù)位 void SD_DeInit(void) {?SD_LowLevel_DeInit(); } SD_PowerOn()函數(shù)用于查詢卡的工作電壓和時(shí)鐘控制配置,沒有修改。可以看一下。
/*** @brief Enquires cards about their operating voltage and configures * clock controls.* @param None* @retval SD_Error: SD Card Error code.*/ SD_Error SD_PowerON(void) {SD_Error errorstatus = SD_OK;uint32_t response = 0, count = 0, validvoltage = 0;uint32_t SDType = SD_STD_CAPACITY;/*!< Power ON Sequence -----------------------------------------------------*//*!< Configure the SDIO peripheral *//*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) *//*!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz *//*!< SDIO_CK for initialization should not exceed 400 KHz */ SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;SDIO_Init(&SDIO_InitStructure);/*!< Set Power State to ON */SDIO_SetPowerState(SDIO_PowerState_ON);/*!< Enable SDIO Clock */SDIO_ClockCmd(ENABLE);/*!< CMD0: 復(fù)位所有的SD卡,使其進(jìn)入空閑狀態(tài) ---------------------------------------------------*//*!< No CMD response required */SDIO_CmdInitStructure.SDIO_Argument = 0x0;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;//關(guān)閉等待中斷SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;//CPSM在發(fā)送數(shù)據(jù)之前等待數(shù)據(jù)傳輸結(jié)束SDIO_SendCommand(&SDIO_CmdInitStructure);//檢測(cè)是否正確接收到Cmd0errorstatus = CmdError();if (errorstatus != SD_OK){/*!< CMD Response TimeOut (wait for CMDSENT flag) */return(errorstatus);}/*!< CMD8: SEND_IF_COND ----------------------------------------------------*//*!< Send CMD8 to verify SD card interface operating condition *//*!< Argument: - [31:12]: Reserved (shall be set to '0')- [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)- [7:0]: Check Pattern (recommended 0xAA) *//*!< CMD Response: R7 */SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN;SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);//檢查是否接收到該命令errorstatus = CmdResp7Error();if (errorstatus == SD_OK){CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 */SDType = SD_HIGH_CAPACITY;}else{//有相應(yīng)就是SD CARD 2.0,此時(shí)無響應(yīng),代表是1.x或MMC/*!< CMD55 */SDIO_CmdInitStructure.SDIO_Argument = 0x00;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_APP_CMD);}//檢查是SD卡,還是MMC卡,或者是不支持的卡/*!< CMD55 */SDIO_CmdInitStructure.SDIO_Argument = 0x00;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_APP_CMD);/*!< If errorstatus is Command TimeOut, it is a MMC card *//*!< If errorstatus is SD_OK it is a SD card: SD card 2.0 (voltage range mismatch)or SD card 1.x */if (errorstatus == SD_OK){/*!< SD CARD *//*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL)){/*!< SEND CMD55 APP_CMD with RCA as 0 */SDIO_CmdInitStructure.SDIO_Argument = 0x00;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_APP_CMD);if (errorstatus != SD_OK){return(errorstatus);}SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp3Error();if (errorstatus != SD_OK){return(errorstatus);}response = SDIO_GetResponse(SDIO_RESP1);validvoltage = (((response >> 31) == 1) ? 1 : 0);count++;}if (count >= SD_MAX_VOLT_TRIAL){errorstatus = SD_INVALID_VOLTRANGE;return(errorstatus);}if (response &= SD_HIGH_CAPACITY){CardType = SDIO_HIGH_CAPACITY_SD_CARD;}}/*!< else MMC Card */return(errorstatus); } 初始化所有的卡或者單個(gè)卡進(jìn)入就緒狀態(tài),沒有修改。

/*** @brief Intialises all cards or single card as the case may be Card(s) come * into standby state.* @param None* @retval SD_Error: SD Card Error code.*/ SD_Error SD_InitializeCards(void) {SD_Error errorstatus = SD_OK;uint16_t rca = 0x01;if (SDIO_GetPowerState() == SDIO_PowerState_OFF){errorstatus = SD_REQUEST_NOT_APPLICABLE;return(errorstatus);}if (SDIO_SECURE_DIGITAL_IO_CARD != CardType){/*!< Send CMD2 ALL_SEND_CID */SDIO_CmdInitStructure.SDIO_Argument = 0x0;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp2Error();if (SD_OK != errorstatus){return(errorstatus);}CID_Tab[0] = SDIO_GetResponse(SDIO_RESP1);CID_Tab[1] = SDIO_GetResponse(SDIO_RESP2);CID_Tab[2] = SDIO_GetResponse(SDIO_RESP3);CID_Tab[3] = SDIO_GetResponse(SDIO_RESP4);}if ((SDIO_STD_CAPACITY_SD_CARD_V1_1 == CardType) || (SDIO_STD_CAPACITY_SD_CARD_V2_0 == CardType) || (SDIO_SECURE_DIGITAL_IO_COMBO_CARD == CardType)|| (SDIO_HIGH_CAPACITY_SD_CARD == CardType)){/*!< Send CMD3 SET_REL_ADDR with argument 0 *//*!< SD Card publishes its RCA. */SDIO_CmdInitStructure.SDIO_Argument = 0x00;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp6Error(SD_CMD_SET_REL_ADDR, &rca);if (SD_OK != errorstatus){return(errorstatus);}}if (SDIO_SECURE_DIGITAL_IO_CARD != CardType){RCA = rca;/*!< Send CMD9 SEND_CSD with argument as card's RCA */SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16);SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp2Error();if (SD_OK != errorstatus){return(errorstatus);}CSD_Tab[0] = SDIO_GetResponse(SDIO_RESP1);CSD_Tab[1] = SDIO_GetResponse(SDIO_RESP2);CSD_Tab[2] = SDIO_GetResponse(SDIO_RESP3);CSD_Tab[3] = SDIO_GetResponse(SDIO_RESP4);}errorstatus = SD_OK; /*!< All cards get intialized */return(errorstatus); } 2.3 數(shù)據(jù)操作

SD卡數(shù)據(jù)擦除操作,基本沒有修改。

/*** @brief Allows to erase memory area specified for the given card.* @param startaddr: the start address.* @param endaddr: the end address.* @retval SD_Error: SD Card Error code.*/ SD_Error SD_Erase(uint32_t startaddr, uint32_t endaddr) {SD_Error errorstatus = SD_OK;uint32_t delay = 0;__IO uint32_t maxdelay = 0;uint8_t cardstate = 0;/*!< Check if the card coomnd class supports erase command */if (((CSD_Tab[1] >> 20) & SD_CCCC_ERASE) == 0){errorstatus = SD_REQUEST_NOT_APPLICABLE;return(errorstatus);}//延時(shí),根據(jù)時(shí)鐘分頻設(shè)置來計(jì)算maxdelay = 120000 / ((SDIO->CLKCR & 0xFF) + 2);if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED){errorstatus = SD_LOCK_UNLOCK_FAILED;return(errorstatus);}if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){startaddr /= 512;endaddr /= 512;}/*!< According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */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 SD_ERASE_GRP_START with argument as addr */SDIO_CmdInitStructure.SDIO_Argument = startaddr;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_START;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_START);if (errorstatus != SD_OK){return(errorstatus);}/*!< Send CMD33 SD_ERASE_GRP_END with argument as addr */SDIO_CmdInitStructure.SDIO_Argument = endaddr;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_ERASE_GRP_END;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_SD_ERASE_GRP_END);if (errorstatus != SD_OK){return(errorstatus);}}/*!< Send CMD38 ERASE */SDIO_CmdInitStructure.SDIO_Argument = 0;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ERASE;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_ERASE);if (errorstatus != SD_OK){return(errorstatus);}for (delay = 0; delay < maxdelay; delay++){}/*!< Wait till the card is in programming state */errorstatus = IsCardProgramming(&cardstate);while ((errorstatus == SD_OK) && ((SD_CARD_PROGRAMMING == cardstate) || (SD_CARD_RECEIVING == cardstate))){errorstatus = IsCardProgramming(&cardstate);}return(errorstatus); } 數(shù)據(jù)寫入操作,需要修改,關(guān)鍵,否則可能出錯(cuò)。

/*** @brief Allows to write one block starting from a specified address in a card.* The Data transfer can be managed by DMA mode or Polling mode.* @note This operation should be followed by two functions to check if the * DMA Controller and SD Card status.* - SD_ReadWaitOperation(): this function insure that the DMA* controller has finished all data transfer.* - SD_GetStatus(): to check that the SD Card has finished the * data transfer and it is ready for data. * @param writebuff: pointer to the buffer that contain the data to be transferred.* @param WriteAddr: Address from where data are to be read. * @param BlockSize: the SD card Data block size. The Block size should be 512.* @retval SD_Error: SD Card Error code.*/ SD_Error SD_WriteBlock(uint8_t *writebuff, uint32_t WriteAddr, uint16_t BlockSize) {SD_Error errorstatus = SD_OK;TransferError = SD_OK;TransferEnd = 0;StopCondition = 0;//復(fù)位SDIO配置SDIO->DCTRL = 0x0;if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){BlockSize = 512;WriteAddr /= 512;}//----------------------在庫(kù)的基礎(chǔ)上添加的,沒有此段將容易卡死在DMA檢測(cè)中--------------------------/*!< Send CMD16 設(shè)置塊大小 */SDIO_CmdInitStructure.SDIO_Argument = BlockSize;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);if (errorstatus != SD_OK){return(errorstatus);}//----------------------------------------------------------------------------------------------/*!< Send CMD24 WRITE_SINGLE_BLOCK */SDIO_CmdInitStructure.SDIO_Argument = WriteAddr;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_WRITE_SINGLE_BLOCK;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_WRITE_SINGLE_BLOCK);if (errorstatus != SD_OK){return(errorstatus);}//配置SDIO寫數(shù)據(jù)寄存器SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;SDIO_DataInitStructure.SDIO_DataLength = BlockSize;SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToCard;SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;//開啟數(shù)據(jù)通道狀態(tài)機(jī)SDIO_DataConfig(&SDIO_DataInitStructure);SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);//開啟數(shù)據(jù)傳輸結(jié)束中斷SD_DMA_TxConfig((uint32_t *)writebuff, BlockSize);//配置DMA,跟Rx類似SDIO_DMACmd(ENABLE);//使能SDIO的DMA請(qǐng)求return(errorstatus); } /*** @brief ?This function waits until the SDIO DMA data transfer is finished. 寫操作等待函數(shù)* ? ? ? ? This function should be called after SDIO_WriteBlock() and* ? ? ? ? SDIO_WriteMultiBlocks() function to insure that all data sent by the?* ? ? ? ? card are already transferred by the DMA controller. ? ? ? ?* @param ?None.* @retval SD_Error: SD Card Error code.*/ SD_Error SD_WaitWriteOperation(void) {SD_Error errorstatus = SD_OK;while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK)){}if (TransferError != SD_OK){return(TransferError);}/*!< Clear all the static flags */SDIO_ClearFlag(SDIO_STATIC_FLAGS);return(errorstatus); } 數(shù)據(jù)讀取操作,需要修改,關(guān)鍵,否則可能出錯(cuò)。
/*** @brief Allows to read one block from a specified address in a card. The Data * transfer can be managed by DMA mode or Polling mode. * @note This operation should be followed by two functions to check if the * DMA Controller and SD Card status.* - SD_ReadWaitOperation(): this function insure that the DMA* controller has finished all data transfer.* - SD_GetStatus(): to check that the SD Card has finished the * data transfer and it is ready for data. * @param readbuff: pointer to the buffer that will contain the received data* @param ReadAddr: Address from where data are to be read. * @param BlockSize: the SD card Data block size. The Block size should be 512.* @retval SD_Error: SD Card Error code.*/ SD_Error SD_ReadBlock(uint8_t *readbuff, uint32_t ReadAddr, uint16_t BlockSize) {SD_Error errorstatus = SD_OK;TransferError = SD_OK;TransferEnd = 0;//清除傳輸結(jié)束標(biāo)志位,在中斷服務(wù)中置一StopCondition = 0;SDIO->DCTRL = 0x0;if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){BlockSize = 512;ReadAddr /= 512;}//----------------------在庫(kù)的基礎(chǔ)上添加的,沒有此段將容易卡死在DMA檢測(cè)中--------------------------/*!< Send CMD16 設(shè)置塊大小 */SDIO_CmdInitStructure.SDIO_Argument = BlockSize;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);if (errorstatus != SD_OK){return(errorstatus);}//----------------------------------------------------------------------------------------------SDIO_DataInitStructure.SDIO_DataTimeOut = SD_DATATIMEOUT;SDIO_DataInitStructure.SDIO_DataLength = BlockSize;SDIO_DataInitStructure.SDIO_DataBlockSize = (uint32_t) 9 << 4;SDIO_DataInitStructure.SDIO_TransferDir = SDIO_TransferDir_ToSDIO;SDIO_DataInitStructure.SDIO_TransferMode = SDIO_TransferMode_Block;SDIO_DataInitStructure.SDIO_DPSM = SDIO_DPSM_Enable;SDIO_DataConfig(&SDIO_DataInitStructure);/*!< Send CMD17 READ_SINGLE_BLOCK */SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)ReadAddr;SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_READ_SINGLE_BLOCK;SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;SDIO_SendCommand(&SDIO_CmdInitStructure);errorstatus = CmdResp1Error(SD_CMD_READ_SINGLE_BLOCK);if (errorstatus != SD_OK){return(errorstatus);}SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);SDIO_DMACmd(ENABLE);SD_DMA_RxConfig((uint32_t *)readbuff, BlockSize);return(errorstatus); } /*** @brief ?This function waits until the SDIO DMA data transfer is finished.?* ? ? ? ? This function should be called after SDIO_ReadMultiBlocks() function* ? ? ? ? to insure that all data sent by the card are already transferred by?* ? ? ? ? the DMA controller. ? ? ? ?* @param ?None.* @retval SD_Error: SD Card Error code.*/ SD_Error SD_WaitReadOperation(void) {SD_Error errorstatus = SD_OK;while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK)){}if (TransferError != SD_OK){return(TransferError);}return(errorstatus); } 2.4 中斷服務(wù)函數(shù),此處需要提醒的是,這個(gè)中斷處理函數(shù)的位置推薦也放在 bsp_sdio_sdcard.c文件中,因?yàn)檫@樣的話可以防止忘記,Keil會(huì)自動(dòng)地根據(jù)它的名稱識(shí)別出它是一個(gè)中斷函數(shù),無論該函數(shù)位于哪個(gè)文件中,這個(gè)請(qǐng)放心。

//SDIO中斷服務(wù)函數(shù) void SDIO_IRQHandler() {//中斷相關(guān)的處理SD_ProcessIRQSrc(); } /*** @brief Allows to process all the interrupts that are high. 由中斷服務(wù)程序調(diào)用,負(fù)責(zé)中斷相關(guān)的處理* @param None* @retval SD_Error: SD Card Error code.*/ SD_Error SD_ProcessIRQSrc(void) {if (StopCondition == 1)//發(fā)送讀取/多塊讀寫命令時(shí)置一{SDIO->ARG = 0x0;//命令參數(shù)寄存器SDIO->CMD = 0x44C;//命令寄存器TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);//開啟命令狀態(tài)機(jī)短響應(yīng)}else{TransferError = SD_OK;}SDIO_ClearITPendingBit(SDIO_IT_DATAEND);//清中斷SDIO_ITConfig(SDIO_IT_DATAEND, DISABLE);//關(guān)閉SDIO中斷使能TransferEnd = 1;return(TransferError); } 2.5 測(cè)試函數(shù)

#include "sdio_test.h" #include "stdio.h" #include "bsp_sdio_sdcard.h" #include "stm32f10x.h"#define BLOCK_SIZE 512 #define NUMBER_OF_BLOCKS 32 #define MULTI_BUFFER_SIZE (BLOCK_SIZE * NUMBER_OF_BLOCKS)//緩沖區(qū)大小uint8_t Buffer_Block_Tx[BLOCK_SIZE]; uint8_t Buffer_Block_Rx[BLOCK_SIZE]; uint8_t Buffer_MultiBlock_Tx[MULTI_BUFFER_SIZE]; uint8_t Buffer_MultiBlock_Rx[MULTI_BUFFER_SIZE]; SD_Error Status;//測(cè)試狀態(tài) typedef enum {FAILED=0,PASSED=!FAILED } TestStatus;volatile TestStatus EraseStatus = FAILED, TransferStatus1 = FAILED, TransferStatus2 = FAILED; //聲明外部變量 extern SD_CardInfo SDCardInfo;//是否擦除成功 TestStatus eBuffercmp(uint8_t* pBuffer,uint32_t BufferLength) {while(BufferLength--){if((*pBuffer!=0xFF) && (*pBuffer!=0x00))//擦除后是0xff或0x00{return FAILED;}pBuffer++;}return PASSED; } /* *函數(shù)名:Buffercmp *描述:比較兩個(gè)緩沖區(qū)中的數(shù)據(jù)是否相等 *輸入:-pBuffer1,-pBuffer2:要比較的緩沖區(qū)的指針*-BufferLength緩沖區(qū)長(zhǎng)度*輸出:-PASSED相等*-FAILED不等*/ TestStatus Buffercmp(uint8_t* pBuffer1,uint8_t* pBuffer2,uint32_t BufferLength) {while(BufferLength--){if(*pBuffer1 != *pBuffer2){return FAILED;}pBuffer1++;pBuffer2++;}return PASSED; }/* *函數(shù)名:Fill_Buffer *描述:在緩沖區(qū)中填寫數(shù)據(jù) *輸入:-pBuffer要填充的緩沖區(qū) * -BufferLength要填充的大小 * -Offset填在緩沖區(qū)的第一個(gè)值 *輸出:無 */ void Fill_Buffer(uint8_t* pBuffer,uint32_t BufferLength,uint32_t Offset) {uint16_t index=0;/*Putin global buffer some values*/for(index=0;index<BufferLength;index++){pBuffer[index] = index + Offset;} }/* *函數(shù)名:SD_EraseTest *描述:擦除數(shù)據(jù)測(cè)試 *輸入:無 *輸出:無 */ void SD_EraseTest(void) {/*-------------------BlockErase------------------------------------------*/if(Status==SD_OK){Status=SD_Erase(0x00,(BLOCK_SIZE*NUMBER_OF_BLOCKS));//第一個(gè)參數(shù)為擦除起始地址,第二個(gè)參數(shù)為擦除結(jié)束地址}if(Status==SD_OK){//讀取剛剛擦除的區(qū)域Status=SD_ReadMultiBlocks(Buffer_MultiBlock_Rx,0x00,BLOCK_SIZE,NUMBER_OF_BLOCKS);/*Check if the Transfer is finished*/Status=SD_WaitReadOperation();//循環(huán)查詢dma傳輸是否結(jié)束/*Wait until end of DMA transfer*/while(SD_GetStatus()!=SD_TRANSFER_OK);}/*Check the correctness of erased blocks*/if(Status==SD_OK){//把擦除區(qū)域讀出來對(duì)比EraseStatus=eBuffercmp(Buffer_MultiBlock_Rx,MULTI_BUFFER_SIZE);}if(EraseStatus==PASSED){printf("擦除測(cè)試成功!\r\n");}else{printf("擦除測(cè)試失敗!\r\n");} }//單塊讀寫測(cè)試 void SD_SingleBlockTest() {//向數(shù)組填充要寫入的數(shù)據(jù)Fill_Buffer(Buffer_Block_Tx, BLOCK_SIZE, 0x320F);if(Status == SD_OK){//將BLOCK_SIZE個(gè)字節(jié)寫入SD卡的0地址Status = SD_WriteBlock(Buffer_Block_Tx, 0x00, BLOCK_SIZE);//檢查傳輸Status = SD_WaitWriteOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}if(Status == SD_OK){//從SD卡的0地址讀取512個(gè)字節(jié)的數(shù)據(jù)Status = SD_ReadBlock(Buffer_Block_Rx, 0x00, BLOCK_SIZE);//檢查傳輸Status = SD_WaitWriteOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}//校驗(yàn)數(shù)據(jù)是否一致if(Status == SD_OK){TransferStatus1 = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE);}if(TransferStatus1 == PASSED){printf("單塊讀寫測(cè)試成功!\r\n");}else{printf("單塊讀寫測(cè)試失敗!\r\n");} }//SD卡測(cè)試函數(shù) void SD_Test() {//SD卡使用SDIO中斷及DMA中斷接收數(shù)據(jù),中斷服務(wù)程序位于"bsp_sdio_sdcard.c"中Status = SD_Init();if(Status != SD_OK){printf("SD卡初始化失敗!請(qǐng)確保SD卡插在開發(fā)板上,或者換一張SD卡測(cè)試!\r\n");}else{printf("SD卡初始化成功!\r\n");printf("SD_cid:%d \r\n", (SDCardInfo.SD_cid.ManufacturerID));printf("CardBlockSize:%d \r\n", SDCardInfo.CardBlockSize);printf("CardCapacity:%d \r\n", SDCardInfo.CardCapacity);}if(Status == SD_OK){//擦除測(cè)試SD_EraseTest();//單塊讀寫測(cè)試SD_SingleBlockTest();} } 2 .6 重要提醒

因?yàn)闄z測(cè)SD卡是否正確插入的宏SD_PRESENT和SD_NOT_PRESENT是ST官方的原SD驅(qū)動(dòng)程序以一個(gè)輸入引腳電平判斷SD卡是否插入的,但是我們硬件中沒有使用到該引腳,所以我們應(yīng)該把ST驅(qū)動(dòng)中原來用來進(jìn)行引腳檢測(cè)部分的代碼刪除掉,但代碼中,我們還是保留了宏SD_PRESENT和SD_NOT_PRESENT的定義。

用于代碼檢測(cè)的具體位置:

修改方案:

其實(shí)就是不做檢查,利用初始化是否成功來代替檢查過程,就可以了。


刪除步驟:

/*** @brief Detect if SD card is correctly plugged in the memory slot.* @param None* @retval Return if SD is detected or not*/ uint8_t SD_Detect(void) {__IO uint8_t status = SD_PRESENT;/*!< Check GPIO to detect SD */if (GPIO_ReadInputDataBit(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) != Bit_RESET){status = SD_NOT_PRESENT;}return status; }//來自于測(cè)試文件中的外部全局變量 extern SD_Error Status;/*** @brief Returns the current card's state.* @param None* @retval SDCardState: SD Card Error or SD Card Current State.*/ SDCardState SD_GetState(void) {uint32_t resp1 = 0;//原SD卡驅(qū)動(dòng)程序以一個(gè)輸入引腳的電平判斷SD卡是否正確插入,由于我們硬件中沒有使用該引腳,所以我們的程序需要在這里屏蔽掉SD驅(qū)動(dòng)中原來引腳電平檢測(cè)部分的代碼//if(SD_Detect()== SD_PRESENT)if(Status == SD_OK){if (SD_SendStatus(&resp1) != SD_OK){return SD_CARD_ERROR;}else{return (SDCardState)((resp1 >> 9) & 0x0F);}}else{return SD_CARD_ERROR;} } 你可能會(huì)缺少的代碼: /*** @brief Gets the cuurent sd card data transfer status.* @param None* @retval SDTransferState: Data Transfer state.* This value can be: * - SD_TRANSFER_OK: No data transfer is acting* - SD_TRANSFER_BUSY: Data transfer is acting*/ SDTransferState SD_GetStatus(void) {SDCardState cardstate = SD_CARD_TRANSFER;cardstate = SD_GetState();if (cardstate == SD_CARD_TRANSFER){return(SD_TRANSFER_OK);}else if(cardstate == SD_CARD_ERROR){return (SD_TRANSFER_ERROR);}else{return(SD_TRANSFER_BUSY);} }就是這些,下一節(jié)將介紹向SD卡移植FatFs。

總結(jié)

以上是生活随笔為你收集整理的SDIO读写SD卡的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。