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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SDIO读写SD卡

發布時間:2023/12/20 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SDIO读写SD卡 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

工程介紹:主要文件在USER組中,bsp_sdio_sdcard.c,bsp_sdio_sdcard.h和main.c,另外FatFs是用來后面移植文件系統使用的,對于本節內容暫時不需要。bsp_sdio_sdcard.c和bsp_sdio_sdcard.h文件主要參考教材《STM32庫開發實戰指南——基于STM32F03》。教材中部分省略內容來自于其他網友總結,在此表示感謝。

本文想大概講一下SD卡讀寫實驗的具體步驟,以及最重要的是一個細節問題,它使我在這個問題上耗了兩天的時間。

大概流程如下:

1.硬件設計:

因為在該平臺的板子上已經存在了一個SD卡接口,因此,不需要額外的連線,只需要一條串口連接線連接到電腦上輸出調試信息即可。

2.軟件設計:

操作的大致流程:

1》初始化相關的GPIO及SDIO外設;

2》配置SDIO基本通信環境進入卡識別模式,通過幾個命令處理得到卡類型;

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

具體的步驟:

因為官方固件庫有實現的案例,所以我們不妨”拿來主義“。其實bsp_sdio_sdcard.c和bsp_sdio_sdcard.h就是對stm32_eval_sdio_sd.c和stm32_eval_sdio_sd.h文件的修改和借鑒。我是直接把名字改了,然后在源文件的基礎上做了修改。

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

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

//GPIO初始化,開啟時鐘 static void GPIO_Configuration() {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);//開啟時鐘//配置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;//設置復用模式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時鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);//使能DMA時鐘RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE); } //DMA傳輸配置,接收數據 void SD_DMA_RxConfig(uint32_t* BufferDST, uint32_t BufferSize) {DMA_InitTypeDef DMA_InitStructure;//清除DMA標志位DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);//配置前禁止DMADMA_Cmd(DMA2_Channel4, DISABLE);//DMA傳輸配置//外設地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;//目標地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferDST;//外設為源地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//除以4,把字轉換成字節單位DMA_InitStructure.DMA_BufferSize = BufferSize / 4;//外設地址不增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//存儲目標地址DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//外設數據大小為字DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//存儲數據大小DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//不循環,一次DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//通道優先級為高DMA_InitStructure.DMA_Priority = DMA_Priority_High;//非存儲器至存儲器模式DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//初始化DMADMA_Init(DMA2_Channel4, &DMA_InitStructure);//使能DMA通道DMA_Cmd(DMA2_Channel4, ENABLE); } //為SDIO發送數據配置DMA2的通道2的請求 void SD_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize) {DMA_InitTypeDef DMA_InitStructure;//清除DMA標志位DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4);//配置前禁止DMADMA_Cmd(DMA2_Channel4, DISABLE);//DMA傳輸配置//外設地址DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS;//存儲地址DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferSRC;//外設為目的地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//除以4,把字轉換成字節單位DMA_InitStructure.DMA_BufferSize = BufferSize / 4;//外設地址不增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//存儲目標地址DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//外設數據大小為字DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//存儲數據大小DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//不循環,一次DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//通道優先級為高DMA_InitStructure.DMA_Priority = DMA_Priority_High;//非存儲器至存儲器模式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; //優先級組選擇 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //選擇USART的中斷源 NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn; //配置搶占優先級 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //配置子優先級 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中斷優先級SDIO_NVIC_Configuration();//SDIO外設底層引腳初始化GPIO_Configuration();//對SDIO所有的寄存器進行復位SDIO_DeInit();//上電,并進行卡識別流程,確認卡的操作電壓errorstatus = SD_PowerON();//識別不成功if (errorstatus != SD_OK){/*!< CMD Response TimeOut (wait for CMDSENT flag) */return(errorstatus);}//識別成功,對SD卡進行初始化errorstatus = SD_InitializeCards();//初始化失敗if (errorstatus != SD_OK){/*!< CMD Response TimeOut (wait for CMDSENT flag) */return(errorstatus);}//進入數據傳輸模式,提高讀寫速度/*!< 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); } 與之相對的還有一個SD_DeInit()函數,復位寄存器。

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); } //對SDIO所有的寄存器進行復位 void SD_DeInit(void) {?SD_LowLevel_DeInit(); } SD_PowerOn()函數用于查詢卡的工作電壓和時鐘控制配置,沒有修改。可以看一下。
/*** @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: 復位所有的SD卡,使其進入空閑狀態 ---------------------------------------------------*//*!< 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;//關閉等待中斷SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;//CPSM在發送數據之前等待數據傳輸結束SDIO_SendCommand(&SDIO_CmdInitStructure);//檢測是否正確接收到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{//有相應就是SD CARD 2.0,此時無響應,代表是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); } 初始化所有的卡或者單個卡進入就緒狀態,沒有修改。

/*** @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 數據操作

SD卡數據擦除操作,基本沒有修改。

/*** @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);}//延時,根據時鐘分頻設置來計算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); } 數據寫入操作,需要修改,關鍵,否則可能出錯。

/*** @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;//復位SDIO配置SDIO->DCTRL = 0x0;if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){BlockSize = 512;WriteAddr /= 512;}//----------------------在庫的基礎上添加的,沒有此段將容易卡死在DMA檢測中--------------------------/*!< Send CMD16 設置塊大小 */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寫數據寄存器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;//開啟數據通道狀態機SDIO_DataConfig(&SDIO_DataInitStructure);SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);//開啟數據傳輸結束中斷SD_DMA_TxConfig((uint32_t *)writebuff, BlockSize);//配置DMA,跟Rx類似SDIO_DMACmd(ENABLE);//使能SDIO的DMA請求return(errorstatus); } /*** @brief ?This function waits until the SDIO DMA data transfer is finished. 寫操作等待函數* ? ? ? ? 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); } 數據讀取操作,需要修改,關鍵,否則可能出錯。
/*** @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;//清除傳輸結束標志位,在中斷服務中置一StopCondition = 0;SDIO->DCTRL = 0x0;if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){BlockSize = 512;ReadAddr /= 512;}//----------------------在庫的基礎上添加的,沒有此段將容易卡死在DMA檢測中--------------------------/*!< Send CMD16 設置塊大小 */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 中斷服務函數,此處需要提醒的是,這個中斷處理函數的位置推薦也放在 bsp_sdio_sdcard.c文件中,因為這樣的話可以防止忘記,Keil會自動地根據它的名稱識別出它是一個中斷函數,無論該函數位于哪個文件中,這個請放心。

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

