STM32中SD的初始化代码:
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)
{
errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b); //开启4bits模式
}
return(errorstatus);
}
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 外设 */
/* SDIOCLK = HCLK, SDIO_CK = HCLK/(2 + SDIO_INIT_CLK_DIV) = 400KHz */
/* 卡识别模式时的 SDIO_CK 不能超过 400KHz */
/*初始化时的时钟不能大于400KHz*/
SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;/*设置时钟分频=178*/ /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz
*/
SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising; //时钟上升沿采集数据
SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;//不使用bypass模式,直接用HCLK进行分频得到SDIO_CK
SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable; // 空闲时不关闭时钟电源
SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b; //1位数据线
SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;//硬件流
SDIO_Init(&SDIO_InitStructure);//初始化SDIO
/*!< Set Power State to ON */ /*打开SDIO的电源*/
SDIO_SetPowerState(SDIO_PowerState_ON);
/*!< Enable SDIO Clock */ /*开SDIO的时钟*/
SDIO_ClockCmd(ENABLE);
/*下面发送一系列命令,开始卡识别流程*/
/************************发送CMD0*************************************** */
/************************发送CMD0*************************************** */
/************************发送CMD0*************************************** */
/*!< CMD0: GO_IDLE_STATE变为空闲状态---------------------------------------------------*/
/*!< No CMD response required */
/* 发送 CMD0 复位卡,该命令不需要响应 */
SDIO_CmdInitStructure.SDIO_Argument = 0x0;//命令参数,是命令的一部分,和命令一起发送
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_GO_IDLE_STATE; //cmd0命令索引,变为空闲状态
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;//无响应 SDIO响应类型
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //SDIO不等待中断
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;//则CPSM在开始发送命令之前等待数据传输结束。
SDIO_SendCommand(&SDIO_CmdInitStructure); //写命令进SDIO命令寄存器
errorstatus = CmdError();//检测是否正确接收到cmd0
/* 没发送CMD0,返回命令超时错误 */
if (errorstatus != SD_OK) //命令发送出错,返回
{
/*!< CMD Response TimeOut (wait for CMDSENT flag) */
return(errorstatus);
}
/************************发送CMD8*************************************** */
/************************发送CMD8*************************************** */
/************************发送CMD8*************************************** */
/*!< CMD8: SEND_IF_COND ----------------------------------------------------*/
/*!< Send CMD8 to verify SD card interface operating condition */
/*!< Argument: - : Reserved (shall be set to '0')
- : Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V)
- : Check Pattern (recommended 0xAA) */
/*!< CMD Response: R7 */
/* CMD8: SEND_IF_COND -------------------------------------------------------------*/
/* 发送 CMD8 核实 SD 卡接口操作条件 */
/* 参数: - : 保留('0')
- : 供电电压(VHS) 0x1 (范围: 2.7-3.6 V)
- : 检查类型 (推荐 0xAA) */
/* 响应类型: R7 */
SDIO_CmdInitStructure.SDIO_Argument = SD_CHECK_PATTERN; //接收到命令sd会返回这个参数
SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_SEND_IF_COND; //cmd8
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r7
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; //关闭等待中断
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
/*检查是否接收到命令*/
errorstatus = CmdResp7Error();
/* 如果已收到响应 R7,则符合SD卡2.0标准,并且可以设置HCS(HCS=1,表示主机支持SDHC) */
if (errorstatus == SD_OK) //有响应则card遵循sd协议2.0版本
{
CardType = SDIO_STD_CAPACITY_SD_CARD_V2_0; /*!< SD Card 2.0 ,先把它定义会sdsc类型的卡*/ /* 标准容量SD卡2.0 */
SDType = SD_HIGH_CAPACITY; //这个变量用作acmd41的参数,用来询问是sdsc卡还是sdhc卡
}
else //无响应,说明是1.x的或mmc的卡
{
/*!< CMD55 也就是PDF图中的ACMD41 0x41=d55*/
/* CMD55: APP_CMD */
/* 发送CMD55判断是不是SD卡 */
/* 参数: - : RCA = 0x0000
- : 保留('0') */
/* 响应类型: R1 */
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: APP_CMD */
/* 发送CMD55判断是不是SD卡 */
/* 参数: - : RCA = 0x0000
- : 保留('0') */
/* 响应类型: R1 */
/*!< CMD55 */ //为什么在else里和else外面都要发送CMD55?
//发送cmd55,用于检测是sd卡还是mmc卡,或是不支持的卡
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD;
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_APP_CMD); //是否响应,没响应的是mmc或不支持的卡
/*!< 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 */
/* 如果 errorstatus 是命令响应超时,则是 MMC 卡 */
/* 如果 errorstatus 是 SD_OK ,则是 SD 卡: SD卡1.x(不符合SD卡2.0标准)或SD 卡 2.0(不支持设置的电压范围(2.7~3.6V)) */
if (errorstatus == SD_OK) //响应了cmd55,是sd卡,可能为1.x,可能为2.0
{
/*下面开始循环地发送sdio支持的电压范围,循环一定次数*/
/*!< SD CARD */
/*!< Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */
while ((!validvoltage) && (count < SD_MAX_VOLT_TRIAL))
{
/* CMD55: APP_CMD */
/* 必须在发送 ACMD41 之前发送 CMD55 通知卡,下面一条命令是应用特定命令 */
/* 参数: - : RCA = 0x0000
- : 保留('0') */
/* 响应类型: R1 */
//因为下面要用到ACMD41,是ACMD命令,在发送ACMD命令前都要先向卡发送CMD55
/*!< SEND CMD55 APP_CMD with RCA as 0 */
SDIO_CmdInitStructure.SDIO_Argument = 0x00;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_APP_CMD; //CMD55
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);//没响应CMD55,返回
}
//acmd41,命令参数由支持的电压范围及HCS位组成,HCS位置一来区分卡是SDSc还是sdhc
/* ACMD41: SD_SEND_OP_COND */
/* 发送 ACMD41 要求卡发送操作条件寄存器(OCR) */
/* 参数: - : 保留('0')
- : 主机容量支持(HCS) SDType = 0x40000000
- : VDD电压窗口 SD_VOLTAGE_WINDOW_SD = 0x00100000(3.2~3.3V) */
/* 响应类型: R3 */
SDIO_CmdInitStructure.SDIO_Argument = SD_VOLTAGE_WINDOW_SD | SDType; //参数为主机可供电压范围及hcs位
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SD_APP_OP_COND;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;//r3
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);//没正确接收到acmd41,出错,返回
}
/* 从SDIO_RESP1寄存器中读取响应R3(OCR),并解析 */
/*若卡需求电压在SDIO的供电电压范围内,会自动上电并标志pwr_up位*/
response = SDIO_GetResponse(SDIO_RESP1); //读取卡寄存器,卡状态
/* 判断busy位(OCR)是否为1(busy=1,表示ACMD41的初始化完成) */
validvoltage = (((response >> 31) == 1) ? 1 : 0); //读取卡的ocr寄存器的pwr_up位,看是否已工作在正常电压
count++; //计算循环次数
}
/* 如果尝试了 SD_MAX_VOLT_TRIAL 次,初始化还没有完成,则VDD电压窗口(3.2~3.3V)是无效的 */
if (count >= SD_MAX_VOLT_TRIAL) //循环检测超过一定次数还没上电
{
errorstatus = SD_INVALID_VOLTRANGE; //SDIO不支持card的供电电压
return(errorstatus);
}
/*检查卡返回信息中的HCS位*/
/* 判断CCS位(OCR)是否为1(CCS=1,表示卡是高容量SD卡) */
if (response &= SD_HIGH_CAPACITY)//判断ocr中的ccs位 ,如果是sdsc卡则不执行下面的语句
{
CardType = SDIO_HIGH_CAPACITY_SD_CARD;//把卡类型从初始化的sdsc型改为sdhc型
}
}/*!< else MMC Card *//* 否则是 MMC 卡 */
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 */
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 = SDIO_GetResponse(SDIO_RESP1);
CID_Tab = SDIO_GetResponse(SDIO_RESP2);
CID_Tab = SDIO_GetResponse(SDIO_RESP3);
CID_Tab = SDIO_GetResponse(SDIO_RESP4);
}
/*下面开始SD卡初始化流程*/
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)) //使用的是2.0的卡
{
/*!< 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; //cmd3
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; //r6
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 = SDIO_GetResponse(SDIO_RESP1);
CSD_Tab = SDIO_GetResponse(SDIO_RESP2);
CSD_Tab = SDIO_GetResponse(SDIO_RESP3);
CSD_Tab = SDIO_GetResponse(SDIO_RESP4);
}
errorstatus = SD_OK; /*!< All cards get intialized */
return(errorstatus);
}
阅读(1613) | 评论(0) | 转发(0) |