官方給的E:\2018-9-3\stm32-奮鬥者\STM32 官方庫3.5版本\stm32f10x_stdperiph_lib35\STM32F10x_StdPeriph_Lib_V3.5.0\Utilities\STM32_EVAL\Common下的文件只是用於他們的測試版,所以須要修改stm32_eval_sdio_sd.h中的include,由原來的#include "stm32_eval.h"改成#include "stm32f10x.h"
數組
/** @defgroup STM32_EVAL_SDIO_SD_Exported_Constants * @{ */ /*宏定義*/ #define SDIO_FIFO_ADDRESS ((uint32_t)0x40018080) //SDIO_FIOF地址=SDIO地址+0x80至 sdio地址+0xfc /** * @brief SDIO Intialization Frequency (400KHz max) */ #define SDIO_INIT_CLK_DIV ((uint8_t)0xB2) /** * @brief SDIO Data Transfer Frequency (25MHz max) */ /*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */ #define SDIO_TRANSFER_CLK_DIV ((uint8_t)0x01)
static void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; //使能gpio時鐘,判斷APB仍是AHB,看System architecture圖(PDF搜) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC,ENABLE); //配置pc8,pc9,pc10,pc11,pc12爲D0,D0,D2,D3,D4,CLK,看電路線路圖 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 |GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP; 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); }
/** 配置好dma2,一發現有中斷,就自動傳輸 Rx **/ void SD_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize) { DMA_InitTypeDef DMA_InitStructure; //清除標誌位 DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 |DMA2_FLAG_HT4 | DMA2_FLAG_GL4); //禁止DMA DMA_Cmd(DMA2_Channel4,DISABLE); //傳輸配置 //外設地址,fifo DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS; //目標地址 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferDST; //傳輸方向 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //把字轉爲字節 DMA_InitStructure.DMA_BufferSize = BufferSize / 4; //存儲地址自增 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //不循環 When circular mode is activated, the number of data to be transferred is automatically reloaded with the initial value programmed during the channel configuration phase, and the DMA requests continue to be served. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //外設數據大小爲字, 32 位 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //存儲數據大小爲字, 32 位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //通道優先級高 DMA_InitStructure.DMA_Priority = DMA_Priority_High; //外設地址不自增 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //非 存儲器至存儲器模式 The DMA channels can also work without being triggered by a request from a peripheral. This mode is called Memory to Memory mode. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA4_Channel4,&DMA_InitStructure); /*!< 使能 DMA 通道 */ DMA_Cmd(DMA2_Channel4, ENABLE); } /** 配置好dma2,一發現有中斷,就自動傳輸 Tx **/ void SD_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize) { DMA_InitTypeDef DMA_InitStructure; DMA_ClearFlag(DMA2_FLAG_TC4 | DMA2_FLAG_TE4 | DMA2_FLAG_HT4 | DMA2_FLAG_GL4); /*!< DMA2 Channel4 disable */ DMA_Cmd(DMA2_Channel4, DISABLE); /*!< DMA2 Channel4 Config */ DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferSRC; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外設爲寫入目標 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; DMA_Init(DMA2_Channel4, &DMA_InitStructure); /*!< DMA2 Channel4 enable */ DMA_Cmd(DMA2_Channel4, ENABLE); }
static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* Configure the NVIC Preemption Priority Bits */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //SDIO的中斷請求 配置好NVIC的中斷控制器和中斷來,判斷誰的優先級高(假設啓動多箇中斷)。先配NVIC,在配外部中斷器來屏蔽--硬件或軟件(事件或中斷) NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStructure); //SDIO_IRQ不須要外部中斷/事件或軟件中斷/事件,所以不須要初始化EXIT控制器的所有寄存器,好比中斷屏蔽寄存器、事件屏蔽寄存器,看圖External interrupt/event controller block diagram }
/** 描述 :初始化SD卡,使卡處於就緒狀態(準備傳輸數據) */ - 此函數原stm32_eval_sdio_sd.c有,不需添加,須要修改 SD_Error SD_Init(void) { /*重置SD_Error狀態*/ SD_Error errorstatus = SD_OK; NVIC_Configuration(); /* SDIO 外設底層引腳初始化 */ GPIO_Configuration(); /*對SDIO的全部寄存器進行復位*/ SDIO_DeInit(); /*上電並進行卡識別流程,確認卡的操做電壓 */ errorstatus = SD_PowerON(); /*若是上電,識別不成功,返回「響應超時」錯誤 */ if (errorstatus != SD_OK) { /*!< CMD Response TimeOut (wait for CMDSENT flag) */ return(errorstatus); } /*卡識別成功,進行卡初始化 */ errorstatus = SD_InitializeCards(); if (errorstatus != SD_OK) //失敗返回 { /*!< CMD Response TimeOut (wait for CMDSENT flag) */ return(errorstatus); } /*!< Configure the SDIO peripheral */ /*!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz */ /*!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */ //從新配置 SDIO 外設,提升時鐘頻率,由卡識別模式的400khz提高到數據傳輸模式小於25Mhz SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV; //上升沿採集數據 SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; // 不使能Bypass,使SDIO_CK通過SDIO_ClockDiv分頻 SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; //開啓的話,總線空閒時關閉SD_CLK 時鐘 SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; //暫時配置成lbit模式 SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; //硬件流。若開啓,在FIFO不能進行發送和接受數據是,數據暫停 SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; SDIO_Init(&SDIO_InitStructure); if (errorstatus == SD_OK) { /*----------------- Read CSD/CID MSD registers ------------------*/ //用來讀取csd/cid寄存器 /*調用 SD_GetCardInfo 函數獲取 SD 卡信息,它須要一個指向 SD_CardInfo 類型變 量地址的指針形參,這裏賦值爲 SDCardInfo 變量的地址。 SD 卡信息主要是 CID 和 CSD 寄存器內容,這兩個寄存器內容在 SD_InitializeCards 函數中都完成讀取過 程並將其分別存放在 CID_Tab 數組和 CSD_Tab 數組中,因此 SD_GetCardInfo 函 數只是簡單的把這兩個數組內容整合複製到 SDCardInfo 變量對應成員內。正確執 行 SD_GetCardInfo 函數後, SDCardInfo 變量就存放了 SD 卡的不少狀態信息,這 在以後應用中使用頻率是很高的。 */ errorstatus = SD_GetCardInfo(&SDCardInfo); } if (errorstatus == SD_OK) { /*----------------- Select Card --------------------------------*/ //經過cm7,rca選擇要操做的卡 errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16)); } if (errorstatus == SD_OK) { //提升讀寫,開啓4bit模式 errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b); } return(errorstatus); }
//確保 SD 卡的工做電壓和配置控制時鐘 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時鐘 SDIO_ClockCmd(ENABLE); /*!< CMD0: GO_IDLE_STATE ---------------------------------------------------*/ /*!< 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是否開啓或關閉等待中斷 SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; /* CPSM 在開始發送命令以前等待數據傳輸結束 */ SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; SDIO_SendCommand(&SDIO_CmdInitStructure); //檢測是否正確接收CM0 , CmdError 函數用於無需響應的命令發送 errorstatus = 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 */ //發送CMD8檢查SD卡電壓操做 //發送 CMD8 命令,檢測 SD 卡支持的操做條件,主要就是電壓匹配, CMD8 的響 //應類型是 R7,使用 CmdResp7Error 函數可獲取獲得 R7 響應結果,它是經過檢測 //SDIO_STA 寄 存 器 相 關 位 完 成 的 , 並 具 有 等 待 超 時 檢 測 功 能 。 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); //檢測是否正確接收 ,Checks for error conditions for R7 response. 搜索R7 (Card interface condition) errorstatus = CmdResp7Error(); if (errorstatus == SD_OK) { CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 */ SDType = SD_HIGH_CAPACITY; } else //無響應,說明1.x { /*!< 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); } /*!< CMD55 */ //發送CMD55,用於檢測sd卡仍是mmc卡,或者不支持的卡 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); //是否響應,沒響應就是mmc或不支持的卡 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) //響應cmd44.是sd卡,可能爲1.x也可能2.x { //下面,循環發送sdio支持的電壓範圍, /*!< SD CARD */ /*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */ while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL)) { // 在發送 ACMD 命令前都要先向卡發送 CMD55 ,CMD55用於指示下一條指令是應用指令 /*!< 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); } /* ACMD41 ,肯定卡是否是 SDSC 仍是 SDHC,返回R3(就是OCR寄存器),須要用CmdResp3Error返回狀態,主要從OCR寄存器31位0或1來判斷那種類型 * 命令參數由支持的電壓範圍及 HCS 位組成, HCS 位置一來區分卡是 SDSC 仍是 SDHC * 0:SDSC * 1:SDHC * 響應: R3,對應的是 OCR 寄存器 */ /*使用 ACMD41 命令判斷卡的具體類型。由於是 A 類命令,因此在發送 ACMD41 以前必須先發送 CMD55, CMD55 命令的響應類型的 R1。若是 CMD55 命令都沒 有響應說明是 MMC 卡或不可用卡。在正確發送 CMD55 以後就能夠發送 ACMD41,並根據響應判斷卡類型, ACMD41 的響應號爲 R3, CmdResp3Error 函 數用於檢測命令正確發送並帶有超時檢測功能,但並不具有響應內容接收功能, 須要在斷定命令正確發送以後調用 SDIO_GetResponse 函數才能獲取響應的內容。 */ SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType;//0x80100000 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); } /* 若卡需求電壓在 SDIO 的供電電壓範圍內,會自動上電並標誌 pwr_up 位 * 讀取卡寄存器,卡狀態 */ response = SDIO_GetResponse(SDIO_RESP1); /* 讀取卡的 ocr 寄存器的 pwr_up 位,看是否已工做在正常電壓 */ validvoltage = (((response >> 31) == 1) ? 1 : 0); count++; //計算循環 } //結束循環 // 循環檢測超過必定次數還沒上電 if (count >= SD_MAX_VOLT_TRIAL) { // SDIO 不支持 card 的供電電壓 errorstatus = SD_INVALID_VOLTRANGE; return(errorstatus); } /*檢查卡返回信息中的 HCS 位*/ /* 判斷 ocr 中的 ccs 位 ,若是是 sdsc 卡則不執行下面的語句 */ if (response &= SD_HIGH_CAPACITY) //判斷30位是否爲1 { CardType = SDIO_HIGH_CAPACITY_SD_CARD; } }/*!< else MMC Card */ return(errorstatus); }
//描述 :初始化全部的卡或者單個卡進入就緒狀態 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 響應: R2,對應 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 信息存儲起來 CID_Tab已經定義好了,不用咱們本身,直接用 */ CID_Tab[0] = SDIO_GetRespon se(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 卡返回自身的 RCA 地址. */ /*!< 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 響應:R2 對應寄存器 CSD(Card-Specific Data)*/ 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); }
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) { //在 sdhc 卡中,地址參數爲塊地址,每塊 512 字節,而 sdsc 卡地址爲字節地址 //因此如果 sdhc 卡要對地址/512 進行轉換 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; //R1 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); }
SD_Error SD_WriteBlock(uint8_t *writebuff, uint64_t WriteAddr, uint16_t BlockSize) { SD_Error errorstatus = SD_OK; #if defined (SD_POLLING_MODE) uint32_t bytestransferred = 0, count = 0, restwords = 0; uint32_t *tempbuff = (uint32_t *)writebuff; #endif TransferError = SD_OK; TransferEnd = 0; StopCondition = 0; SDIO->DCTRL = 0x0; if (CardType == SDIO_HIGH_CAPACITY_SD_CARD) { BlockSize = 512; WriteAddr /= 512; } /*-------------- add , 沒有這一段容易卡死在DMA檢測中 -------------------*/ /* Set Block Size for Card,cmd16, * 如果sdsc卡,能夠用來設置塊大小, * 如果sdhc卡,塊大小爲512字節,不受cmd16影響 */ SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) 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 (SD_OK != errorstatus) { 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; //r1 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_DataBlockSize_512b 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); /*!< In case of single data block transfer no need of stop command at all */ #if defined (SD_POLLING_MODE) //普通模式 while (!(SDIO->STA & (SDIO_FLAG_DBCKEND | SDIO_FLAG_TXUNDERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_STBITERR))) { if (SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET) { if ((512 - bytestransferred) < 32) { restwords = ((512 - bytestransferred) % 4 == 0) ? ((512 - bytestransferred) / 4) : (( 512 - bytestransferred) / 4 + 1); for (count = 0; count < restwords; count++, tempbuff++, bytestransferred += 4) { SDIO_WriteData(*tempbuff); } } else { for (count = 0; count < 8; count++) { SDIO_WriteData(*(tempbuff + count)); } tempbuff += 8; bytestransferred += 32; } } } if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) { SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); errorstatus = SD_DATA_TIMEOUT; return(errorstatus); } else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) { SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); errorstatus = SD_DATA_CRC_FAIL; return(errorstatus); } else if (SDIO_GetFlagStatus(SDIO_FLAG_TXUNDERR) != RESET) { SDIO_ClearFlag(SDIO_FLAG_TXUNDERR); errorstatus = SD_TX_UNDERRUN; return(errorstatus); } else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) { SDIO_ClearFlag(SDIO_FLAG_STBITERR); errorstatus = SD_START_BIT_ERR; return(errorstatus); } #elif defined (SD_DMA_MODE) //dma模式 SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE); //數據傳輸結束中斷 SD_DMA_TxConfig((uint32_t *)writebuff, BlockSize); //配置dma,跟rx相似 SDIO_DMACmd(ENABLE); // 使能sdio的dma請求 #endif return(errorstatus); }
/** * 上述代碼調用庫函數 SD_DMAEndOfTransferStatus 一直檢測 DMA 的傳輸完成標誌, 當 DMA 傳輸結束時,該函數會返回 SET 值。另外, while 循環中的判斷條件使用的 TransferEnd 和 TransferError 是全局變量,它們會在 SDIO 的中斷服務函數根據傳輸狀況被 設置, 傳輸結束後,根據 TransferError 的值來確認是否正確傳輸,若不正確則直接返回錯 誤代碼。 SD_WaitWriteOperation 函數最後是清除相關標誌位並返回錯誤。因爲這個函數裏 的 while 循環的存在, 它會確保 DMA 的傳輸結束。 */ SD_Error SD_WaitWriteOperation(void) { SD_Error errorstatus = SD_OK; //等待dma是否傳輸 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); }
SD_Error SD_ReadBlock(uint8_t *readbuff, uint64_t ReadAddr, uint16_t BlockSize) { SD_Error errorstatus = SD_OK; #if defined (SD_POLLING_MODE) uint32_t count = 0, *tempbuff = (uint32_t *)readbuff; #endif TransferError = SD_OK; TransferEnd = 0; //傳輸結束標置位,在中斷服務置1 StopCondition = 0; SDIO->DCTRL = 0x0; if (CardType == SDIO_HIGH_CAPACITY_SD_CARD) { BlockSize = 512; ReadAddr /= 512; } /*******************add,沒有這一段容易卡死在DMA檢測中*************************************/ /* Set Block Size for Card,cmd16, * 如果sdsc卡,能夠用來設置塊大小, * 如果sdhc卡,塊大小爲512字節,不受cmd16影響 */ SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize; SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN; SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r1 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 (SD_OK != errorstatus) { 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); } #if defined (SD_POLLING_MODE) /*!< In case of single block transfer, no need of stop transfer at all.*/ /*!< Polling mode */ while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR))) { if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET) { for (count = 0; count < 8; count++) { *(tempbuff + count) = SDIO_ReadData(); } tempbuff += 8; } } if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) { SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT); errorstatus = SD_DATA_TIMEOUT; return(errorstatus); } else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET) { SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL); errorstatus = SD_DATA_CRC_FAIL; return(errorstatus); } else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET) { SDIO_ClearFlag(SDIO_FLAG_RXOVERR); errorstatus = SD_RX_OVERRUN; return(errorstatus); } else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET) { SDIO_ClearFlag(SDIO_FLAG_STBITERR); errorstatus = SD_START_BIT_ERR; return(errorstatus); } while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) { *tempbuff = SDIO_ReadData(); tempbuff++; } /*!< Clear all the static flags */ SDIO_ClearFlag(SDIO_STATIC_FLAGS); #elif defined (SD_DMA_MODE) SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE); SDIO_DMACmd(ENABLE); SD_DMA_RxConfig((uint32_t *)readbuff, BlockSize); #endif return(errorstatus); }
// 在 SDIO_ITConfig()這個函數開啓了 sdio 中斷 , void SDIO_IRQHandler(void) { //SDIO中斷相關處理 SD_ProcessIRQSrc(); //定義在bsp_sdio_sdcard.c }
/* * 函數名:SD_ProcessIRQSrc * 描述 :數據傳輸結束中斷 * 輸入 :無 * 輸出 :SD錯誤類型 */ SD_Error SD_ProcessIRQSrc(void) { if (StopCondition == 1) //發送讀取、多塊讀寫命令時置1 { SDIO->ARG = 0x0; //命令參數寄存器 SDIO->CMD = 0x44C; // 命令寄存器: 0100 01 001100 // [7:6] [5:0] // CPSMEN WAITRESP CMDINDEX // 開啓命令狀態機 短響應 cmd12 STOP_ TRANSMISSION 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); }
點擊下載:【sd卡讀取】app