20240909-DXSPX-emb/Src/Usr/Driver/DrvSdSpi.c

358 lines
9.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}