步骤:
/**
* @brief Card Specific Data: CSD Register
*/
typedef struct
{
/***省略若干行***/
__IO uint8_t RdBlockLen; /*!< Max. read data block length V1.0计算公式要用到*/
/***省略若干行***/
__IO uint32_t DeviceSize; /*!< Device Size V1.0和V2.0计算公式都要用到*/
/***省略若干行***/
__IO uint8_t DeviceSizeMul; /*!< Device size multiplier */
/***省略若干行***/
} SD_CSD;
/**
* @brief SD Card information
* 这个结构体包含了SD卡的CSD寄存器和CID寄存器,这里我们只讨论CSD寄存器
*/
typedef struct
{
SD_CSD SD_csd;
SD_CID SD_cid;
uint32_t CardCapacity; /*!< Card Capacity */
uint32_t CardBlockSize; /*!< Card Block Size */
uint16_t RCA;
uint8_t CardType;
} SD_CardInfo; //此结构体将上面两个结构体都包含了;
/**
* @brief Returns information about specific card.
* @param cardinfo: pointer to a SD_CardInfo structure that contains all SD card
* information.
* @retval SD_Error: SD Card Error code.
*/
SD_Error SD_GetCardInfo(SD_CardInfo *cardinfo)
{
SD_Error errorstatus = SD_OK;
uint8_t tmp = 0;
/*************************************************************/
/*****************SD_CardInfo结构体填充****************/
/*************************************************************/
cardinfo->CardType = (uint8_t)CardType;
cardinfo->RCA = (uint16_t)RCA;
/**********************************************/
/*****************CSD结构体填充****************/
/**********************************************/
/*!< 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 = (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;
/***省略若干行***/
return(errorstatus);
}
//代码来自上面历程
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; //最终计算的结果,以字节为单位;
//代码来自上面历程
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 512 * 1024; //最终计算的结果,以字节为单位;
cardinfo->CardBlockSize = 512;
特别注意:尤其是V2.0的SD卡最大可以达到32G类型,防止溢出;
问题:在对SD卡进行FatFS系统移植的时候,我在实验中发现STM32官方提供的SD卡程序只能支持0~4G以内的SD卡(其实不能说是BUG,严格的说是一个移植不兼容的问题);详细问题情况如下:
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res = RES_PARERR;
switch (pdrv) {
case DEV_SPI_FLASH :
return res;
case DEV_SDHC :
switch(cmd)
{
/* Generic command (Used by FatFs) */
case CTRL_SYNC: res = RES_OK;break; //确保设备完成了等待写过程,也就是设备数据缓冲区内的数据写入了存储介质;
case GET_SECTOR_COUNT: //获取存储设备中可用扇区数值返回到buff所指向的DWORD中;
*(DWORD*)buff = SDCardInfo.CardCapacity/SDCardInfo.CardBlockSize;
res = RES_OK;break;
case GET_SECTOR_SIZE: //获取存储设备中扇区大小返回到buff所指向的DWORD中;
*(DWORD*)buff = SDCardInfo.CardBlockSize;//SDCardInfo.CardBlockSize; //扇区大小等于块大小;
res = RES_OK;
break;
case GET_BLOCK_SIZE: //GET_BLOCK_SIZE:以扇区为单位,将擦除块大小返回到buff指向的DWORD变量;
*(DWORD*)buff = 1;
res = RES_OK;
break;
case CTRL_TRIM: //告诉设备此扇区块(cmd中包含的地址)不再需要,可以擦除;
res = RES_OK;
break;
default:;break;
}
return res;
}
return RES_PARERR;
}
(DWORD)buff = SDCardInfo.CardCapacity/SDCardInfo.CardBlockSize; 是问题的原因,在准确点说是: SDCardInfo.CardCapacity这个结构体成员的值发生了错误,然而导致这个问题的原因是如下代码:
cardinfo->CardCapacity = (cardinfo->SD_csd.DeviceSize + 1) * 512 * 1024; //最终计算的结果,以字节为单位;
cardinfo->CardBlockSize = 512;
对,就是V2.0的计算公式;然而再准确的说,原因是:cardinfo->SD_csd.DeviceSize这个成员变量的数据类型,如下定义:
__IO uint32_t DeviceSize; /*!< Device Size V1.0和V2.0计算公式都要用到*/
通过计算可知:uint32_t的最大表示值为0xFFFF FFFF = (4GB-1Byte),如果超出4G,则势必会发生溢出,从而导致数据错误,再引起分区错误;