基于AVR的SD卡操作以及一些注意的地方(原创)
0赞
发表于 8/9/2010 4:25:35 PM
阅读(2503)
最近搞了一下SD卡的一些东西,有很多有意思的地方。所以跟大家一起分享一下。
其实这个东西没有上FAT也很好搞,网上的程序啊,资料啊一大堆。所以对于程序来说,一般都很容易搞的定。我使用的是AVR的ATMEGA128 所以SD卡用的是SPI模式,如果你不明白我说的SPI模式是什么,建议你先去看一下DATASHEET,也可以去找一些中文的资料看一下。我使用的是AVR自带的SPI接口,所以操作起来很方便。做的过程也碰到了几点问题,所以拿出来说一下。(本人也是初级选手,所以有什么说的不对的地方请包含……)
SD卡的供电方式是3.3v的供电,而我的MCU用的是5V的供电,在网上搜了一下,据传说SD卡接5V会烧。所以没有敢去尝试(不是不想尝试,主要还是尝试不起)。
在网上找了很久找到一篇关于3.3V转5V文章看了一下,(其实在之前,我也想把AVR用3,3V供电,这样就能解决电源匹配的问题,但是对于我来说平常使用3.3V少,所以就没有考虑)又看了一下MEGA的DATASHEET和SD的DATASHEET,发现AVR发送SD接收(MOSI),片选信号,时钟信号等等,电平应该是没有什么大问题的,可以直接两者接到到一起。但是SD发送到AVR得时候可能会不稳定(MISO)。所以搞了一个转换电平,如图。

