STM32F4X SDIO(七) 例程讲解-SD_InitializeCards SD_GetCardInfo
最佳答案 问答题库598位专家为你答疑解惑
STM32F4X SDIO(七)例程讲解-SD_InitializeCards & SD_GetCardInfo
- 例程讲解-SD_InitializeCards & SD_GetCardInfo
- CMD2:ALL_SEND_CID
- 命令发送程序
- 命令响应程序
- CID数据解析
- CMD3:SEND_RELATIVE_ADDR
- 命令发送程序
- 命令响应程序
- CMD9:SEND_CSD
- 命令发送程序
- 命令响应程序
- CSD数据解析
- CSD结构版本
- READ_BL_LEN
- SD卡容量
- 获取SD卡信息
- SD卡初始化流程
本节例程基于 野火电子的STM32F407的SD卡读写例程进行讲解。上一节中讲解了SD卡上电过程,这节将会讲解一下SD卡的初始化过程,包括 获取SD卡的CID、CSD和SD卡RCA地址。
例程讲解-SD_InitializeCards & SD_GetCardInfo
CMD2:ALL_SEND_CID
CMD2的作用是通知所有卡通过CMD线返回CID值,CID值包括SD卡的识别号、制造商ID、OEMID、产品名称、版本号、序列号等信息,相当于是SD卡的身份证。
命令发送程序
CMD2命令无需带参数,所以SDIO控制器可以直接发送CMD2命令
SDIO_CmdInitStructure.SDIO_Argument = 0x0; // 不带参数SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_ALL_SEND_CID; // 命令所以为CMD2SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long; // 长响应SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // 不等待SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // 使能CPSM状态机SDIO_SendCommand(&SDIO_CmdInitStructure);
命令响应程序
CMD2的响应是R2,其响应类型为长响应。其中bit[127:1]是其响应的数据。
首先需要先判断SD卡的响应是否正常,如果响应正常,下一步就需要把128位的CID读出来。
static SD_Error CmdResp2Error(void)
{SD_Error errorstatus = SD_OK;uint32_t status;status = SDIO->STA;while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CTIMEOUT | SDIO_FLAG_CMDREND))){status = SDIO->STA;}if (status & SDIO_FLAG_CTIMEOUT){errorstatus = SD_CMD_RSP_TIMEOUT;SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);return(errorstatus);}else if (status & SDIO_FLAG_CCRCFAIL){errorstatus = SD_CMD_CRC_FAIL;SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);return(errorstatus);}/*!< Clear all the static flags */SDIO_ClearFlag(SDIO_STATIC_FLAGS);return(errorstatus);
}
// 读取128位CIDCID_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);
根据STM32F4X的数据手册可知,如果是长响应,高位的数据保存在SDIO_RESP1寄存器,低位保存在SDIO_RESP4寄存器
CID数据解析
根据波形图可知SD卡的CID响应数据为0x9f54495344333247614af80704017158,CID的数据解析表如下
下面就来对SD卡读取到CID数据进行解析
"SD32G"Product revisionPRV8[63:56]0x61 Product serial numberPSN32[55:24]0x4af80704reservedX4[23:20]0Manufacturing dateMDT12[19:8]0x171CRC7 checksumCRC7[7:1]0x2Cnot used, always 1x1[0:0]0x1
CMD3:SEND_RELATIVE_ADDR
CMD3的作用是请求SD卡发布一个RCA,RCA的作用相当于是一个地址,这个RCA后续在读写SD卡中用于对SD卡进行寻址。
命令发送程序
SDIO_CmdInitStructure.SDIO_Argument = 0x00; // 不带参数SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_REL_ADDR; // 命令索引 CMD3SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short; // 短响应SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // 不等待SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // 使能 CPSM状态机SDIO_SendCommand(&SDIO_CmdInitStructure);
命令响应程序
CMD3的响应是R6,其中SD卡的RCA在响应数据的bit[31:16]
在程序中会先判断SD卡的响应是否正常,如果响应正常就通过SDIO_RESP1寄存器读取R6响应的数据,然后保存高16位的RCA地址。
static SD_Error CmdResp6Error(uint8_t cmd, uint16_t *prca)
{SD_Error errorstatus = SD_OK;uint32_t status;uint32_t response_r1;status = SDIO->STA;while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CTIMEOUT | SDIO_FLAG_CMDREND))){status = SDIO->STA;}if (status & SDIO_FLAG_CTIMEOUT){errorstatus = SD_CMD_RSP_TIMEOUT;SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);return(errorstatus);}else if (status & SDIO_FLAG_CCRCFAIL){errorstatus = SD_CMD_CRC_FAIL;SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);return(errorstatus);}/*!< Check response received is of desired command */if (SDIO_GetCommandResponse() != cmd){errorstatus = SD_ILLEGAL_CMD;return(errorstatus);}/*!< Clear all the static flags */SDIO_ClearFlag(SDIO_STATIC_FLAGS);/*!< We have received response, retrieve it. */response_r1 = SDIO_GetResponse(SDIO_RESP1);if (SD_ALLZERO == (response_r1 & (SD_R6_GENERAL_UNKNOWN_ERROR | SD_R6_ILLEGAL_CMD | SD_R6_COM_CRC_FAILED))){*prca = (uint16_t) (response_r1 >> 16);return(errorstatus);}if (response_r1 & SD_R6_GENERAL_UNKNOWN_ERROR){return(SD_GENERAL_UNKNOWN_ERROR);}if (response_r1 & SD_R6_ILLEGAL_CMD){return(SD_ILLEGAL_CMD);}if (response_r1 & SD_R6_COM_CRC_FAILED){return(SD_COM_CRC_FAILED);}return(errorstatus);
}
CMD9:SEND_CSD
CMD9的作用是获取SD卡的CSD数据,CSD数据主要包含SD卡一些基本状态信息,包括SD的块大小、SD卡传输速率、SD卡的擦除扇区大小等信息。CMD9命令需要带参数,其参数是SD卡的RCA地址。
命令发送程序
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t)(rca << 16); // 参数RCA地址SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SEND_CSD; // 命令索引 CMD9SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Long; // 长响应SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No; // 不等待SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable; // 使能CPSM状态机SDIO_SendCommand(&SDIO_CmdInitStructure);
命令响应程序
CMD9的响应是R2,长响应,CSD的返回数据是128位。
static SD_Error CmdResp2Error(void)
{SD_Error errorstatus = SD_OK;uint32_t status;status = SDIO->STA;while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CTIMEOUT | SDIO_FLAG_CMDREND))){status = SDIO->STA;}if (status & SDIO_FLAG_CTIMEOUT){errorstatus = SD_CMD_RSP_TIMEOUT;SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);return(errorstatus);}else if (status & SDIO_FLAG_CCRCFAIL){errorstatus = SD_CMD_CRC_FAIL;SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);return(errorstatus);}/*!< Clear all the static flags */SDIO_ClearFlag(SDIO_STATIC_FLAGS);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);
CSD的数据读取跟CID的数据读取是一样,不同的是两个数据的解析方法不一样
CSD数据解析
从波形图可知CSD的数据为0x400e00325b590000e68f7f800a400018,下面就对读取到的CSD数据进行解析。
"SD32G"data read access-time-2 in CLK cycles (NSAC*100)NSAC8[111:104]0x0max. data transfer rateTRAN_SPEED8[103:96]0x32card command classesCCC12[95:84]0x5b5max. read data block lengthREAD_BL_LEN4[83:80]0x9partial blocks for read allowedREAD_BL_PARTIAL1[79:79]0x0write block misalignmentWRITE_BLK_MISALIGN1[78:78]0x0read block misalignmentREAD_BLK_MISALIGN1[77:77]0x0DSR implementedDSR_IMP1[76:76]0x0reservedX6[75:70]0x0device sizeC_SIZE22[69:48]0xE68FreservedX1[47:47]0x0erase single block enableERASE_BLK_EN1[46:46]0x1erase sector sizeSECTOR_SIZE7[45:39]0x7Fwrite protect group sizeWP_GRP_SIZE7[39:32]0x0write protect group enableWP_GRP_ENABLE1[31:31]0x0reservedX2[30:29]0x0write speed factorR2W_FACTOR2[28:26]0x2max. write data block lengthWRITE_BL_LEN4[25:22]0x9partial blocks for write allowedWRITE_BL_PARTIAL1[21:21]0x0reservedX5[20:16]0x0File format groupFILE_FORMAT_GRP1[15:15]0x0copy flagCOPY1[14:14]0x0permanent write protectionPERM_WRITE_PROTECT1[13:13]0x0temporary write protectionTMP_WRITE_PROTECT1[12:12]0x0File formatFILE_FORMAT2[11:10]0x0reservedX2[9:8]0x0CRCCRC7[7:1]0xCnot used, always'1'X1[0:0]0x1
CSD结构版本
CSD_STRUCTURE区域代表的是CSD寄存器结构使用的解析版本号,在SD卡的发展中使用了不同的CSD版本,在上面的例程中CSD_STRUCTURE的值是0x01,则代表使用的CSD V2.0的版本
READ_BL_LEN
最大的数据块读取长度,数值为9则代表是512字节
SD卡容量
根据上面的CSD数据我们可以计算出SD卡的容量大小,其计算公式如下memory capacity = (C_SIZE+1) * 512KByte
memory capacity = (0xE68F + 1) * 512 = 30,220,288(Byte) = 29512(M) = 28G
获取SD卡信息
MCU读取到SD卡的CSD和CID数据后,就可以根据上面的表格进行数据的解析
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{SD_Error errorstatus = SD_OK;uint8_t tmp = 0;cardinfo->CardType = (uint8_t)CardType;cardinfo->RCA = (uint16_t)RCA;/*!< Byte 0 */tmp = (uint8_t)((CSD_Tab[0] & 0xFF000000) >> 24);cardinfo->SD_csd.CSDStruct = (tmp & 0xC0) >> 6;cardinfo->SD_csd.SysSpecVersion = (tmp & 0x3C) >> 2;cardinfo->SD_csd.Reserved1 = tmp & 0x03;/*!< Byte 1 */tmp = (uint8_t)((CSD_Tab[0] & 0x00FF0000) >> 16);cardinfo->SD_csd.TAAC = tmp;/*!< Byte 2 */tmp = (uint8_t)((CSD_Tab[0] & 0x0000FF00) >> 8);cardinfo->SD_csd.NSAC = tmp;/*!< Byte 3 */tmp = (uint8_t)(CSD_Tab[0] & 0x000000FF);cardinfo->SD_csd.MaxBusClkFrec = tmp;/*!< Byte 4 */tmp = (uint8_t)((CSD_Tab[1] & 0xFF000000) >> 24);cardinfo->SD_csd.CardComdClasses = tmp << 4;/*!< Byte 5 */tmp = (uint8_t)((CSD_Tab[1] & 0x00FF0000) >> 16);cardinfo->SD_csd.CardComdClasses |= (tmp & 0xF0) >> 4;cardinfo->SD_csd.RdBlockLen = tmp & 0x0F;/*!< Byte 6 */tmp = (uint8_t)((CSD_Tab[1] & 0x0000FF00) >> 8);cardinfo->SD_csd.PartBlockRead = (tmp & 0x80) >> 7;cardinfo->SD_csd.WrBlockMisalign = (tmp & 0x40) >> 6;cardinfo->SD_csd.RdBlockMisalign = (tmp & 0x20) >> 5;cardinfo->SD_csd.DSRImpl = (tmp & 0x10) >> 4;cardinfo->SD_csd.Reserved2 = 0; /*!< Reserved */if ((CardType == SDIO_STD_CAPACITY_SD_CARD_V1_1) || (CardType == SDIO_STD_CAPACITY_SD_CARD_V2_0)){cardinfo->SD_csd.DeviceSize = (tmp & 0x03) << 10;/*!< Byte 7 */tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);cardinfo->SD_csd.DeviceSize |= (tmp) << 2;/*!< Byte 8 */tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);cardinfo->SD_csd.DeviceSize |= (tmp & 0xC0) >> 6;cardinfo->SD_csd.MaxRdCurrentVDDMin = (tmp & 0x38) >> 3;cardinfo->SD_csd.MaxRdCurrentVDDMax = (tmp & 0x07);/*!< Byte 9 */tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);cardinfo->SD_csd.MaxWrCurrentVDDMin = (tmp & 0xE0) >> 5;cardinfo->SD_csd.MaxWrCurrentVDDMax = (tmp & 0x1C) >> 2;cardinfo->SD_csd.DeviceSizeMul = (tmp & 0x03) << 1;/*!< Byte 10 */tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);cardinfo->SD_csd.DeviceSizeMul |= (tmp & 0x80) >> 7;cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) ;cardinfo->CardCapacity *= (1 << (cardinfo->SD_csd.DeviceSizeMul + 2));cardinfo->CardBlockSize = 1 << (cardinfo->SD_csd.RdBlockLen);cardinfo->CardCapacity *= cardinfo->CardBlockSize;}else if (CardType == SDIO_HIGH_CAPACITY_SD_CARD){/*!< Byte 7 */tmp = (uint8_t)(CSD_Tab[1] & 0x000000FF);cardinfo->SD_csd.DeviceSize = (tmp & 0x3F) << 16;/*!< Byte 8 */tmp = (uint8_t)((CSD_Tab[2] & 0xFF000000) >> 24);cardinfo->SD_csd.DeviceSize |= (tmp << 8);/*!< Byte 9 */tmp = (uint8_t)((CSD_Tab[2] & 0x00FF0000) >> 16);cardinfo->SD_csd.DeviceSize |= (tmp);/*!< Byte 10 */tmp = (uint8_t)((CSD_Tab[2] & 0x0000FF00) >> 8);cardinfo->CardCapacity = ((uint64_t)cardinfo->SD_csd.DeviceSize + 1) * 512 * 1024;cardinfo->CardBlockSize = 512; }cardinfo->SD_csd.EraseGrSize = (tmp & 0x40) >> 6;cardinfo->SD_csd.EraseGrMul = (tmp & 0x3F) << 1;/*!< Byte 11 */tmp = (uint8_t)(CSD_Tab[2] & 0x000000FF);cardinfo->SD_csd.EraseGrMul |= (tmp & 0x80) >> 7;cardinfo->SD_csd.WrProtectGrSize = (tmp & 0x7F);/*!< Byte 12 */tmp = (uint8_t)((CSD_Tab[3] & 0xFF000000) >> 24);cardinfo->SD_csd.WrProtectGrEnable = (tmp & 0x80) >> 7;cardinfo->SD_csd.ManDeflECC = (tmp & 0x60) >> 5;cardinfo->SD_csd.WrSpeedFact = (tmp & 0x1C) >> 2;cardinfo->SD_csd.MaxWrBlockLen = (tmp & 0x03) << 2;/*!< Byte 13 */tmp = (uint8_t)((CSD_Tab[3] & 0x00FF0000) >> 16);cardinfo->SD_csd.MaxWrBlockLen |= (tmp & 0xC0) >> 6;cardinfo->SD_csd.WriteBlockPaPartial = (tmp & 0x20) >> 5;cardinfo->SD_csd.Reserved3 = 0;cardinfo->SD_csd.ContentProtectAppli = (tmp & 0x01);/*!< Byte 14 */tmp = (uint8_t)((CSD_Tab[3] & 0x0000FF00) >> 8);cardinfo->SD_csd.FileFormatGrouop = (tmp & 0x80) >> 7;cardinfo->SD_csd.CopyFlag = (tmp & 0x40) >> 6;cardinfo->SD_csd.PermWrProtect = (tmp & 0x20) >> 5;cardinfo->SD_csd.TempWrProtect = (tmp & 0x10) >> 4;cardinfo->SD_csd.FileFormat = (tmp & 0x0C) >> 2;cardinfo->SD_csd.ECC = (tmp & 0x03);/*!< Byte 15 */tmp = (uint8_t)(CSD_Tab[3] & 0x000000FF);cardinfo->SD_csd.CSD_CRC = (tmp & 0xFE) >> 1;cardinfo->SD_csd.Reserved4 = 1;/*!< Byte 0 */tmp = (uint8_t)((CID_Tab[0] & 0xFF000000) >> 24);cardinfo->SD_cid.ManufacturerID = tmp;/*!< Byte 1 */tmp = (uint8_t)((CID_Tab[0] & 0x00FF0000) >> 16);cardinfo->SD_cid.OEM_AppliID = tmp << 8;/*!< Byte 2 */tmp = (uint8_t)((CID_Tab[0] & 0x000000FF00) >> 8);cardinfo->SD_cid.OEM_AppliID |= tmp;/*!< Byte 3 */tmp = (uint8_t)(CID_Tab[0] & 0x000000FF);cardinfo->SD_cid.ProdName1 = tmp << 24;/*!< Byte 4 */tmp = (uint8_t)((CID_Tab[1] & 0xFF000000) >> 24);cardinfo->SD_cid.ProdName1 |= tmp << 16;/*!< Byte 5 */tmp = (uint8_t)((CID_Tab[1] & 0x00FF0000) >> 16);cardinfo->SD_cid.ProdName1 |= tmp << 8;/*!< Byte 6 */tmp = (uint8_t)((CID_Tab[1] & 0x0000FF00) >> 8);cardinfo->SD_cid.ProdName1 |= tmp;/*!< Byte 7 */tmp = (uint8_t)(CID_Tab[1] & 0x000000FF);cardinfo->SD_cid.ProdName2 = tmp;/*!< Byte 8 */tmp = (uint8_t)((CID_Tab[2] & 0xFF000000) >> 24);cardinfo->SD_cid.ProdRev = tmp;/*!< Byte 9 */tmp = (uint8_t)((CID_Tab[2] & 0x00FF0000) >> 16);cardinfo->SD_cid.ProdSN = tmp << 24;/*!< Byte 10 */tmp = (uint8_t)((CID_Tab[2] & 0x0000FF00) >> 8);cardinfo->SD_cid.ProdSN |= tmp << 16;/*!< Byte 11 */tmp = (uint8_t)(CID_Tab[2] & 0x000000FF);cardinfo->SD_cid.ProdSN |= tmp << 8;/*!< Byte 12 */tmp = (uint8_t)((CID_Tab[3] & 0xFF000000) >> 24);cardinfo->SD_cid.ProdSN |= tmp;/*!< Byte 13 */tmp = (uint8_t)((CID_Tab[3] & 0x00FF0000) >> 16);cardinfo->SD_cid.Reserved1 |= (tmp & 0xF0) >> 4;cardinfo->SD_cid.ManufactDate = (tmp & 0x0F) << 8;/*!< Byte 14 */tmp = (uint8_t)((CID_Tab[3] & 0x0000FF00) >> 8);cardinfo->SD_cid.ManufactDate |= tmp;/*!< Byte 15 */tmp = (uint8_t)(CID_Tab[3] & 0x000000FF);cardinfo->SD_cid.CID_CRC = (tmp & 0xFE) >> 1;cardinfo->SD_cid.Reserved2 = 1;return(errorstatus);
}
SD卡初始化流程
- 发送CMD2获取CID数据
- 发送CMD3获取SD卡的RCA地址
- 发送CMD9获取SD卡的CSD数据
- 根据CID和CSD表格解析数据
99%的人还看了
猜你感兴趣
版权申明
本文"STM32F4X SDIO(七) 例程讲解-SD_InitializeCards SD_GetCardInfo":http://eshow365.cn/6-33812-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!