单片机读取SD卡CSD寄存器获取容量详解(V1.0&V2.0)

  • 学习12811次

目前,SD卡CSD寄存器有V1.0和V2.0两个版本。

下面是V1.0和V2.0的CSD寄存器各位的定义表格。

SDCSDV10

sdcsdv20

1.单片机如何识别SD卡是V1.0还是V2.0的?

答:CSD寄存器为128个位,即16个字节。通过检测CSD寄存器的bit126是0还是1来判断。如果是0,即是V1.0版本的;如果是1,即是V2.0版本的。

单片机获取CSD数据流程(SPI方式):定义一个数组csd[16],CS引脚拉低,发送命令9,然后SPI发送命令0xff,同时观察SPI接收到的数据,如果数据不是0xfe,就再发送0xff,如此循环,直到接收到0xfe,就可以开始接收16个字节CSD寄存器数据了,这16个字节即CSD的128个位,接收完16个字节数据以后,然后再发送两个0xff,把CS拉高,再发送一个0xff,就完成了。

csd[0]是CSD寄存器的bit120~127,csd[15]是CSD寄存器的bit0~7。也就是说数据是从高位开始发送。

列个表格方便写程序:

CSD位与接收数组的对应关系

uint8_t SD_GetCSD(uint8_t *csd_data)
{
  uint8_t res;
  res=SD_SendCommand(CMD9,0,0xFF);
  if(res)return res;
  SD_ReceiveData(csd_data, 16, RELEASE);
  return 0;
}

uint8_t SD_ReceiveData(uint8_t *data, uint16_t len, uint8_t release)
{
  uint8_t n;
  uint16_t d;
  SD_CS_Low;
  if(SD_GetResponse(0xFE))
  {
    SD_CS_High;
    return 1;
  }
  while(len--)
  {
   *data=SPI0_communication(0xFF);
    data++;
  }

  SPI0_communication(0xFF);
  SPI0_communication(0xFF);
  if(release==RELEASE)
  {
    SD_CS_High;
    SPI0_communication(0xFF);
  }
  return 0;
}

uint8_t SD_GetResponse(uint8_t Response)
{
  uint16_t Count=0xFFF;
  while ((SPI0_communication(0XFF)!=Response)&&Count)Count--;
  if (Count==0)return MSD_RESPONSE_FAILURE;
  else return MSD_RESPONSE_NO_ERROR;
}
uint8_t SD_SendCommand(uint8_t cmd, uint32_t arg, uint8_t crc)
{
  uint8_t r1; 
  uint8_t repeat=0; 
  SD_CS_High;
  SPI0_communication(0xff);
  SPI0_communication(0xff); 
  SPI0_communication(0xff); 
  SD_CS_Low; 
  SPI0_communication(cmd | 0x40);//·Ö±ðдÈëÃüÁî
  SPI0_communication(arg >> 24);
  SPI0_communication(arg >> 16);
  SPI0_communication(arg >> 8);
  SPI0_communication(arg);
  SPI0_communication(crc); 

  while((r1=SPI0_communication(0xFF))==0xFF)
  {
    repeat++; 
    if(repeat>200)break; 
  } 

  SD_CS_High;

  SPI0_communication(0xFF);

  return r1;
} 	

2.V1.0容量的计算

从V1.0的CSD寄存器可以看到,关于容量的位如下所示:

CSD寄存器计算容量用到的位10

手册上提供的容量计算公式和方法如下:

SDCSIZE1

CSD位与接收数组的对应关系

C_SIZE是bit62~73,即共12个位,在接收到的数组中,位于csd[6]的低2位,csd[7]的8位,csd[8]的高2位。

C_SIZE = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) ;

C_SIZE_MULT是bit47~49,共3个位,在接收到的数组中,位与csd[10]的最高位和csd[9]的低两位。

C_SIZE_MULT = ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1);

READ_BL_LEN是bit80~83,共4个位,在接收的数组中,位于csd[5]的低四位。

READ_BL_LEN = csd[5] & 15;

技巧提示:上面的公式中,“&”符号用来清除不需要的位,如csd[6]&3,3写成二进制即0000 0011,即“把csd[6]寄存器的高6位清除,保留低2位”

需要用到的位都计算好了,就可以带入公式了。

由公式memory capacity = BLOCKNR*BLOCK_LEN和BLOCKNR=(C_SIZE+1)*MULT可得:

memory capacity = (C_SIZE+1)*MULT*BLOCK_LEN

公式中,3个参数在上面都计算好了,所以:

memory capacity = (C_SIZE+1)<<(C_SIZE_MULT+2+BLOCK_LEN);

计算出来的单位是字节。

如果需要转换成Kbyte,左移10位即可实现,也可以把结果除以1024,或者把上面的公式写成如下:

memory capacity = (C_SIZE+1)<<(C_SIZE_MULT+2+BLOCK_LEN-10);

技巧提示:c语言中,2的n次方,可以用1<<n(左移n位)来解决。例如2的1次方就是1左移1位,2的2次方就是1左移2位,2的3次方就是1左移3位……你可以自己举个例子算算。

3.V2.0容量的计算

V2.0的CSD寄存器中,关于容量的寄存器如下图所示:

SD卡CSDV20容量相关寄存器

V2.0只有1个C_SIZE和容量相关了,共22个位,从bit48~69,位于csd[7] csd[8] csd[9]

CSD位与接收数组的对应关系

手册上提供的公式和方法如下图所示:

sdcsize2

这个计算起来,比V1.0容易多了。乘以512,即左移9位。

csize = csd[9] + ((uint32_t)csd[8] << 8) + ((uint32_t)(csd[7] & 63) << 16) + 1;
Capacity = csize << 9;

注意:这时候算出来的容量单位是Kbyte,实际应用中,注意单位的转换。

1G=1024M, 1M=1024K,1K=1024byte

4.总结

读取SD卡CSD寄存器,通过bit126位判断遵循哪个协议,再计算容量。

uint32_t SD_GetCapacity(void)
{
  uint8_t csd[16];
  uint32_t Capacity;
  uint16_t n;
  uint16_t csize; 

  if(SD_GetCSD(csd)!=0) return 0; 

  if((csd[0]&0xC0)==0x40)//判断bit126是否为1
  { 
    csize = csd[9] + ((uint32_t)csd[8] << 8) + ((uint32_t)(csd[7] & 63) << 16) + 1;
    Capacity = csize << 9; 
  }
  else
  { 
    n = (csd[5] & 0x0F) + ((csd[10] & 0x80) >> 7) + ((csd[9] & 0x03) << 1) + 2;
    csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 0x03) << 10) + 1;
    Capacity = (uint32_t)csize << (n - 10);
  }
  return Capacity;
} 

此函数计算出来的容量单位为Kbyte,结果除以1024就是Mbyte,再除以1024就是Gbyte。2G的卡,结果可能是1.8G;8G的卡,结果可能是7.6G,代表用户可用的容量。

发表评论

关闭菜单