SD卡驱动介绍
一、介绍
1.SD 卡
安全数码卡, 它是在 MMC 的基础上发展而来, 是一种基于半导体快闪记忆器的新一代记忆设备。按容量分类,可以将SD 卡分为 3 类: SD 卡、 SDHC 卡、 SDXC 卡。SD卡(SDSC):0~2G SDHC卡:2~32G SDXC卡:32G~2T
2. SD的通讯模式
- SD 卡模式(通过 SD 总线通信):允许 4 线的高速数据传输,只能使用 3.3V 的 IO 电平,所以, MCU 一定要能够支持 3.3V 的 IO 端口输出。
- SPI 模式:同 SD 卡模式相比就是丧失了速度,在 SPI 模式下, CS/MOSI/MISO/CLK 都需要加 10~100K 左右的上拉电阻。
3.SD引脚定义
二、SD卡驱动介绍
1.SD寄存器介绍
名称 | 宽度 | 描述 |
---|---|---|
CID | 128 | 卡识别寄存器 |
CSD | 128 | 卡描述数据寄存器:卡操作条件相关的信息数据。 |
OCR | 32 | 操作条件寄存器 |
RCA | 16 | 相对卡地址寄存器:本地系统中卡的地址,动态变化,在卡的初始化时确定。(SPI模式中没有) |
SCR | 64 | SD配置寄存器:SD卡特定信息数据 |
2、SD卡识别流程
初始化过程
- 初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置, IO 口配置;
- 上电延时(>74 个 CLK)(因为 SD 卡内部有个供电电压上升时间,大概为 64 个 CLK,剩下的 10 个 CLK 用于 SD 卡同步,之后才能开始 CMD0 的操作);
- 复位卡(CMD0),进入 IDLE 状态;
- 发送 CMD8,检查是否支持 2.0 协议;
- 根据不同协议检查 SD 卡(命令包括: CMD55、 CMD41、 CMD58 和 CMD1 等);
- 取消片选,发多 8 个 CLK(提供 SD 卡额外的时钟,完成某些操作),结束初始化;
3、读写SD卡
SD卡读取数据(CMD17):
- 发送 CMD17;
- 接收卡响应 R1;
- 接收数据起始令牌 0XFE;
- 接收数据;
- 接收 2 个字节的 CRC,如果不使用 CRC,这两个字节在读取后可以丢掉。
- 禁止片选之后,发多 8 个 CLK;
SD卡写数据(CMD24):
- 发送 CMD24;
- 接收卡响应 R1;
- 发送写数据起始令牌 0XFE;
- 发送数据;
- 发送 2 字节的伪 CRC;
- 禁止片选之后,发多 8 个 CLK;
三、SD卡驱动源码
源文件
#include "mmc_sd.h"
uint8_t SD_Type = 0;//SD卡的类型
uint32_t Capacity = 0; //可用扇区数
移植修改区///
//SPI初始化
void hal_spi_init(void)
{
}
/*****************************************************************************
** 描 述:写入一个字节
** 入 参:Dat:待写入的数据
** 返回值:读出的数据
******************************************************************************/
uint8_t SD_SPI_ReadWriteByte(uint8_t Dat)
{
/**
根据不同平台进行实现
****/
}
//取消选择,释放SPI总线
void SD_DisSelect(void)
{
SD_CS_HIGH_HRS();
SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
}
//选择sd卡,并且等待卡准备OK
//返回值:0,成功;1,失败;
uint8_t SD_Select(void)
{
SD_CS_LOW_HRS();
if(SD_WaitReady()==0)return 0;//等待成功
SD_DisSelect();
return 1;//等待失败
}
///
//等待卡准备好
//返回值:0,准备好了;其他,错误代码
uint8_t SD_WaitReady(void)
{
uint32_t t=0;
do
{
if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK
t++;
}
while(t<0XFFFFFF); //等待
return 1;
}
//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
// 其他,得到回应值失败
uint8_t SD_GetResponse(uint8_t Response)
{
uint16_t Count=0xFFF;//等待次数
while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应
if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
else return MSD_RESPONSE_NO_ERROR;//正确回应
}
//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;
uint8_t SD_RecvData(uint8_t*buf,uint16_t len)
{
if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
while(len--)//开始接收数据
{
*buf=SD_SPI_ReadWriteByte(0xFF);
buf++;
}
//下面是2个伪CRC(dummy CRC)
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
return 0;//读取成功
}
//向sd卡写入一个数据包的内容 512字节
//buf:数据缓存区
//cmd:指令
//返回值:0,成功;其他,失败;
uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd)
{
uint16_t t;
if(SD_WaitReady())return 1;//等待准备失效
SD_SPI_ReadWriteByte(cmd);
if(cmd!=0XFD)//不是结束指令
{
for(t=0; t<512; t++)SD_SPI_ReadWriteByte(buf[t]); //提高速度,减少函数传参时间
SD_SPI_ReadWriteByte(0xFF);//忽略crc
SD_SPI_ReadWriteByte(0xFF);
t=SD_SPI_ReadWriteByte(0xFF);//接收响应
if((t&0x1F)!=0x05)return 2;//响应错误
}
return 0;//写入成功
}
//向SD卡发送一个命令
//输入: uint8_t cmd 命令
// uint32_t arg 命令参数
// uint8_t crc crc校验值
//返回值:SD卡返回的响应
uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
{
uint8_t r1;
uint8_t Retry=0;
SD_DisSelect();//取消上次片选