358 lines
9.8 KiB
C
358 lines
9.8 KiB
C
|
|
#include "DrvSdSpi.h"
|
|||
|
|
#include "BSPSpi.h"
|
|||
|
|
|
|||
|
|
#include <string.h>
|
|||
|
|
|
|||
|
|
static uint8_t sd_type = 0; // SD卡的类型
|
|||
|
|
static unsigned char gSDCsd[16] = {0};
|
|||
|
|
|
|||
|
|
// SD片选
|
|||
|
|
static uint8_t Drv_SdSelect(void);
|
|||
|
|
static void Drv_SdDisselect(void);
|
|||
|
|
void Drv_SdSpiCs(uint8_t value);
|
|||
|
|
uint8_t Drv_SdSpiRWByte(uint8_t data);
|
|||
|
|
void Drv_SdSpiSetSpeed(uint8_t mode);
|
|||
|
|
|
|||
|
|
// 数据指令收发函数
|
|||
|
|
static uint8_t Drv_SdSendCmd(uint8_t cmd, uint32_t arg, uint8_t crc);
|
|||
|
|
static unsigned char Drv_SDGetResponse(unsigned char response);
|
|||
|
|
static unsigned char Drv_SDRecvData(unsigned char *buf, unsigned short len);
|
|||
|
|
static unsigned char Drv_SDSendBlock(unsigned char *buf, unsigned char cmd);
|
|||
|
|
static unsigned char Drv_SDGetCsd(unsigned char *csd_data);
|
|||
|
|
|
|||
|
|
// sd等待卡片准备好
|
|||
|
|
uint8_t Drv_SdWaitReady(void);
|
|||
|
|
|
|||
|
|
// SD卡初始化
|
|||
|
|
uint8_t Drv_SdInit(void);
|
|||
|
|
|
|||
|
|
// 读取和写入SD卡
|
|||
|
|
unsigned char Drv_SdReadDisk(unsigned char *buf, unsigned int sector, unsigned char cnt);
|
|||
|
|
unsigned char Drv_SdWriteDisk(unsigned char *buf, unsigned int sector, unsigned char cnt);
|
|||
|
|
|
|||
|
|
// 获取SD卡总扇区数
|
|||
|
|
unsigned int Drv_SdGetSectorCount(void);
|
|||
|
|
|
|||
|
|
// 向SD卡发送指令
|
|||
|
|
static uint8_t Drv_SdSendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
|
|||
|
|
{
|
|||
|
|
uint8_t response;
|
|||
|
|
uint8_t retry_limit = 0x1f;
|
|||
|
|
|
|||
|
|
Drv_SdDisselect();
|
|||
|
|
|
|||
|
|
if (Drv_SdSelect() != 0) {
|
|||
|
|
return 0xff;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Drv_SdSpiRWByte(cmd | 0x40);
|
|||
|
|
for (int shift = 24; shift >= 0; shift -= 8) {
|
|||
|
|
Drv_SdSpiRWByte((uint8_t)((arg >> shift) & 0xff));
|
|||
|
|
}
|
|||
|
|
Drv_SdSpiRWByte(crc);
|
|||
|
|
|
|||
|
|
if (cmd == CMD12) {
|
|||
|
|
Drv_SdSpiRWByte(0xff);
|
|||
|
|
}
|
|||
|
|
do {
|
|||
|
|
response = Drv_SdSpiRWByte(0xff);
|
|||
|
|
} while ((response & 0x80) && retry_limit--);
|
|||
|
|
|
|||
|
|
return response;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// sd等待卡片准备好
|
|||
|
|
uint8_t Drv_SdWaitReady(void)
|
|||
|
|
{
|
|||
|
|
uint8_t rec;
|
|||
|
|
uint32_t retry_time = 0;
|
|||
|
|
do {
|
|||
|
|
rec = Drv_SdSpiRWByte(0xff);
|
|||
|
|
if (0xff == rec) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
retry_time++;
|
|||
|
|
if (retry_time % 0xffffff == 0) {
|
|||
|
|
/* 长时间没有成功,进行重新初始化 */
|
|||
|
|
Bsp_SpiInit(BSP_SPI3);
|
|||
|
|
Drv_SdSpiCs(1);
|
|||
|
|
}
|
|||
|
|
} while (retry_time < 0xfffffff);
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SD片选
|
|||
|
|
static uint8_t Drv_SdSelect(void)
|
|||
|
|
{
|
|||
|
|
Drv_SdSpiCs(0);
|
|||
|
|
if (Drv_SdWaitReady() == 0) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
Drv_SdDisselect();
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SD取消片选
|
|||
|
|
static void Drv_SdDisselect(void)
|
|||
|
|
{
|
|||
|
|
Drv_SdSpiCs(1);
|
|||
|
|
Drv_SdSpiRWByte(0xff);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Drv_SdSpiCs(unsigned char value)
|
|||
|
|
{
|
|||
|
|
Bsp_SpiCS(BSP_SPI3, value);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置SD通信速度
|
|||
|
|
void Drv_SdSpiSetSpeed(uint8_t mode)
|
|||
|
|
{
|
|||
|
|
uint32_t speed;
|
|||
|
|
if (mode == USR_DRV_SD_LOW_SPEED_MODE) {
|
|||
|
|
speed = USR_DRV_SD_LOW_SPEED;
|
|||
|
|
} else if (mode == USR_DRV_SD_HIGH_SPEED_MODE) {
|
|||
|
|
speed = USR_DRV_SD_HIGH_SPEED;
|
|||
|
|
}
|
|||
|
|
Bsp_SpiSetSpeed(BSP_SPI3, speed);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置SD读写函数
|
|||
|
|
uint8_t Drv_SdSpiRWByte(uint8_t data)
|
|||
|
|
{
|
|||
|
|
return Bsp_RWByte(BSP_SPI3, data);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 从SD卡读取一个数据包的内容
|
|||
|
|
static unsigned char Drv_SDRecvData(unsigned char *buf, unsigned short len)
|
|||
|
|
{
|
|||
|
|
if (Drv_SDGetResponse(0xfe)) {
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
while (len--) {
|
|||
|
|
*buf = Drv_SdSpiRWByte(0xff);
|
|||
|
|
buf++;
|
|||
|
|
}
|
|||
|
|
Drv_SdSpiRWByte(0xff);
|
|||
|
|
Drv_SdSpiRWByte(0xff);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 向SD卡写入一个数据包的内容512字节
|
|||
|
|
static unsigned char Drv_SDSendBlock(unsigned char *buf, unsigned char cmd)
|
|||
|
|
{
|
|||
|
|
unsigned char rt;
|
|||
|
|
unsigned short i;
|
|||
|
|
rt = Drv_SdWaitReady();
|
|||
|
|
if (0 != rt) {
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
Drv_SdSpiRWByte(cmd);
|
|||
|
|
if (cmd != 0xfd) {
|
|||
|
|
for (i = 0; i < 512; i++) {
|
|||
|
|
Drv_SdSpiRWByte(buf[i]);
|
|||
|
|
}
|
|||
|
|
Drv_SdSpiRWByte(0xff);
|
|||
|
|
Drv_SdSpiRWByte(0xff);
|
|||
|
|
rt = Drv_SdSpiRWByte(0xff);
|
|||
|
|
if ((rt & 0x1F) != 0x05) {
|
|||
|
|
return 2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 等待SD回应
|
|||
|
|
static unsigned char Drv_SDGetResponse(unsigned char response)
|
|||
|
|
{
|
|||
|
|
unsigned short count = 0xffff;
|
|||
|
|
while ((Drv_SdSpiRWByte(0xff) != response) && count) {
|
|||
|
|
count--;
|
|||
|
|
}
|
|||
|
|
if (count == 0) {
|
|||
|
|
return MSD_RESPONSE_FAILURE;
|
|||
|
|
} else {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取SD卡的CSD信息包括容量和速度信息
|
|||
|
|
static unsigned char Drv_SDGetCsd(unsigned char *csd_data)
|
|||
|
|
{
|
|||
|
|
unsigned char rt;
|
|||
|
|
rt = Drv_SdSendCmd(CMD9, 0, 0x01);
|
|||
|
|
if (rt == 0x00) {
|
|||
|
|
rt = Drv_SDRecvData(csd_data, 16);
|
|||
|
|
}
|
|||
|
|
Drv_SdDisselect();
|
|||
|
|
if (rt != 0x00) {
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取SD卡总扇区数
|
|||
|
|
unsigned int Drv_SdGetSectorCount(void)
|
|||
|
|
{
|
|||
|
|
unsigned int capacity; // 记录扇区数量
|
|||
|
|
unsigned char n;
|
|||
|
|
unsigned short csize;
|
|||
|
|
memset(gSDCsd, 0, sizeof(gSDCsd));
|
|||
|
|
/* 获取CSD信息 */
|
|||
|
|
if (Drv_SDGetCsd(gSDCsd) != 0x00) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
if ((gSDCsd[0] & 0xc0) == 0x40) {
|
|||
|
|
csize = gSDCsd[9] + ((unsigned short)gSDCsd[8] << 8) + 1;
|
|||
|
|
capacity = (unsigned int)csize << 10;
|
|||
|
|
} else {
|
|||
|
|
n = (gSDCsd[5] & 15) + ((gSDCsd[10] & 128) >> 7) + ((gSDCsd[9] & 3) << 1) + 2;
|
|||
|
|
csize = (gSDCsd[8] >> 6) + ((unsigned short)gSDCsd[7] << 2) + ((unsigned short)(gSDCsd[6] & 3) << 10) + 1;
|
|||
|
|
capacity = (unsigned int)csize << (n - 9);
|
|||
|
|
}
|
|||
|
|
return capacity;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// SD卡初始化
|
|||
|
|
uint8_t Drv_SdInit(void)
|
|||
|
|
{
|
|||
|
|
unsigned char RxData; // 返回值
|
|||
|
|
unsigned short RetryTime; // 用来进行超时计数
|
|||
|
|
unsigned char buf[4];
|
|||
|
|
|
|||
|
|
unsigned short i;
|
|||
|
|
|
|||
|
|
Bsp_SpiInit(BSP_SPI3);
|
|||
|
|
Drv_SdSpiCs(0);
|
|||
|
|
Drv_SdSpiSetSpeed(USR_DRV_SD_LOW_SPEED_MODE); // 初始化的时候要是低速模式
|
|||
|
|
for(i = 0; i < 100; i++) {
|
|||
|
|
RxData = Drv_SdSpiRWByte(0xff); // 发送最少74个脉冲,保守起见多发送一点
|
|||
|
|
}
|
|||
|
|
/* 格式化命令 */
|
|||
|
|
Drv_SdSpiRWByte(CMD0 | 0x40);
|
|||
|
|
Drv_SdSpiRWByte((unsigned char)((0 >> 24) & 0xff));
|
|||
|
|
Drv_SdSpiRWByte((unsigned char)((0 >> 16) & 0xff));
|
|||
|
|
Drv_SdSpiRWByte((unsigned char)((0 >> 8) & 0xff));
|
|||
|
|
Drv_SdSpiRWByte((unsigned char)(0 & 0xff));
|
|||
|
|
Drv_SdSpiRWByte(0x95);
|
|||
|
|
|
|||
|
|
RetryTime = 20;
|
|||
|
|
do {
|
|||
|
|
RxData = Drv_SdSendCmd(CMD0, 0, 0x95);//
|
|||
|
|
} while((RxData != 0x01) && RetryTime--);
|
|||
|
|
|
|||
|
|
sd_type = 0; // 设置默认没有卡
|
|||
|
|
if(RxData == 0x01) {
|
|||
|
|
if(Drv_SdSendCmd(CMD8, 0x1AA, 0x87) == 1) // SD 协议版本V2.0
|
|||
|
|
{
|
|||
|
|
for(i = 0; i < 4; i++) {
|
|||
|
|
buf[i] = Drv_SdSpiRWByte(0xff);
|
|||
|
|
}
|
|||
|
|
if(buf[2] == 0x01 && buf[3] == 0xaa) // 判断卡是否支持2.7V~3.6V
|
|||
|
|
{
|
|||
|
|
RetryTime = 0xfffe;
|
|||
|
|
do {
|
|||
|
|
Drv_SdSendCmd(CMD55, 0, 0x01);
|
|||
|
|
RxData = Drv_SdSendCmd(ACMD41, 0x40000000, 0x01);
|
|||
|
|
} while(RxData && RetryTime--);
|
|||
|
|
if(RetryTime && (Drv_SdSendCmd(CMD58, 0, 0x01)) == 0) // 鉴别SD2.0卡版本
|
|||
|
|
{
|
|||
|
|
for(i = 0; i < 4; i++) {
|
|||
|
|
buf[i] = Drv_SdSpiRWByte(0xff); // 得到OCR值
|
|||
|
|
}
|
|||
|
|
// 检查CSS
|
|||
|
|
if (buf[0] & 0x40) {
|
|||
|
|
sd_type = SD_TYPE_V2HC;
|
|||
|
|
}
|
|||
|
|
else {
|
|||
|
|
sd_type = SD_TYPE_V2;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else { // SD V1.x/ MMC V3
|
|||
|
|
Drv_SdSendCmd(CMD55, 0, 0X01);
|
|||
|
|
RxData = Drv_SdSendCmd(ACMD41, 0, 0X01);
|
|||
|
|
if(RxData <= 1) {
|
|||
|
|
sd_type = SD_TYPE_V1;
|
|||
|
|
RetryTime = 0xfffe;
|
|||
|
|
do { // 等待退出IDLE模式
|
|||
|
|
Drv_SdSendCmd(CMD55, 0, 0X01);
|
|||
|
|
RxData = Drv_SdSendCmd(ACMD41, 0, 0X01);
|
|||
|
|
} while(RxData && RetryTime--);
|
|||
|
|
} else { // MMC卡不支持CMD55余CMD41识别
|
|||
|
|
sd_type = SD_TYPE_MMC; // MMC V3
|
|||
|
|
RetryTime = 0xfffe;
|
|||
|
|
do { // 等待退出IDLE模式
|
|||
|
|
RxData = Drv_SdSendCmd(CMD1, 0, 0X01);
|
|||
|
|
} while(RxData && RetryTime--);
|
|||
|
|
}
|
|||
|
|
if((RetryTime == 0) || (Drv_SdSendCmd(CMD16, 512, 0X01) != 0)) {
|
|||
|
|
sd_type = SD_TYPE_ERR; // 错误的卡,未能识别
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Drv_SdDisselect();
|
|||
|
|
Drv_SdSpiSetSpeed(USR_DRV_SD_HIGH_SPEED_MODE);
|
|||
|
|
if(sd_type != 0) {
|
|||
|
|
return 0;
|
|||
|
|
} else if(RxData != 0) {
|
|||
|
|
return RxData;
|
|||
|
|
}
|
|||
|
|
return 0xaa; // 其他错误
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 读取SD卡
|
|||
|
|
unsigned char Drv_SdReadDisk(unsigned char *buf, unsigned int sector, unsigned char cnt)
|
|||
|
|
{
|
|||
|
|
unsigned char rt;
|
|||
|
|
if(sd_type != SD_TYPE_V2HC) {
|
|||
|
|
sector <<= 9; // 转换为字节地址
|
|||
|
|
}
|
|||
|
|
if(cnt == 1) {
|
|||
|
|
rt = Drv_SdSendCmd(CMD17, sector, 0x01); // 读命令
|
|||
|
|
if (rt == 0) // 指令发送成功
|
|||
|
|
{
|
|||
|
|
rt = Drv_SDRecvData(buf, 512); // 接收512个字节
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
rt = Drv_SdSendCmd(CMD18, sector, 0X01); // 连续读命令
|
|||
|
|
do
|
|||
|
|
{
|
|||
|
|
rt = Drv_SDRecvData(buf, 512); // 接收512个字节
|
|||
|
|
buf += 512;
|
|||
|
|
} while(--cnt && rt == 0);
|
|||
|
|
Drv_SdSendCmd(CMD12, 0, 0X01); // 发送停止命令
|
|||
|
|
}
|
|||
|
|
Drv_SdDisselect(); // 取消片选
|
|||
|
|
return rt;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 写入SD卡
|
|||
|
|
unsigned char Drv_SdWriteDisk(unsigned char *buf, unsigned int sector, unsigned char cnt)
|
|||
|
|
{
|
|||
|
|
unsigned char rt;
|
|||
|
|
if(sd_type != SD_TYPE_V2HC) {
|
|||
|
|
sector *= 512; // 转换为字节地址
|
|||
|
|
}
|
|||
|
|
if (cnt == 1) {
|
|||
|
|
rt = Drv_SdSendCmd(CMD24, sector, 0x01);
|
|||
|
|
if(rt == 0) {
|
|||
|
|
rt = Drv_SDSendBlock(buf, 0xfe);
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
if(sd_type != SD_TYPE_MMC) {
|
|||
|
|
Drv_SdSendCmd(CMD55, 0, 0X01);
|
|||
|
|
Drv_SdSendCmd(CMD23, cnt, 0X01);
|
|||
|
|
}
|
|||
|
|
rt = Drv_SdSendCmd(CMD25, sector, 0X01); // 连续读取
|
|||
|
|
if(rt == 0) {
|
|||
|
|
do {
|
|||
|
|
rt = Drv_SDSendBlock(buf, 0xfc); // 接收512个字节
|
|||
|
|
buf += 512;
|
|||
|
|
} while(--cnt && rt == 0);
|
|||
|
|
rt = Drv_SDSendBlock(0, 0xfd); // 接收512个字节
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
Drv_SdDisselect();
|
|||
|
|
return rt;
|
|||
|
|
}
|