#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)//緩沖區大小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;//測試狀態 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; } /* *函數名:Buffercmp *描述:比較兩個緩沖區中的數據是否相等 *輸入:-pBuffer1,-pBuffer2:要比較的緩沖區的指針*-BufferLength緩沖區長度*輸出:-PASSED相等*-FAILED不等*/ TestStatus Buffercmp(uint8_t* pBuffer1,uint8_t* pBuffer2,uint32_t BufferLength) {while(BufferLength--){if(*pBuffer1 != *pBuffer2){return FAILED;}pBuffer1++;pBuffer2++;}return PASSED; }/* *函數名:Fill_Buffer *描述:在緩沖區中填寫數據 *輸入:-pBuffer要填充的緩沖區 * -BufferLength要填充的大小 * -Offset填在緩沖區的第一個值 *輸出:無 */ 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;} }/* *函數名:SD_EraseTest *描述:擦除數據測試 *輸入:無 *輸出:無 */ void SD_EraseTest(void) {/*-------------------BlockErase------------------------------------------*/if(Status==SD_OK){Status=SD_Erase(0x00,(BLOCK_SIZE*NUMBER_OF_BLOCKS));//第一個參數為擦除起始地址,第二個參數為擦除結束地址}if(Status==SD_OK){//讀取剛剛擦除的區域Status=SD_ReadMultiBlocks(Buffer_MultiBlock_Rx,0x00,BLOCK_SIZE,NUMBER_OF_BLOCKS);/*Check if the Transfer is finished*/Status=SD_WaitReadOperation();//循環查詢dma傳輸是否結束/*Wait until end of DMA transfer*/while(SD_GetStatus()!=SD_TRANSFER_OK);}/*Check the correctness of erased blocks*/if(Status==SD_OK){//把擦除區域讀出來對比EraseStatus=eBuffercmp(Buffer_MultiBlock_Rx,MULTI_BUFFER_SIZE);}if(EraseStatus==PASSED){printf("擦除測試成功!\r\n");}else{printf("擦除測試失敗!\r\n");} }//單塊讀寫測試 void SD_SingleBlockTest() {//向數組填充要寫入的數據Fill_Buffer(Buffer_Block_Tx, BLOCK_SIZE, 0x320F);if(Status == SD_OK){//將BLOCK_SIZE個字節寫入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個字節的數據Status = SD_ReadBlock(Buffer_Block_Rx, 0x00, BLOCK_SIZE);//檢查傳輸Status = SD_WaitWriteOperation();while(SD_GetStatus() != SD_TRANSFER_OK);}//校驗數據是否一致if(Status == SD_OK){TransferStatus1 = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE);}if(TransferStatus1 == PASSED){printf("單塊讀寫測試成功!\r\n");}else{printf("單塊讀寫測試失敗!\r\n");} }//SD卡測試函數 void SD_Test() {//SD卡使用SDIO中斷及DMA中斷接收數據,中斷服務程序位于"bsp_sdio_sdcard.c"中Status = SD_Init();if(Status != SD_OK){printf("SD卡初始化失敗!請確保SD卡插在開發板上,或者換一張SD卡測試!\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){//擦除測試SD_EraseTest();//單塊讀寫測試SD_SingleBlockTest();} } 2 .6 重要提醒

因為檢測SD卡是否正確插入的宏SD_PRESENT和SD_NOT_PRESENT是ST官方的原SD驅動程序以一個輸入引腳電平判斷SD卡是否插入的,但是我們硬件中沒有使用到該引腳,所以我們應該把ST驅動中原來用來進行引腳檢測部分的代碼刪除掉,但代碼中,我們還是保留了宏SD_PRESENT和SD_NOT_PRESENT的定義。

用于代碼檢測的具體位置:

修改方案:

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


刪除步驟:

/*** @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; }//來自于測試文件中的外部全局變量 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卡驅動程序以一個輸入引腳的電平判斷SD卡是否正確插入,由于我們硬件中沒有使用該引腳,所以我們的程序需要在這里屏蔽掉SD驅動中原來引腳電平檢測部分的代碼//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;} } 你可能會缺少的代碼: /*** @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);} }就是這些,下一節將介紹向SD卡移植FatFs。

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。