Files
SM-1000M/RTX5_20220316/Driver/spi/SPI_SD_driver.c
2026-04-23 10:50:18 +08:00

423 lines
12 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 "SPI_SD_driver.h"
#include "spi.h"
/*
*********************************************************************************
变量
*********************************************************************************
*/
u8 SD_Type=0;
/*
*********************************************************************************************************
* 函 数 名: SD_SPI_ReadWriteByte()
* 功能说明: SD卡读写数据
* 输 入 data:要写入的数据
* 输 出 :读到的数据
*********************************************************************************************************
*/
u8 SD_SPI_ReadWriteByte(u8 data)
{
return SPI2_ReadWriteByte(data);
}
//SD卡初始化的时候,需要低速
void SD_SPI_SpeedLow(void)
{
SPI2_SetSpeed(SPI_BaudRatePrescaler_256);//设置到低速模式
}
//SD卡正常工作的时候,可以高速了
void SD_SPI_SpeedHigh(void)
{
SPI2_SetSpeed(SPI_BaudRatePrescaler_2);//设置到高速模式
}
/**********************************************
*函数名称void SPI_Configuration(void)
*入口参数:无
*出口参数:无
*返回值 :无
*功能说明SPI模块初始化【包括相关IO口的初始化】
**********************************************/
void SD_SPI_Init(void)
{
SPI2_Init();
//SPI2_SetSpeed(7);
SD_SPI_SpeedHigh();
}
/*
*********************************************************************************************************
* 函 数 名: SD_DisSelect()
* 功能说明: 取消片选
* 输 入 :无
* 输 出 :无
*********************************************************************************************************
*/
void SD_DisSelect(void)
{
SD_CS_DISABLE() ;
SD_SPI_ReadWriteByte(0xff);//提供额外的8个时钟
}
/*
*********************************************************************************************************
* 函 数 名: SD_Select()
* 功能说明: 选择sd卡,并且等待卡准备OK
* 输 入 :无
* 输 出 0,准备好了;其他,失败;
*********************************************************************************************************
*/
u8 SD_Select(void)
{
SD_CS_ENABLE();
if(SD_WaitReady()==0)return 0;//等待成功
SD_DisSelect();
return 1;//等待失败
}
/*
*********************************************************************************************************
* 函 数 名: SD_WaitReady()
* 功能说明: 等待卡准备好
* 输 入 Response:要得到的回应值
* 输 出 0,准备好了;其他,失败;
*********************************************************************************************************
*/
u8 SD_WaitReady(void)
{
u32 t=0;
do
{
if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;//OK
t++;
}while(t<0XFFFFFF);//等待
return 1;
}
/*
*********************************************************************************************************
* 函 数 名: SD_GetResponse()
* 功能说明: 等待SD卡回应
* 输 入 Response:要得到的回应值
* 输 出 0,成功;其他,失败;
*********************************************************************************************************
*/
u8 SD_GetResponse(u8 Response)
{
u16 Count=0xFFFF;//等待次数
while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应
if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
else return MSD_RESPONSE_NO_ERROR;//正确回应
}
/*
*********************************************************************************************************
* 函 数 名: SD_RecvData()
* 功能说明: 从sd卡读取一个数据包的内容
* 输 入 buf:数据缓存区 len:要读取的数据长度.
* 输 出 0,成功;其他,失败;
*********************************************************************************************************
*/
u8 SD_RecvData(u8*buf,u16 len)
{
if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
while(len--)//开始接收数据
{
*buf=SPI2_ReadWriteByte(0xFF);
buf++;
}
//下面是2个伪CRCdummy CRC
SD_SPI_ReadWriteByte(0xFF);
SD_SPI_ReadWriteByte(0xFF);
return 0;//读取成功
}
/*
*********************************************************************************************************
* 函 数 名: SD_SendCmd()
* 功能说明: 向sd卡写入一个数据包的内容 512字节 cmd:指令
* 输 入 buf:数据缓存区
* 输 出 0,成功;其他,失败;
*********************************************************************************************************
*/
u8 SD_SendBlock(u8*buf,u8 cmd)
{
u16 t;
if(SD_WaitReady())return 1;//等待准备失效
SD_SPI_ReadWriteByte(cmd);
if(cmd!=0XFD)//不是结束指令
{
for(t=0;t<512;t++)SPI2_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_SendCmd()
* 功能说明: 向SD卡发送一个命令
* 输 入 u8 cmd 命令 u32 arg 命令参数 u8 crc crc校验值
* 输 出 SD卡返回的响应
*********************************************************************************************************
*/
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
{
u8 r1;
u8 Retry=0;
SD_DisSelect();//取消上次片选
if(SD_Select())return 0XFF;//片选失效
//发送
SD_SPI_ReadWriteByte(cmd | 0x40);//分别写入命令
SD_SPI_ReadWriteByte(arg >> 24);
SD_SPI_ReadWriteByte(arg >> 16);
SD_SPI_ReadWriteByte(arg >> 8);
SD_SPI_ReadWriteByte(arg);
SD_SPI_ReadWriteByte(crc);
if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff);//Skip a stuff byte when stop reading
//等待响应,或超时退出
Retry=0X1F;
do
{
r1=SD_SPI_ReadWriteByte(0xFF);
}while((r1&0X80) && Retry--);
//返回状态值
return r1;
}
/*
*********************************************************************************************************
* 函 数 名: SD_GetCID()
* 功能说明: 获取SD卡的CID信息包括制造商信息
* 输 入 u8 *cid_data(存放CID的内存至少16Byte
* 输 出 0NO_ERR 1错误
*********************************************************************************************************
*/
u8 SD_GetCID(u8 *cid_data)
{
u8 r1;
//发CMD10命令读CID
r1=SD_SendCmd(CMD10,0,0x01);
if(r1==0x00)
{
r1=SD_RecvData(cid_data,16);//接收16个字节的数据
}
SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}
/*
*********************************************************************************************************
* 函 数 名: SD_GetCSD()
* 功能说明: 获取SD卡的CSD信息包括容量和速度信息
* 输 入 u8 *cid_data(存放CID的内存至少16Byte
* 输 出 0NO_ERR 1错误
*********************************************************************************************************
*/
u8 SD_GetCSD(u8 *csd_data)
{
u8 r1;
r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令读CSD
if(r1==0)
{
r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
}
SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}
/*
*********************************************************************************************************
* 函 数 名: SD_GetSectorCount()
* 功能说明: 获取SD卡扇区数量
* 输 入 :无
* 输 出 其他Capacity 卡的容量 0容量出错
*********************************************************************************************************
*/
u32 SD_GetSectorCount(void)
{
u8 csd[16];
u32 Capacity;
u8 n;
u16 csize;
//取CSD信息如果期间出错返回0
if(SD_GetCSD(csd)!=0) return 0;
//如果为SDHC卡按照下面方式计算
if((csd[0]&0xC0)==0x40) //V2.00的卡
{
csize = csd[9] + ((u16)csd[8] << 8) + 1;
Capacity = (u32)csize << 10;//得到扇区数
}else//V1.XX的卡
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
Capacity= (u32)csize << (n - 9);//得到扇区数
}
return Capacity;
}
/*
*********************************************************************************************************
* 函 数 名: SD_Initialize()
* 功能说明: SD卡初始化
* 输 入 :无
* 输 出 :卡的类型.
*********************************************************************************************************
*/
u8 SD_Initialize(void)
{
u8 r1; // 存放SD卡的返回值
u16 retry; // 用来进行超时计数
u8 buf[4];
u16 i;
SD_SPI_Init(); //初始化IO
SD_SPI_SpeedLow(); //设置到低速模式
for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
retry=20;
do
{
r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
}while((r1!=0X01) && retry--);
SD_Type=0;//默认无卡
if(r1==0X01)
{
if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF); //Get trailing return value of R7 resp
if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
{
retry=0XFFFE;
do
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
}while(r1&&retry--);
if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
{
for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC; //检查CCS
else SD_Type=SD_TYPE_V2;
}
}
}else//SD V1.x/ MMC V3
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0,0X01); //发送CMD41
if(r1<=1)
{
SD_Type=SD_TYPE_V1;
retry=0XFFFE;
do //等待退出IDLE模式
{
SD_SendCmd(CMD55,0,0X01); //发送CMD55
r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
}while(r1&&retry--);
}else
{
SD_Type=SD_TYPE_MMC;//MMC V3
retry=0XFFFE;
do //等待退出IDLE模式
{
r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
}while(r1&&retry--);
}
if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
}
}
SD_DisSelect();//取消片选
SD_SPI_SpeedHigh();//高速
if(SD_Type)
return 0;
else if(r1)
return r1;
return 0xaa;//其他错误
}
/*
*********************************************************************************************************
* 函 数 名: SD_ReadDisk()
* 功能说明: 读SD卡扇区数据
* 输 入 :数据缓存区 buf 起始扇区sector 扇区数量 cnt
* 输 出 r1 0,ok;其他,失败.
*********************************************************************************************************
*/
u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;//转换为字节地址
if(cnt==1)
{
r1=SD_SendCmd(CMD17,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_RecvData(buf,512);//接收512个字节
}
}else
{
r1=SD_SendCmd(CMD18,sector,0X01);//连续读命令
do
{
r1=SD_RecvData(buf,512);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
SD_SendCmd(CMD12,0,0X01); //发送停止命令
}
SD_DisSelect();//取消片选
return r1;//
}
/*
*********************************************************************************************************
* 函 数 名: SD_WriteDisk()
* 功能说明: 向SD卡扇区写数据
* 输 入 :数据 buf 起始扇区sector 扇区数量 cnt
* 输 出 r1 0,ok;其他,失败.
*********************************************************************************************************
*/
u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
{
u8 r1;
if(SD_Type!=SD_TYPE_V2HC)sector *= 512;//转换为字节地址
if(cnt==1)
{
r1=SD_SendCmd(CMD24,sector,0X01);//读命令
if(r1==0)//指令发送成功
{
r1=SD_SendBlock(buf,0xFE);//写512个字节
}
}else
{
if(SD_Type!=SD_TYPE_MMC)
{
SD_SendCmd(CMD55,0,0X01);
SD_SendCmd(CMD23,cnt,0X01);//发送指令
}
r1=SD_SendCmd(CMD25,sector,0X01);//连续读命令
if(r1==0)
{
do
{
r1=SD_SendBlock(buf,0xFC);//接收512个字节
buf+=512;
}while(--cnt && r1==0);
r1=SD_SendBlock(0,0xFD);//接收512个字节
}
}
SD_DisSelect();//取消片选
return r1;//
}
/***************************** END OF FILE *********************************************************************/