这个东西使用的器件比较少,一个二极管,一个上拉的电阻,电阻接的是5V
SD_DO :SD卡输出
MCU_DI :MCU输入
工作方式是这样的,当SD_DO=0的时候,MCU_DI也应该是0V+二极管导通电压,这个不用分析,一看
就很清楚。 当SD_DO=1的时候呢 这时候要注意了。D1上加的电压应该是5V-3.3V=1.7V ,所以你在选择二级管的时候,要选导通电压比这个电压值大的二极管,这样 1.7V的电压是导通不了二极管的,所以D1是截止状态的,从而MCU_DI也就得到了高电平了。
当然也有特殊的情况。在选择测试二极管的时候,把SD_DO接个限流电阻接到3.3V 去量图上节点的电压,如果电压是3.3V+二极管导通电压,而不是5V。则二极管是导通的,但不代表不能用,也要看这个电平够不够AVR去识别数字"1"这你要参考AVR的DATASHEET了。
下面说一下程序。我自己写了一个测试的程序。有些是参考了别人的代码。整个工程就不写了,就把重要的看一下吧,我使用的是ICC编译环境。已经测试可以使用。下面就贴出来。
#include <iom128v.h>
#include <macros.h>
#define MMC_CS_PIN BIT(4) //PORTB.4
#define MMC_PORT PORTB
unsigned char reading=0;
//***************************************************************************
//延时函数
//***************************************************************************
void delay_nus(unsigned int n)
{
unsigned char b;
for (b = 1; b<n; b++);
}
//****************************************************************************
//Send a Command to MMC/SD-Card
//Return: the second byte of response register of MMC/SD-Card
//****************************************************************************
unsigned char SD_Write_Command(unsigned char cmd,unsigned long arg)
{
unsigned char tmp;
unsigned char retry=0;
//MMC_PORT|=MMC_CS_PIN; //SD卡关闭
//send 8 Clock Impulse
Write_Byte_SPI(0xFF);
//set MMC_Chip_Select to low (MMC/SD-Card active)
MMC_PORT&=~MMC_CS_PIN; //SD卡使能
//延时函数
//***************************************************************************
void delay_nus(unsigned int n)
{
unsigned char b;
for (b = 1; b<n; b++);
}
//****************************************************************************
//Send a Command to MMC/SD-Card
//Return: the second byte of response register of MMC/SD-Card
//****************************************************************************
unsigned char SD_Write_Command(unsigned char cmd,unsigned long arg)
{
unsigned char tmp;
unsigned char retry=0;
//MMC_PORT|=MMC_CS_PIN; //SD卡关闭
//send 8 Clock Impulse
Write_Byte_SPI(0xFF);
//set MMC_Chip_Select to low (MMC/SD-Card active)
MMC_PORT&=~MMC_CS_PIN; //SD卡使能
Write_Byte_SPI(cmd|0x40); //送头命令
Write_Byte_SPI(arg>>24);
Write_Byte_SPI(arg>>16); //send 6 Byte Command to MMC/SD-Card
Write_Byte_SPI(arg>>8);
Write_Byte_SPI(arg&0xff);
Write_Byte_SPI(0x95); //仅仅对RESET有效的CRC效验码
Write_Byte_SPI(arg>>24);
Write_Byte_SPI(arg>>16); //send 6 Byte Command to MMC/SD-Card
Write_Byte_SPI(arg>>8);
Write_Byte_SPI(arg&0xff);
Write_Byte_SPI(0x95); //仅仅对RESET有效的CRC效验码
//get 8 bit response
//Read_Byte_MMC(); //read the first byte,ignore it.
do
{ //Only last 8 bit is used here.Read it out.
tmp = Read_Byte_SPI();
retry++;
}
while((tmp==0xff)&&(retry<100)); //当没有收到有效的命令的时候
if(reading==0)
MMC_PORT|=MMC_CS_PIN; //MMC_CS_PIN=1;
else MMC_PORT&=~MMC_CS_PIN; //MMC_CS_PIN=0;
return(tmp);
}
//****************************************************************************
//SD卡初始化(SPI-MODE)
//****************************************************************************
unsigned char SD_Init(void)
{
unsigned char retry,temp;
unsigned char i;
MMC_PORT&=~MMC_CS_PIN; //SD卡使能
//Read_Byte_MMC(); //read the first byte,ignore it.
do
{ //Only last 8 bit is used here.Read it out.
tmp = Read_Byte_SPI();
retry++;
}
while((tmp==0xff)&&(retry<100)); //当没有收到有效的命令的时候
if(reading==0)
MMC_PORT|=MMC_CS_PIN; //MMC_CS_PIN=1;
else MMC_PORT&=~MMC_CS_PIN; //MMC_CS_PIN=0;
return(tmp);
}
//****************************************************************************
//SD卡初始化(SPI-MODE)
//****************************************************************************
unsigned char SD_Init(void)
{
unsigned char retry,temp;
unsigned char i;
MMC_PORT&=~MMC_CS_PIN; //SD卡使能
delay_nus(250); //Wait MMC/SD ready...
for (i=0;i<0x0f;i++)
{
Write_Byte_SPI(0xff); //send 74 clock at least!!!
}
//Send Command CMD0 to MMC/SD Card
retry=0;
do
{ //retry 200 times to send CMD0 command
temp=SD_Write_Command(0,0);
retry++;
if(retry==100)
{
return(1) ;//CMD0 Error!
}
}
while(temp!=1);
//Send Command CMD1 to MMC/SD-Card
retry=0;
do
{ //retry 100 times to send CMD1 command
temp=SD_Write_Command(1,0);
retry++;
if(retry==100)
{
return(1) ;
}
}
while(temp!=0);
retry=0;
// SD_Write_Command(16,512); //设置一次读写BLOCK的长度为512个字节
for (i=0;i<0x0f;i++)
{
Write_Byte_SPI(0xff); //send 74 clock at least!!!
}
//Send Command CMD0 to MMC/SD Card
retry=0;
do
{ //retry 200 times to send CMD0 command
temp=SD_Write_Command(0,0);
retry++;
if(retry==100)
{
return(1) ;//CMD0 Error!
}
}
while(temp!=1);
//Send Command CMD1 to MMC/SD-Card
retry=0;
do
{ //retry 100 times to send CMD1 command
temp=SD_Write_Command(1,0);
retry++;
if(retry==100)
{
return(1) ;
}
}
while(temp!=0);
retry=0;
// SD_Write_Command(16,512); //设置一次读写BLOCK的长度为512个字节
MMC_PORT|=MMC_CS_PIN; //MMC_CS_PIN=1; //set MMC_Chip_Select to high
return(0); //All commands have been taken.
}
//****************************************************************************
//从SD卡读一个扇区
//long address --SD卡地址
//*P--存储缓冲
//Return 0 if no Error.
//****************************************************************************
unsigned char SD_Read_Block(unsigned long address,unsigned char *P)
{
unsigned char temp=0;
unsigned int i,j;
reading=1;
temp=SD_Write_Command(17,address); //读出RESPONSE
while (Read_Byte_SPI()!= 0xfe)
{;} //直到读取到了数据的开始头0XFE,才继续
for(i=0; i<512; i++)
{
*P=Read_Byte_SPI();
P++;
}
Read_Byte_SPI();//CRC - Byte
Read_Byte_SPI();//CRC - Byte
reading=0;
MMC_PORT|=MMC_CS_PIN; //关闭SD卡
return(temp);
}
//***************************************************************************
//SD卡写一个扇区
//long address --SD卡地址
//*P--存储缓冲
// Return 0 if no Error.
//***************************************************************************
unsigned char SD_Write_Block(unsigned long address,unsigned char *P)
{
unsigned char temp,temp1;
unsigned int i,j;
reading=1;
temp=SD_Write_Command(24,address);//读出RESPONSE
Write_Byte_SPI(0xFF);//Add NWR
Write_Byte_SPI(0XFE);//Add Start Block
for(i=0;i<512;i++)
{
Write_Byte_SPI(*P);
P++;
}
Write_Byte_SPI(0xFF);
Write_Byte_SPI(0xFF); //2 Bytes CRC
temp1=Read_Byte_SPI();//Read the Response xxx0 0101 is ok
if ((temp1&0x1f)!=0x05)
{
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return (1);// Error to Response
}
while(!Read_Byte_SPI());//wait for SD not busy
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
Write_Byte_SPI(0XFF);//ADD NDS
return(temp);
}
//******************************************************************************
//设置扇区读取字节设置
//Return 0 if no Error
//******************************************************************************
unsigned char Set_BLlock(unsigned int Choose_count)
{
return(0); //All commands have been taken.
}
//****************************************************************************
//从SD卡读一个扇区
//long address --SD卡地址
//*P--存储缓冲
//Return 0 if no Error.
//****************************************************************************
unsigned char SD_Read_Block(unsigned long address,unsigned char *P)
{
unsigned char temp=0;
unsigned int i,j;
reading=1;
temp=SD_Write_Command(17,address); //读出RESPONSE
while (Read_Byte_SPI()!= 0xfe)
{;} //直到读取到了数据的开始头0XFE,才继续
for(i=0; i<512; i++)
{
*P=Read_Byte_SPI();
P++;
}
Read_Byte_SPI();//CRC - Byte
Read_Byte_SPI();//CRC - Byte
reading=0;
MMC_PORT|=MMC_CS_PIN; //关闭SD卡
return(temp);
}
//***************************************************************************
//SD卡写一个扇区
//long address --SD卡地址
//*P--存储缓冲
// Return 0 if no Error.
//***************************************************************************
unsigned char SD_Write_Block(unsigned long address,unsigned char *P)
{
unsigned char temp,temp1;
unsigned int i,j;
reading=1;
temp=SD_Write_Command(24,address);//读出RESPONSE
Write_Byte_SPI(0xFF);//Add NWR
Write_Byte_SPI(0XFE);//Add Start Block
for(i=0;i<512;i++)
{
Write_Byte_SPI(*P);
P++;
}
Write_Byte_SPI(0xFF);
Write_Byte_SPI(0xFF); //2 Bytes CRC
temp1=Read_Byte_SPI();//Read the Response xxx0 0101 is ok
if ((temp1&0x1f)!=0x05)
{
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return (1);// Error to Response
}
while(!Read_Byte_SPI());//wait for SD not busy
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
Write_Byte_SPI(0XFF);//ADD NDS
return(temp);
}
//******************************************************************************
//设置扇区读取字节设置
//Return 0 if no Error
//******************************************************************************
unsigned char Set_BLlock(unsigned int Choose_count)
{
unsigned char temp,count=0;
do
{
temp=SD_Write_Command(16,Choose_count);
count++;
if (count==200)
{
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return(1); //Return Error
}
}
while(temp!=0);
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return(temp);
}
do
{
temp=SD_Write_Command(16,Choose_count);
count++;
if (count==200)
{
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return(1); //Return Error
}
}
while(temp!=0);
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return(temp);
}
