/*************************************************************************
*Copyright (c) 2009 陈崇
*All rights reserved
*文 件 名: sd.c
*说 明: sd卡驱动源文件
*
*主要硬件: Mega16
*编译环境: avr-gcc (WinAVR 20080610) 4.3.0
*当前版本: 1.0
*作 者: 陈崇
*取代版本:
*原作 者:
*完成日期: 2009-04-27
*************************************************************************/
#include "sd.h"
SD_INFO g_SDInfo;
/*************************************************************************
* 名称: SPI_MasterInit
* 功能: SPI主机模式初始化
* 参数: u8Speed SPI速度
* 返回: 无
*************************************************************************/
void SPI_MasterInit(INT8U u8Speed)
{
if(u8Speed == SPI_HIGH_SPEED)//初始化为高速
{
SPCR = (1 << SPE) | (1 << MSTR);
//使能SPI 主机模式,设置时钟速率为fck/2
SPSR |= _BV(SPI2X); //倍速
}
if(u8Speed == SPI_LOW_SPEED) //初始化为低速
{
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
//使能SPI主机模式,设置时钟速率为fck/128
SPSR &= ~(1 << SPI2X); //关闭倍速
}
}
/*************************************************************************
* 名称: void SPI_MasterTransmit(INT8U u8Data)
* 功能: SPI主机模式传送数据
* 参数: cData 要传输的字节数据
* 返回: SPI接收值
*************************************************************************/
INT8U SPI_MasterTransmit(INT8U u8Data)
{
SPDR = u8Data; //* 启动数据传输
while(!(SPSR & (1<<SPIF)));//等待传输结束
return SPDR; //返回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);//发送读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;
SPI_MasterInit(SPI_LOW_SPEED);
for(i = 0; i < 100; i++) //至少发送74个脉冲
{
SPI_MasterTransmit(0xFF);
}
do //复位存储卡
{
r1 = SD_SendCMD(CMD_GO_IDLE_STATE , 0); //发IDLE命令
if(Temp++ > 100)
{
return 1; //超时退出
}
} while(r1 != 0x01);
Temp = 0;
do //激活存储卡
{
r1 = SD_SendCMD(CMD_SEND_OP_COND , 0); //发CMD1命令激活卡
if(Temp++ > 100)
{
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;
}
}
if(Temp++ > 100)
{
return 1; //超时退出
}
} while(r1 != 0x00);
if(SD_GetCardInfo(psdi) != 0) // 获取存储卡信息失败
{
return 1;
}
SPI_MasterInit(SPI_HIGH_SPEED); // 设置SPI为高速模式
r1 = SD_SendCMD(CMD_CRC_ON_OFF, 0); // 关闭crc16
if(r1 != 0 )
{
return 1;
}
r1 = SD_SendCMD(CMD_SET_BLOCKLEN, 512); // 设扇区大小512
if(r1 != 0 )
{
return 1;
}
return 0;