📄 sd.c
字号:
#include "..\inc\sd.h"
#include "..\inc\44b.h"
SD_INFO g_SDInfo;
volatile char endSioTR=0;
//启用中断传输模式
void __irq Sio_Int(void) //SPI中断函数
{
rI_ISPC = BIT_SIO; //清零中断标志位
endSioTR = 1;
}
/*************************************************************************
* 名称: void SPI_MasterTransmit(INT8U u8Data)
* 功能: SPI主机模式传送数据
* 参数: cData 要传输的字节数据
* 返回: SPI接收值
*************************************************************************/
INT8U SPI_MasterTransmit(INT8U u8Data)
{
rSIODAT = u8Data;
rSIOCON |= (1 << 3); //启动数据传输
while (!endSioTR); //等待传输结束
endSioTR = 0;
return rSIODAT; //返回SPI接收的数据
}
/*************************************************************************
*名称: SD_SendCMD
*功能: 向SD卡发送命令
*参数: u8Cmd 命令 u32Arg 参数
*返回: SD卡状态值
*************************************************************************/
INT8U SD_SendCMD(INT8U u8Cmd, INT32U u32Arg)
{
INT8U r1;
INT16U Temp = 0;
SPI_CS_ASSERT;
SPI_MasterTransmit(u8Cmd | 0x40); //分别写入命令
SPI_MasterTransmit(u32Arg >> 24);
SPI_MasterTransmit(u32Arg >> 16);
SPI_MasterTransmit(u32Arg >> 8);
SPI_MasterTransmit(u32Arg);
SPI_MasterTransmit(0x95);
do{
r1 = SPI_MasterTransmit(0xFF);
if(Temp++ > 100)
{
break; //超时退出
}
}while(r1 == 0xFF);
SPI_CS_DEASSERT;
SPI_MasterTransmit(0xFF); //发送8个填充时钟
return r1; //返回状态值
}
/*************************************************************************
*名称: SD_GetOCR
*功能: 获取OCR寄存器数据
*参数: *pu8Buff 数据缓存区指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetOCR(INT8U *pu8Buff)
{
INT8U i;
INT8U r1=0;
r1 = SD_SendCMD(CMD_SD_SEND_OP_COND, 0);
if(r1 != 0) //响应错误
{
return 1;
}
SPI_CS_ASSERT;
for (i = 0; i < 4; i++)
{
pu8Buff[i] = SPI_MasterTransmit(0xFF);
}
SPI_CS_DEASSERT;
return 0;
}
/*************************************************************************
*名称: SD_GetCID
*功能: 获取CID寄存器数据
*参数: *pu8Buff 数据缓存区指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetCID(INT8U *pu8Buff)
{
INT8U i;
INT8U Temp = 0;
INT8U r1=0;
r1 = SD_SendCMD(CMD_SEND_CID,0);//发送读CSD寄存器命令
if(r1 != 0) //响应错误
{
return 1;
}
SPI_CS_ASSERT;
do{
r1 = SPI_MasterTransmit(0xFF);
if(Temp++ > 100)
{
return 1;
}
}while(r1 != 0xFE); //等待数据起始令牌
for (i = 0; i < 16; i++)
{
pu8Buff[i] = SPI_MasterTransmit(0xFF);
}
SPI_MasterTransmit(0xFF); //发送8个填充时钟
SPI_CS_DEASSERT;
return 0;
}
/*************************************************************************
*名称: SD_GetCSD
*功能: 获取CSD寄存器数据
*参数: *pu8Buff 数据缓存区指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetCSD(INT8U *pu8Buff)
{
INT8U i;
INT8U Temp = 0;
INT8U r1=0;
r1 = SD_SendCMD(CMD_SEND_CSD ,0);
r1 = SD_SendCMD(CMD_SEND_CSD ,0);//发送读CSD寄存器命令
if(r1 != 0) //响应错误
{
return 1;
}
SPI_CS_ASSERT;
do{
r1 = SPI_MasterTransmit(0xFF);
if(Temp++ > 100)
{
return 1;
}
}while(r1 != 0xFE); //等待数据起始令牌
for (i = 0; i < 16; i++)
{
pu8Buff[i] = SPI_MasterTransmit(0xFF);
}
SPI_MasterTransmit(0xFF); //发送8个填充时钟
SPI_CS_DEASSERT;
return 0;
}
/*************************************************************************
*名称: SD_GetCardInfo
*功能: 获取卡片信息
*参数:
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_GetCardInfo(SD_INFO *pg_SDInfo)
{
INT8U Temp[16];
if(SD_GetCID(Temp) == 0) //获取CID信息
{
INT8U i;
pg_SDInfo->mid = Temp[0];
pg_SDInfo->oid[0] = Temp[1];
pg_SDInfo->oid[1] = Temp[2];
for(i = 0; i < 5; i++)
{
pg_SDInfo->pnm[i] = Temp[i + 3];
}
pg_SDInfo->prv = Temp[1];
pg_SDInfo->psn = ((INT32U)Temp[9] << 24) + ((INT32U)Temp[10] << 16)
+ ((INT32U)Temp[11] << 8) + (INT32U)Temp[12];
//计算32位串号
pg_SDInfo->mdt = Temp[14];
}
else
{
return 3;
}
if(SD_GetCSD(Temp) == 0) //获取CSD信息
{
INT32U j;
pg_SDInfo->bl = 1 << (Temp[5] & 0x0F); //计算块长度
pg_SDInfo->bn = ((Temp[6] & 0x03) << 10) +
(Temp[7] << 2) + ((Temp[8] & 0xC0) >> 6);
//计算C_SIZE + 1
j = ((Temp[9] & 0x03) << 1) + ((Temp[10] & 0x80) >> 7);
//计算C_SIZE_MULT
pg_SDInfo->bn = (pg_SDInfo->bn + 1) * (1 << (j + 2));
//计算BLOCKNR = (C_SIZE + 1) * 2 ^ (C_SIZE_MULT + 2)
pg_SDInfo->cap = pg_SDInfo->bl * pg_SDInfo->bn; //计算容量大小
pg_SDInfo->cap >>= 20;
}
else
{
return 4;
}
return 0;
}
/*************************************************************************
*名称: SD_Init
*功能: SD卡初始化
*参数: 无
*返回: 0成功 非零是失败
*************************************************************************/
INT8U SD_Init(PSD_INFO psdi)
{
INT8U i;
INT8U Temp = 0;
INT8U r1=0;
pISR_SIO = (unsigned)Sio_Int; //中断入口地址
rINTMSK = ~(BIT_GLOBAL | BIT_SIO);
//-- SPI(SIO) port initialize
rPCONF = (rPCONF & 0x3ff) + (3 << 19) + (3 << 16) + (3 << 13) + (3 << 10);
rPUPF |= 0x160; //Rx must pullup
//-- SPI(SIO) controller & card initialize
rSIOCON = (0x0 << 7) | (0x0 << 6) | (0x1 << 5) | (0x0 << 4) | (0x0 << 3) | (0x0 << 2) | 0x1;
//inter clk, MSB 1st, Tx/Rx, falling, no action, auto run, SIO int
rSBRDR = 99; //MCLK=60MHz,SIOCK=300KHz(in initialize time)
rIVTCNT = 0;
for (i = 0;i < 20;i++) //至少发送74个脉冲
{
SPI_MasterTransmit(0xFF);
}
do //复位存储卡
{
r1 = SD_SendCMD(CMD_GO_IDLE_STATE , 0); //发IDLE命令
if(Temp++ > 20)
{
return 1; //超时退出
}
} while(r1 != 0x01);
Temp = 0;
do //激活存储卡
{
r1 = SD_SendCMD(CMD_SEND_OP_COND , 0); //发CMD1命令激活卡
if(Temp++ > 20)
{
return 1; //超时退出
}
} while(r1 != 0x01);
do //判断卡片类型
{
r1 = SD_SendCMD(CMD_APP, 0); //发CMD55命令
if(r1 == 0x01) //响应正确
{
r1 = SD_SendCMD(CMD_SD_SEND_OP_COND, 0);//发ACMD41命令
if(r1 == 0x00) //SD卡
{
psdi->ct = SD_TYPE_SD ;
}
}
else //响应错误
{
r1 = SD_SendCMD(CMD_SEND_OP_COND , 0); //发CMD1命令激活卡
if(r1 == 0x00) //MMC卡
{
psdi->ct = SD_TYPE_MMC;
}
}
// Uart_Printf("卡的类型\n",&psdi->ct);
/* if(Temp++ > 20)
{
return 1; //超时退出
} */
} while(r1 != 0x00);
Uart_Printf("SD卡的类型\n");
if(SD_GetCardInfo(psdi) != 0) // 获取存储卡信息失败
{
return 1;
}
Uart_Printf("获取存储卡信息\n");
r1 = SD_SendCMD(CMD_CRC_ON_OFF, 0); // 关闭crc16
r1 = SD_SendCMD(CMD_CRC_ON_OFF, 0);
if(r1 != 0 )
{
return 1;
}
Uart_Printf("关闭crc16\n");
r1 = SD_SendCMD(CMD_SET_BLOCKLEN, 512); // 设扇区大小512
if(r1 != 0 )
{
return 1;
}
Uart_Printf("\nIn ready state\n");
rSIOCON = (0x0 << 7) | (0x0 << 6) | (0x1 << 5) | (0x0 << 4) | (0x0 << 3) | (0x0 << 2) | 0x1;
rSBRDR = 5; //MCLK=60MHz,SIOCK=5MHz
rIVTCNT = 0;
return 0;
}
/*************************************************************************
*名称: SD_ReadBlockSingle
*功能: 读取单块数据
*参数: u32Sector扇区地址, *pBuff读取数据存饭缓存指针
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_ReadBlockSingle(INT32U u32Sector, INT8U *pu8Buff)
{
INT16U Temp = 0;
INT8U r1 = 0;
INT16U i = 0;
do{
r1 = SD_SendCMD(CMD_READ_SINGLE_BLOCK, u32Sector << 9);
//发送读BLOCK命令
if(Temp++ > 10) //超时返回
{
return 1;
}
}while(r1 != 0x00);
Temp = 0;
SPI_CS_ASSERT;
while( SPI_MasterTransmit(0xFF) != 0xFE); //等待数据起始令牌
for (i = 0; i < 512; i++) //读取一整块数据
{
pu8Buff[i] = SPI_MasterTransmit(0xFF);
}
SPI_MasterTransmit(0xFF); //接收伪CRC16
SPI_MasterTransmit(0xFF);
SPI_CS_DEASSERT;
SPI_MasterTransmit(0xFF); //发送8个填充时钟
return 0;
}
/*************************************************************************
*名称: SD_WriteBlockSingle
*功能: 写取单块数据
*参数: u32Sector扇区地址, *pBuff指向写入数据
*返回: 0成功 非零失败
*************************************************************************/
INT8U SD_WriteBlockSingle(INT32U u32Sector, INT8U *pu8Buff)
{
INT16U i;
INT8U Temp = 0;
INT8U r1 = 0;
do{
r1 = SD_SendCMD(CMD_WRITE_SINGLE_BLOCK, u32Sector << 9);
//发送读BLOCK命令
if(Temp++ > 10)
{
return 1;
}
}while(r1 != 0);
SPI_CS_ASSERT;
SPI_MasterTransmit(0xFF);
SPI_MasterTransmit(0xFE); //发送数据起始令牌
for (i = 0; i < 512; i++)
{
SPI_MasterTransmit(*pu8Buff++);
}
SPI_MasterTransmit(0xFF); //发送伪CRC16
SPI_MasterTransmit(0xFF);
r1 = SPI_MasterTransmit(0xFF);
if((r1 & 0x0F) != 0x05) //等待是否成功
{
SPI_MasterTransmit(0xFF);
SPI_CS_DEASSERT;
return 1;
}
while(SPI_MasterTransmit(0xFF) != 0xFF); //等待是否完成
SPI_MasterTransmit(0xFF);
SPI_CS_DEASSERT;
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -