?? +
字號:
/*********************************************************************************
* 文件名 :sdio_sdcard.c
* 描述 :MicroSD卡應用函數庫(SDIO模式)
* 實驗平臺:CHD1807-STM32開發板
* 硬件連接:------------------------------
* | PC8-SDIO-D0 :DATA0 |
* | PC9-SDIO-D1 :DATA1 |
* | PC10-SDIO-D2 :DATA2 |
* | PC11-SDIO-D3 :CD/DATA3 |
* | PC12-SDIO-CLK:CLK |
* | PD2-SDIO-CMD :CMD |
* ------------------------------
* 庫版本 :ST 3.5.0
**********************************************************************************/
#include "sdio_sdcard.h"
#include "usart1.h"
/* Private macro -------------------------------------------------------------*/
/**
* @brief SDIO Static flags, TimeOut, FIFO Address
*/
#define NULL 0
#define SDIO_STATIC_FLAGS ((uint32_t)0x000005FF)
#define SDIO_CMD0TIMEOUT ((uint32_t)0x00010000)
/**
* @brief Mask for errors Card Status R1 (OCR Register)
*/
#define SD_OCR_ADDR_OUT_OF_RANGE ((uint32_t)0x80000000)
#define SD_OCR_ADDR_MISALIGNED ((uint32_t)0x40000000)
#define SD_OCR_BLOCK_LEN_ERR ((uint32_t)0x20000000)
#define SD_OCR_ERASE_SEQ_ERR ((uint32_t)0x10000000)
#define SD_OCR_BAD_ERASE_PARAM ((uint32_t)0x08000000)
#define SD_OCR_WRITE_PROT_VIOLATION ((uint32_t)0x04000000)
#define SD_OCR_LOCK_UNLOCK_FAILED ((uint32_t)0x01000000)
#define SD_OCR_COM_CRC_FAILED ((uint32_t)0x00800000)
#define SD_OCR_ILLEGAL_CMD ((uint32_t)0x00400000)
#define SD_OCR_CARD_ECC_FAILED ((uint32_t)0x00200000)
#define SD_OCR_CC_ERROR ((uint32_t)0x00100000)
#define SD_OCR_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00080000)
#define SD_OCR_STREAM_READ_UNDERRUN ((uint32_t)0x00040000)
#define SD_OCR_STREAM_WRITE_OVERRUN ((uint32_t)0x00020000)
#define SD_OCR_CID_CSD_OVERWRIETE ((uint32_t)0x00010000)
#define SD_OCR_WP_ERASE_SKIP ((uint32_t)0x00008000)
#define SD_OCR_CARD_ECC_DISABLED ((uint32_t)0x00004000)
#define SD_OCR_ERASE_RESET ((uint32_t)0x00002000)
#define SD_OCR_AKE_SEQ_ERROR ((uint32_t)0x00000008)
#define SD_OCR_ERRORBITS ((uint32_t)0xFDFFE008)
/**
* @brief Masks for R6 Response
*/
#define SD_R6_GENERAL_UNKNOWN_ERROR ((uint32_t)0x00002000)
#define SD_R6_ILLEGAL_CMD ((uint32_t)0x00004000)
#define SD_R6_COM_CRC_FAILED ((uint32_t)0x00008000)
#define SD_VOLTAGE_WINDOW_SD ((uint32_t)0x80100000)
#define SD_HIGH_CAPACITY ((uint32_t)0x40000000)
#define SD_STD_CAPACITY ((uint32_t)0x00000000)
#define SD_CHECK_PATTERN ((uint32_t)0x000001AA)
#define SD_MAX_VOLT_TRIAL ((uint32_t)0x0000FFFF)
#define SD_ALLZERO ((uint32_t)0x00000000)
#define SD_WIDE_BUS_SUPPORT ((uint32_t)0x00040000)
#define SD_SINGLE_BUS_SUPPORT ((uint32_t)0x00010000)
#define SD_CARD_LOCKED ((uint32_t)0x02000000)
#define SD_DATATIMEOUT ((uint32_t)0xFFFFFFFF)
#define SD_0TO7BITS ((uint32_t)0x000000FF)
#define SD_8TO15BITS ((uint32_t)0x0000FF00)
#define SD_16TO23BITS ((uint32_t)0x00FF0000)
#define SD_24TO31BITS ((uint32_t)0xFF000000)
#define SD_MAX_DATA_LENGTH ((uint32_t)0x01FFFFFF)
#define SD_HALFFIFO ((uint32_t)0x00000008)
#define SD_HALFFIFOBYTES ((uint32_t)0x00000020)
/**
* @brief Command Class Supported
*/
#define SD_CCCC_LOCK_UNLOCK ((uint32_t)0x00000080)
#define SD_CCCC_WRITE_PROT ((uint32_t)0x00000040)
#define SD_CCCC_ERASE ((uint32_t)0x00000020)
/**
* @brief Following commands are SD Card Specific commands.
* SDIO_APP_CMD should be sent before sending these commands.
*/
#define SDIO_SEND_IF_COND ((uint32_t)0x00000008)
/* Private variables ---------------------------------------------------------*/
static uint32_t CardType = SDIO_STD_CAPACITY_SD_CARD_V1_1; //存儲卡的類型,先把它初始化為1.1協議的卡
static uint32_t CSD_Tab[4], CID_Tab[4], RCA = 0;//存儲CSD,DID,寄存器和卡相對地址
static uint8_t SDSTATUS_Tab[16]; //存儲卡狀態,是CSR的一部分
__IO uint32_t StopCondition = 0; //用于停止卡操作的標志
__IO SD_Error TransferError = SD_OK; //用于存儲卡錯誤,初始化為正常狀態
__IO uint32_t TransferEnd = 0; //用于標志傳輸是否結束,在中斷服務函數中調用
SD_CardInfo SDCardInfo; //用于存儲卡的信息,DSR的一部分?
/*用于sdio初始化的結構體*/
SDIO_InitTypeDef SDIO_InitStructure;
SDIO_CmdInitTypeDef SDIO_CmdInitStructure;
SDIO_DataInitTypeDef SDIO_DataInitStructure;
/* Private function prototypes -----------------------------------------------*/
static SD_Error CmdError(void);
static SD_Error CmdResp1Error(uint8_t cmd);
static SD_Error CmdResp7Error(void);
static SD_Error CmdResp3Error(void);
static SD_Error CmdResp2Error(void);
static SD_Error CmdResp6Error(uint8_t cmd, uint16_t *prca);
static SD_Error SDEnWideBus(FunctionalState NewState);
static SD_Error IsCardProgramming(uint8_t *pstatus);
static SD_Error FindSCR(uint16_t rca, uint32_t *pscr);
static void GPIO_Configuration(void);
static uint32_t SD_DMAEndOfTransferStatus(void);
static void SD_DMA_RxConfig(uint32_t *BufferDST, uint32_t BufferSize);
static void SD_DMA_TxConfig(uint32_t *BufferSRC, uint32_t BufferSize);
uint8_t convert_from_bytes_to_power_of_two(uint16_t NumberOfBytes);
/* Private functions ---------------------------------------------------------*/
/*
* 函數名:SD_DeInit
* 描述 :復位SDIO端口
* 輸入 :無
* 輸出 :無
*/
void SD_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);
}
/*
* 函數名:NVIC_Configuration
* 描述 :SDIO 優先級配置為最高優先級。
* 輸入 :無
* 輸出 :無
*/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the NVIC Preemption Priority Bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
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);
}
/**
* @brief Returns the DMA End Of Transfer Status.
* @param None
* @retval DMA SDIO Channel Status.
*/
uint32_t SD_DMAEndOfTransferStatus(void)
{
return (uint32_t)DMA_GetFlagStatus(DMA2_FLAG_TC4); //Channel4 transfer complete flag.
}
/*
* 函數名:SD_DMA_RxConfig
* 描述 :為SDIO接收數據配置DMA2的通道4的請求
* 輸入 :BufferDST:用于裝載數據的變量指針
BufferSize: 緩沖區大小
* 輸出 :無
*/
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標志位
/*!< DMA2 Channel4 disable */
DMA_Cmd(DMA2_Channel4, DISABLE); //SDIO為第四通道
/*!< DMA2 Channel4 Config */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SDIO_FIFO_ADDRESS; //外設地址,fifo
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)BufferDST; //目標地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外設為原地址
DMA_InitStructure.DMA_BufferSize = BufferSize / 4; //1/4緩存大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//使能外設地址不自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //使能存儲目標地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外設數據大小為字,32位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //外設數據大小為字,32位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //不循環,循環模式主要用在adc上
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //通道優先級高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //非 存儲器至存儲器模式
DMA_Init(DMA2_Channel4, &DMA_InitStructure);
/*!< DMA2 Channel4 enable */ //不設置dma中斷?
DMA_Cmd(DMA2_Channel4, ENABLE);
}
/*
* 函數名:SD_DMA_RxConfig
* 描述 :為SDIO發送數據配置DMA2的通道4的請求
* 輸入 :BufferDST:裝載了數據的變量指針
BufferSize: 緩沖區大小
* 輸出 :無
*/
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);
}
/*
* 函數名:GPIO_Configuration
* 描述 :初始化SDIO用到的引腳,開啟時鐘。
* 輸入 :無
* 輸出 :無
* 調用 :內部調用
*/
static void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*!< GPIOC and GPIOD Periph clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD , ENABLE);
/*!< 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_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/*!< Configure PD.02 CMD line */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/*!< Enable the SDIO AHB Clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_SDIO, ENABLE);
/*!< Enable the DMA2 Clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
}
/*
* 函數名:SD_Init
* 描述 :初始化SD卡,使卡處于就緒狀態(準備傳輸數據)
* 輸入 :無
* 輸出 :-SD_Error SD卡錯誤代碼
* 成功時則為 SD_OK
* 調用 :外部調用
*/
SD_Error SD_Init(void)
{
/*重置SD_Error狀態*/
SD_Error errorstatus = SD_OK;
/* 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
上電識別,卡初始化都完成后,進入數據傳輸模式,提高讀寫速度
速度若超過24M要進入bypass模式
!< on STM32F2xx devices, SDIOCLK is fixed to 48MHz
!< SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_TRANSFER_CLK_DIV) */
SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; //上升沿采集數據
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable; //時鐘頻率若超過24M,要開啟此模式
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; //若開啟此功能,在總線空閑時關閉sd_clk時鐘
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; //1位模式
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable; //硬件流,若開啟,在FIFO不能進行發送和接收數據時,數據傳輸暫停
SDIO_Init(&SDIO_InitStructure);
if (errorstatus == SD_OK)
{
/*----------------- Read CSD/CID MSD registers ------------------*/
errorstatus = SD_GetCardInfo(&SDCardInfo); //用來讀取csd/cid寄存器
}
if (errorstatus == SD_OK)
{
/*----------------- Select Card --------------------------------*/
errorstatus = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16)); //通過cmd7 ,rca選擇要操作的卡
}
if (errorstatus == SD_OK)
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -