《电子技术应用》
您所在的位置:首页 > 模拟设计 > 设计应用 > 基于MCF51QE128的SD卡接口设计
基于MCF51QE128的SD卡接口设计
摘要: SD (Secure Digital)卡是一种基于闪存技术的可移动存储设备,由于其体积小、功耗低、容量大且成本低,广泛应用于各类小型便携式电子设备中。本文实现了SD卡与Freescale公司的32位低功耗微控制器MCF51QE128之间的软硬件接口设计,可作为数据记录仪、媒体播放器和录音设备等的设计参考。
Abstract:
Key words :

 

SD卡标准

  SD卡标准是SD卡协会针对可移动存储设备设计专利并授权的一种标准,主要用于制定卡的外形尺寸、电气接口和通信协议。

1.1  SD卡引脚功能


图1  SD卡外形

  SD卡的外形如图1所示,引脚功能如表1所列。SD卡的引脚具有双重功能,既可工作在SD模式,也可工作在SPI模式。不同的模式下,引脚的功能不同。

表1  SD卡引脚功能

  SD模式多用于对SD卡读写速度要求较高的场合,SPI模式则是以牺牲读写速度换取更好的硬件接口兼容性。由于SPI协议是目前广泛流行的通信协议,大多数高性能单片机都配备了SPI硬件接口,硬件连接相对简单,因此,在对SD卡读写速度要求不高的情况下,采用SPI模式无疑是一个不错的选择。

1.2  SPI模式

  SPI模式是一种简单的命令响应协议,主控制器发出命令后,SD卡针对不同的命令返回对应的响应。

  SD卡的命令列表都是以CMD和ACMD开头,分别指通用命令和专用命令,后面接命令的编号。例如,CMD17就是一个通用命令,用来读单块数据。

  在SPI模式中,命令都是以如下的6字节形式发送的:

  每帧命令都以“01”开头,然后是6位命令号和4字节的参数(高位在前,低位在后),最后是7位CRC校验和1位停止位“1”。

表2  R1响应格式

  SD卡的每条命令都会返回对应的响应类型。在SPI模式下,共有3种响应类型:R1、R2和R3,分别占1、2和3个字节。这里仅列出了R1响应的格式,如表2所列。当出现表中所描述的状态时,相应的位置1。R2和R3的第1个字节格式与R1完全一样,详细内容请参考SD卡标准。

2  硬件设计

  本设计选用Freescale公司的32位低功耗微控制器MCF51QE128,采用SPI模式实现与SD卡的接口。

  由于MCF51QE128是一款低功耗的微控制器,工作电压的典型值为3.6 V,与SD卡的工作电压兼容,因而可以直接与SD卡连接,无需电平转换电路。这里选用的是MCF51QE128的第2个SPI口,硬件连接如图2所示。


图2  SD卡与MCF51QE128的硬件连接

3  软件实现

  软件部分主要实现MCF51QE128的初始化、底层SPI通信,以及SD卡的通用写命令、初始化和单块数据的读写等功能。

3.1  MCF51QE128的初始化

  在与SD卡通信之前,首先需要配置MCF51QE128,并初始化SPI端口。代码如下:

//定义片选信号
#define select_card() PTDD_PTDD3 = 0
#define unselect_card()  PTDD_PTDD3 = 1
void MCU_Init(void) {
  SOPT1 = 0x23;//关看门狗
  SCGC1 = 0x00;//禁用其他外设的总线时钟
  SCGC2 = 0x02;//开SPI2模块的总线时钟
  PTDDD = 0x08;//SPI片选信号由软件设置
}
void SPI_Init (void) {
  SPI2BR = 0x44;//设初始SPI时钟为400 kHz
  SPI2C1 = 0xD0;//SPI 中断允许,系统中断允许,主模式选择
  SPI2C2 = 0x00;
}

3.2  底层SPI通信

  底层的SPI通信是实现最终读写的关键。由于MCF51QE128自带SPI硬件接口,因此只需要读写SPI数据寄存器的值。这里自定了byte、word和dword三种数据类型,分别对应于8位、16位和32位数据。代码如下:

byte SPI_ReadByte(void) {//SPI读字节函数
  while (!SPI2S_SPTEF);//等待,直到发送寄存器为空
  SPI2D = 0xff;//接收1字节数据
  while (!SPI2S_SPRF);
  return SPI2D;
}
byte SPI_WriteByte(byte val) {//SPI写字节函数
  while ((!SPI2S_SPTEF)&&(!PTDD_PTDD3));//等待,直到发送寄存器为空
  SPI2D = val;//发送数据
}

3.3  SD卡的通用写命令

  由于SD卡的命令具有统一的格式,因此可以用一个通用的写命令函数来实现所有命令的发送。另外,考虑到多数命令的响应类型都是R1,这里的通用写命令函数所接收的响应类型默认为R1。函数代码如下:

byte SD_SendCommand_R1(byte cmd, dword arg) {
  byte i,r1;
  SPI_WriteByte(0xff);//等待几个时钟周期
  SPI_WriteByte((byte)(cmd|0x40));//写入命令号
  SPI_WriteByte((byte)(arg>>24));//4字节命令参数
  SPI_WriteByte((byte)(arg>>16));
  SPI_WriteByte((byte)(arg>>8));
  SPI_WriteByte((byte)(arg));
  SPI_WriteByte((byte)(cmd == 0x00? 0x95 : 0xff));//CRC校验和
  for(i = 0; i < 10; ++i) {//接收响应
    r1 = SPI_ReadByte();
    if(r1 != 0xff) break;
  }
  return r1;
}

3.4  SD卡的初始化

  SD卡的初始化要遵循一定的步骤。首先将SPI时钟降低到400 kHz,等待至少74个时钟周期。接着拉低片选信号,并发送CMD0命令,对SD卡进行复位并使其进入SPI模式,这里需要正确的CRC校验,校验字节为0x95。若SD卡进入空闲状态(即接收响应为0x01时),则发送CMD1命令,激活卡的初始化过程,此时响应为0x00。然后设置块的长度,一般为512字节。最后将片选拉高并将SPI时钟设为最大值,以保证最大的读写速度。SD卡初始化过程如图3所示。


图3  SD卡初始化过程

  SD卡初始化代码如下:

byte SD_Init(void) {
  word i;
  byte response;
  for(i=0;i<10;i++)SPI_ReadByte();//等待至少74个时钟周期
  select_card();//片选拉低
  for(i = 0; ; i++) {
    response = SD_SendCommand_R1(0x00,0);//发送CMD0
    if(response == 0x01) break;//进入空闲状态
    if(i == 0x1ff) {
      unselect_card();
      return 0;
    }
  }
  for(i = 0; ; i++) {
    response = SD_SendCommand_R1(0x01,0);//发送CMD1,激活卡的初始化
    if(response == 0x00) break;
    if(i == 0x1ff) {
      unselect_card();
      return 0;
    }
  } 
  if(SD_SendCommand_R1(0x10, 512)) {//设置块长度为512字节
    unselect_card();
    return 0;
  }
  unselect_card();//片选拉高SPI2BR = 0x40;选择最高SPI时钟
  return 1;
}

3.5  SD卡单块数据读写

  SPI模式支持单块和多块数据的读写操作,可通过发送相应的命令来实现。读单块数据的操作过程如图4所示。拉低片选后,首先由主控制器MCF51QE128发送读单块数据命令CMD17,然后等待SD卡的响应。当收到数据块开始标志0xfe后,开始从SD卡读取512字节的数据,最后读取2字节的CRC校验位。


图4  读单块数据操作

  读单块数据的函数代码如下:

byte SD_ReadSingleBlock(byte data[], dword sector) {
  word i;
  select_card();
  if(SD_SendCommand_R1(0x11, sector)) {//发送读单块数据命令CMD17
    unselect_card();
    return 0;
  }
  while(SPI_ReadByte() != 0xfe) ;//等待,直到收到数据块开始标志0xfe
  for(i = 0; i < 512; i++)  data[i] = SPI_ReadByte();//读512字节数据块
  SPI_ReadByte();//读16位CRC校验
  SPI_ReadByte();
  unselect_card();
  SPI_ReadByte();
  return 1;
}

  写单块数据的操作过程与读操作类似,如图5所示。拉低片选后同样由主控制器MCF51QE128发送写单块数据命令CMD24,SD卡正确响应后发送数据块开始标志0xfe,接着发送512字节数据块和2字节CRC校验。


图5  写单块数据操作

  写入数据后,SD卡会发送1字节的数据响应来反馈数据写入的情况,其格式如图6所示。当数据正确写入SD卡后,数据响应为0x05。最后读数据总线,写数据忙时等待,直到总线为高电平。


图6  数据响应格式

  写单块数据的函数代码如下:

byte SD_WriteSingleBlock(byte data[], dword sector) {
  word i;
  byte response;
  select_card();
  if(SD_SendCommand_R1(0x18, sector)) {//发送写单块数据命令CMD24
    unselect_card();
    return 0;
  }
  SPI_WriteByte(0xfe);//发送数据块开始标志0xfe
  for(i = 0; i < 512; i++)SPI_WriteByte(data[i]);//写512字节数据块
  SPI_WriteByte(0xff); //写16位CRC校验
  SPI_WriteByte(0xff);
  for(i = 0; ; i++) {//读数据响应,判断数据是否//正确写入
    response = SPI_ReadByte();
    if((response & 0x0f) == 0x05) break;
    if(i == 0x1ff) {
      unselect_card();
      return 0;
    }
  }
  while(SPI_ReadByte() != 0xff) ;//写数据忙时,等待
  SPI_ReadByte();
  unselect_card();
  return 1;
}

结语

  SD卡是目前广泛应用的可擦除的大容量存储设备,其接口设计可作为各类嵌入式系统中存储单元的一般解决方案。本文结合SD卡标准的相关技术,基于MCF51QE128微控制器完成了硬件接口和底层通信软件的设计。在此基础上,可进一步构建文件系统,实现对存储数据更有效的管理。

此内容为AET网站原创,未经授权禁止转载。