官方给的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