/******************************************************************************************************************************
* 函数名称:SD_WriteSingleSectors
* 函数功能:把数据缓冲的数据写入卡里
* 函数说明:一次只写个扇区或块
* 参数说明:缓冲区数据指针 扇区或块的位置
* 返 回 值:0 成功 1 失败
* 函数调用:
* 全局变量:
* 编 写:
* E-mail :
* 修改备注:
* 版 本:v1.0
* 日 期:2012年5月21日 星期一 17:57:43
******************************************************************************************************************************/
u8 SD_WriteSingleSectors( u8 *buff, u32 sectors )
{
u8 sta;
if ( sd_type != SD_TYPE_V2HC )
{
sectors *= 512;
}
sta = sd_send_cmds( SD_CMD24, sectors, 0x01 );
if ( sta == 0 )
{
sta = sd_WriteBufferToDisk( buff, 0xFE );
}
sd_Disable_Select();
#if SD_DEBUG_EN>0
printf( "数据写入返回值为 %x \n\n\n", sta );
#endif
return sta;
}
/******************************************************************************************************************************
* 函数名称:SD_ReadMultiSectors
* 函数功能:读取多个扇区或是块的数据
* 函数说明:可以读取一个或是多个
* 参数说明:缓冲区数据指针 扇区/块位置 扇区/块的数量
* 返 回 值:0 成功正确 1 失败异常
* 函数调用:
* 全局变量:
* 编 写:
* E-mail :
* 修改备注:
* 版 本:V1.0
* 日 期:2012年5月21日 星期一 17:56:02
******************************************************************************************************************************/
u8 SD_ReadMultiSectors( u8 *buff, u32 sectors, u32 num )
{
u8 sta;
if ( sd_type != SD_TYPE_V2HC )
{ // 如果不是2.0HC高速卡,则转换为字节地址
sectors <<= 9;
#if SD_DEBUG_EN>0
printf( "使用的不是高速卡哦!" );
#endif
}
if ( num == 1 )
{
sta = sd_send_cmds( SD_CMD17, sectors, 0x01 );
if ( sta == 0 )
{
sta = sd_ReceiveDataToBuffer( buff, 512 );
}
}
else {
sta = sd_send_cmds( SD_CMD18, sectors, 0x01 );
do
{
sta = sd_ReceiveDataToBuffer( buff, 512 );
buff += 512;
num--;
} while ( (sta==0)&&num );
sd_send_cmds( SD_CMD12, 0, 0x01 );
}
sd_Disable_Select();
return sta;
}
/******************************************************************************************************************************
* 函数名称:SD_ReadSingleSectors
* 函数功能:读取一个扇区的数据到缓冲区
* 函数说明:读取的单位是扇区
* 参数说明:缓冲区指针 扇区位置/偏置
* 返 回 值:
* 函数调用:
* 全局变量:
* 编 写:
* E-mail :
* 修改备注:
* 版 本:V1.0
* 日 期:2012年5月21日 星期一 17:16:59
******************************************************************************************************************************/
u8 SD_ReadSingleSectors( u8 *buff, u32 sectors )
{
u8 sta;
#if SD_DEBUG_EN>0
printf( "\n要读取的扇区是%d\n\n", sectors );
#endif
if ( sd_type != SD_TYPE_V2HC )
{ // 如果不是2.0HC高速卡,则转换为字节地址
sectors <<= 9;
}
sta = sd_send_cmds( SD_CMD17, sectors, 0x01 );
if ( sta == 0 )
{
sta = sd_ReceiveDataToBuffer( buff, 512 );
}
sd_Disable_Select();
return sta;
}
/******************************************************************************************************************************
* 函数名称:SD_Init
* 函数功能:检测卡是否存在并检测卡的类型,初始化SD卡
* 函数说明:目前可以适用的卡有V1.0,V2.0,V2.0HC,MMC
* 参数说明:
* 返 回 值:0 初始化成功与正常 1 初始化失败或是卡异常
* 函数调用:
* 全局变量:
* 编 写:
* E-mail :
* 修改备注:
* 版 本:V1.0
* 日 期:2012年5月21日 星期一 17:27:07
******************************************************************************************************************************/
u8 SD_Init( void )
{
u16 i;
u16 cnt;
u8 sta;
u8 buf[4];
sd_type = 0x00;
sd_gpio_spi_init();
sd_Disable_Select();// 取消片选
delay_ms( 5 ); // 小延时,让SD稳定下来
// 发送至少74个时钟,让SD卡完成上电后的工作
for ( cnt = 0; cnt < 11; cnt++ )
{
sd_ReadWriteByte( 0xff ); // 不使能片选信号,发送时钟
}
// 接下来发送命令0,让SD卡复位进入空状态
cnt = 200;
do
{ // 循环读取发送命令0的返回状态,直到出现0x01或是超出200次
sta = sd_send_cmds( SD_CMD0, 0, 0x95 );
cnt--;
} while ( ( sta != 0x01 ) && ( cnt ) );
if ( cnt == 0) // 判断上面循环退出的原因,读取到0x01???? 超时????
{
// 如果超时了,取消片选后,直接退出
sd_Disable_Select();
#if SD_DEBUG_EN>0 // 如果使能了调试,则通过串口打印出调试信息
printf( "SD卡复位失败.......\n\n" );
#endif
return 1; // 返回1,初始化失败
}
#if SD_DEBUG_EN>0
printf( "SD卡复位成功........\n\n" );
#endif
// 读取命令8的返回值
sta = sd_send_cmds( SD_CMD8, 0x1AA, 0x87 );
#if SD_DEBUG_EN>0 // 使能调试时,通过串口打印出该命令的返回值
printf( "命令SD_CMD8 返回 %d........\n\n", sta );
#endif
if ( sta == 0x01 ) // 如果是0x01, 则是2.0版本,2.0版本中还是2.0HC版本
{
// 读取命令8后卡发送来的四字节数据,只有2.0版本有
for ( i = 0; i < 4; i++ )
{
buf[ i ] = sd_ReadWriteByte( 0xff );
}
#if SD_DEBUG_EN>0 // 使能调试时
printf( "检测到卡为2.0卡..." );
printf( "接收到手四字节数据是:%d %d %d %d\n\n", buf[0], buf[1], buf[2], buf[3] );
#endif
// 根据读取回来的四字节数据,判断该卡是否支持2.7---3.6的电压
if ( ( buf[ 2 ] == 0x01 )&&( buf[ 3 ] == 0xAA ) ) //
{
#if SD_DEBUG_EN>0
printf( "SD卡可以支持电压范围2.7---3.6....\n\n" );
#endif
// 只有支持2.7---3.6电压了才继续操作
cnt = 0xffff;
do
{
sd_send_cmds( SD_CMD55, 0, 0x01 );
sta = sd_send_cmds( SD_CMD41, 0x40000000, 0x01 );
cnt--;
} while ( sta && cnt );
sta = sd_send_cmds( SD_CMD58, 0, 0 );
if ( sta != 0x00 ) // 如果没有得到正确的回应
{
sd_Disable_Select();
#if SD_DEBUG_EN>0
printf( "命令SD_CMD58错误返回 %d....\n\n", sta );
#endif
return 1;
}
// 如果有得到正确的回应,则读取卡发回来的OCR信息
for ( i = 0; i < 4; i++ ) // 读取四字节的信息
{
buf[ i ] = sd_ReadWriteByte( 0xff );
}
sd_Disable_Select();
#if SD_DEBUG_EN>0
printf( "从卡读取回来的OCR信息是 %x %x %x %x....\n\n", buf[0],buf[1],buf[2],buf[3] );
#endif
// 读取完成,鉴别卡是2.0还是2.0HC
if ( buf[0] & 0x40 )
{
#if SD_DEBUG_EN>0
printf( "检测到卡的类型是V2.0HC高速卡,可以正常使用.....\n\n" );
#endif
sd_type = SD_TYPE_V2HC;
}
else {
#if SD_DEBUG_EN>0
printf( "检测到卡的类型是V2.0普通卡,可以正常使用.....\n\n" );
#endif
sd_type = SD_TYPE_V2;
}
spi_SpeedHigh(); // 让SPI进入高速模式
}
else { // 如果不支持2.7---3.6电压的处理
sd_Disable_Select();
return 1;
}
}
else { // 认为是1.0版本或是MMC卡,如果是MMC,需要设置扇区的大小
// 无四字节数据的输出
sd_type = SD_TYPE_V1; // 暂时认为是V1.0的卡
sd_send_cmds( SD_CMD55, 0, 0x01 );
sta = sd_send_cmds( SD_CMD41, 0, 0x01 );
if ( sta <= 1 )
{ // V1.0卡
sd_type = SD_TYPE_V1;
cnt = 0xffff;
do
{
sd_send_cmds( SD_CMD55, 0, 0x01 );
sta = sd_send_cmds( SD_CMD41, 0, 0x01 );
cnt--;
} while ( sta && cnt );
#if SD_DEBUG_EN>0
printf( "检测到卡的类型是V1.0普通卡," );
#endif
}
else { // MMC卡
sd_type = SD_TYPE_MMC;
cnt = 0xffff;
do
{
sta = sd_send_cmds( SD_CMD1, 0, 0x01 );
cnt--;
} while ( sta && cnt );
#if SD_DEBUG_EN>0
printf( "检测到卡的类型是MMC卡," );
#endif
}
if ( (cnt==0)||(sd_send_cmds(SD_CMD16,512,0x01)!=0) )
{
sd_type = SD_TYPE_ERR;
sd_Disable_Select();
#if SD_DEBUG_EN>0
printf( "无法设置卡的扇区大小,请检查卡!\n\n" );
#endif
return 1;
}
#if SD_DEBUG_EN>0
else {
printf( "可以正常使用了.....\n\n" );
}
#endif
}
sd_Disable_Select();
return 0; // 返回0 , 初始化成功
}
|