调了很多天了,SD卡读数据出错!!!!求助
最近在研究SD卡的驱动,有几个问题弄不太明白,发CMD0回复0x01,然后发CMD1回复0x00应该是初始化正确了吧,下面我在发送CMD17,可是一直等不到0xfe,是什么原因呢,我已经调了很多天了,哪位高手帮我看一下我的程序,帮我分析一下哪里出了问题谢谢#include"include.h"
u08 sector={1,2,3};
/**************MMC片选***************/
void mmc_cs(u08 data)
{
if(data==1)
PORTB&=~(_BV(PB4));//mmc_cs(1)拉低cs信号线
else
PORTB|=_BV(PB4);//mmc_cs(0)抬高cs信号线
}
/**************MMC发送CMD**************/
u08 mmc_send_cmd(u08 *cmd)
{
u08 i=0,j=0,timeout=0;
u08 temp=0xff;
mmc_cs(0); //cs抬高
spi_send(0xff);
spi_send(0xff);
spi_send(0xff);
spi_send(0xff);
spi_send(0xff);
spi_send(0xff);
mmc_cs(1); //cs拉低
while(i++<6)
{
spi_send(*cmd++);
}
while((temp=spi_send(0xff))==0xff)
{
if(timeout++>200) return(temp);
}
mmc_cs(0); //cs抬高
return(temp);
}
/**************MMC初始化**********/
u08 mmc_init(void)
{
u32 arg=512;
u08 cmd={0x40,0x00,0x00,0x00,0x00,0x95};
u08 a,timeout=0,temp=0x99,temp1=0x88,temp2=0xaa;
u16 i=0;
spi_init();
for(a=0;a<200;a++)
{ }
for(a=0;a<0x10;a++) //74个clock
{
spi_send(0XFF);
}
if((temp=mmc_send_cmd(cmd))!=0x01)
return (0xe0);//发送CMD0失败返回0xe0
//return (temp);//这里是测试需要,发送CMD0后成功发回0x01 (#1)
cmd=0x41;
cmd=0xff;
while((temp1=mmc_send_cmd(cmd))!=0x00)
{if(timeout++>0xfffe)
return(0xe1);//发送CMD1失败返回0xe1
}
//return(temp1);//这里是测试需要,发送CMD1后成功发回0x00
//发送cmd0返回0x01,cmd1返回0x00应该是初始化成功了吧????
spi_highspeed();//高速SPI
/* cmd=59|0x40;
mmc_send_cmd(cmd);*/
cmd=16|0x40;//main函数传递512给arg,CMD16设定读取块长为512字节
cmd=arg>>24;
cmd=arg>>16;
cmd=arg>>8;
cmd=arg;
cmd=0x95;
temp2=mmc_send_cmd(cmd);
return(temp2);
//以上是发送CMD59和CMD16 ,但是我看SD SPEC上面说只有CMD0需要CRC校检,之后CRC校检被忽略掉,即为发送方无需关心和接收方忽略它,而
//而SD卡默认的read_bl_block是512,所以CMD16也应该是不必要的,不知道我说的对不对,但为了调试我还是加上了。
}
/*************读one sector数据**********/
u08 mmc_read_sector(u32 addr,u08 *buffer)
{
u16 i,j;
u08 k=0xaa,retry=0,m=0;
u08 cmd[] = {0x51,0x00,0x00,0x00,0x00,0xFF};
addr=addr<<9; //address*512
cmd=((addr & 0xFF000000) >>24 );
cmd=((addr & 0x00FF0000) >>16 );
cmd=((addr & 0x0000FF00) >>8 );
cmd=addr; //cmd应该为0
do
{k=mmc_send_cmd(cmd);
retry++;
if(retry>100)return(0X44);//发送CMD17失败返回0X44
}
while(k!=0);
//return(k);//为了测试我在这里返回一个值看看cmd17是否被正确写入了
//这里可以返回0x00,应该是写CMD17正确了吧?
mmc_cs(1); //拉低cs
retry=0;
while((m=spi_send(0xff))!=0xfe)
{retry++;
if(retry>100)return(m);
}
//return(m); //读到0xfe成功 即返回m=0xfe,可惜一直等不到只是返回0xff T_T
for(i=0;i<512;i++)
{
*buffer++=spi_send(0xff);
}
spi_send(0xff);
spi_send(0xff);
mmc_cs(0);
return(0xce);//操作成功后返回0xce
} 看看我的FAT文件系统.可能有用 不好意思我还没有搞文件系统,现在还在还没把SD卡的驱动搞好。刚刚调试程序搞的很乱,现在整理一下,待会把我写的程序发上来,希望大家帮我分析一下 CMD0后可以先用 ACMD41(应该是这个了)看看,注意发ACMD前要先发 CMD55的。CMD1有的卡可能不支持。
另外 CMD0ACMD41这些不要只发一次不成功就认为不成功。 卡也是需要时间去准备的。 谢谢BOZAI的提醒,我是看了你和elefan的程序流程后写的,你们的都是CMD0+CMD1,所以我也没多想,今晚就试一试,我想问一下,SD SPEC上面说只有CMD0需要CRC校检,之后CRC校检被忽略掉,即为发送方无需关心和接收方忽略它,而SD卡默认的read_bl_block是512,所以CMD16也应该是不必要的,不知道我说的对不对,还有一个问题,就是看了你的程序里面发送CMD之后CS线都抬高,那么在发送CMD17之后CS抬高,再拉低等待0xfe会不会造成接受0XFE数据的不同步而产生错误呢,我不是高手,只是有点疑问,不知你能否解答一下??谢谢 关于CRC,你说的没错
不过CMD16最好还是加上
512也是的,不过为了保险起见,都加上
CS只是充当传输数据的控制,所以之间停顿一下也没关系的。至少目前我程序跑的都很好。 刚下课,现在终于有时间调试了,继续~~~~ bozai你说的加CMD55+CMD41是不是说CMD1回复0x00也并不代表它结束了初始化呢?那什么样的回复可以代表真正的初始化?
现在更晕了,能收到0xfe但是却读不到数据 问题解决,oh yeah!!!! 对我有用,留个记号! 请教xiaocainiao ,你后来怎么解决的,我也是参考章其波高手的程序改写的,我也调了很多天了,读出来的数据总出错,而且是有规律的出错,比如说每8个字节的第1个数据字节是错的,快疯了,请各位帮帮帮忙。我的 QQ:147360206,邮箱:zxb1717@126.com,或在此论坛上留言也行,谢谢了 每个人的碰到的问题都不一样,我那是头文件定义有错误,改了就好了,你这个情况我倒是没听说过,“每8个字节的第1个数据字节是错的”??是什么意思,能讲清楚一点么? 每读取8个字节中首字节是错误数据,后来我又改了一下程序,这种现象好了一点。
我用的是kingston 的2G的SD卡,发现如果在初始化完成后先擦除要写入的块再写数据的话,就报错,写命令反馈为无效命令,只能是初始化后直接写了,不知道大家是什么操作流程? 发现如果在初始化完成后先擦除要写入的块再写数据的话
到底是读的问题还是写的问题啊?
如果是读的问题的话,CMD0+CMD1之后就可以直接CMD17读取扇区了 谢谢xiaocainiao 兄的关注!
1:我第一遍初始化不能使用CMD0+CMD1,否则永远初始化不了,只能用CMD0+CMD55+ACMD41.
2:如果我先执行擦除命令,以后的写命令就无法执行,一律报错。
3:我不敢确定数据全部写正确了,只能通过读出来的数据来确认写没写正确,但总是出现8个字节当中第一个字节错误的现象,就是第一,第九,第十七....个字节是错误的,原来的数据被替换为01,04,07,08当中的其中一个。 不好意思,对于写的问题我不太了解。
你直接读扇区的时候,是否正确呢?就是说你直接读扇区里面的内容跟你用winhex看到的扇区数据是否一致? winhex???我不懂这个东东,反正我读出来的数据和我写进去的数据有些是不一样的,如果和实际数据不一样,那些值就是01,04,07,08当中的其中一个。 哦,我查了一下winhex是什么了,我没用这个软件,就是用读函数读出来的数据和我写进去的数据比较一下,就发现哪里数据又错了 CMD0+CMD1足以初始化,包括kingston在内 CMD1是针对MMC或厚度为1.4mm的SD卡的,我看协议上也这么说,而我是调试中也发现这个问题,我一开始就是参照网上例程用CMD0+CMD1,后来怎么都不行,仔细阅读数据手册后改为CMD0+CMD55+ACMD41就可以了 怎么能读和写的程序一起调试的呢?你怎么知道写进去的就是自己读出来的,最好还是一步一步来,先用wihex看看自己想读的那个扇区的数据,再把它读出来比对,很简单的,那个软件不难使用,把读调通再调写的就容易些了 是不是把SD卡用USB转换器插到电脑上然后用wihex软件打开观察某一扇区的数据啊,xiaocainiao兄非常热心,再次感谢!
因为我一开始没想到其他的办法,所以只能读出来观察数据是否正确,假设我写的全部正确嘿嘿! 把读卡器查到USB接口上,打开winhex看就行了,你先读扇区看看,最后出来的是55AA的话就差不多了,在比对一下是否完全一样 明天去买一个SD卡USB接口,按你的方法试一下,谢谢 顺便再问一个语法问题,如果要接受的数据比较大,是定义一个数组如aa,还是定义一个指针*aa后为这个指针申请内存,以上哪个比较好,我目前是定义了一个全局型指针变量来接受数据,不知会不会对接收产生影响 不会有什么影响,就看你的RAM够不够大,1024?512就够了吧 刚好一个扇区啊 嗯,我知道了,谢谢!
我是这么做的
BYTE xdata *pt;
..................
BYTE SD_ReadBlockData(uint32 len, BYTE *recbuf)
{
.......
for (i = 0; i < len; i++)
recbuf = SPI_Rec_Byte(); /* 接收数据 receive data */
......
} 嗯,我知道了,谢谢!
我是这么做的
BYTE xdata *pt;
..................
BYTE SD_ReadBlockData(uint32 len, BYTE *recbuf)
{
.......
for (i = 0; i < len; i++)
recbuf = SPI_Rec_Byte(); /* 接收数据 receive data */
......
} 我的读数据函数:
BYTE xdata *pt;
............
BYTE SD_ReadBlockData(uint32 len, BYTE *recbuf)
{
recbuf = pt;
..........
SPI_CS_Assert();
do
{ tmp = 0xFF;
tmp = SPI_Rec_Byte();
i++;
}while(((tmp == 0xFF) && (i < READ_TIMEOUT_100MS));
for (i = 0; i < len; i++)
pt = SPI_Rec_Byte();
.............
}
我担心定义全局变量的时候只分配一个字节内存,而后面有需要512内存,这个在接收数据的时候不是道会不会自动给*pt分配内存,我的RAM 16K,够大了 BYTE xdata *pt;
..................
BYTE SD_ReadBlockData(uint32 len, BYTE *recbuf)
{
recbuf = pt;
.......
for (i = 0; i < len; i++)
recbuf = SPI_Rec_Byte(); /* 接收数据 receive data */
......
}
因为在定义全局变量的时候只给*pt分配一个字节的内存(没错吧?),但是后来接收数据的时候需要512字节,这个系统会自动分配吗?我的RAM 16K的,足够了 搞了这么多天还没搞定,真是郁闷! BYTE xdata *pt; ??
全局指针??pt只是个指针而已,他跟p区别是,p是地址,不能自加减,而pt是指针可以,
recbuf = pt;指针=指针何必搞的那么麻烦呢用个p,不就已经分配内存了么,在用个指针指向他就好了?
我不太明白你的意思,读一个扇区需要开辟1024个字节的内存? 我没开辟1024,那刚才那只是举例,我用数组居然出错,所以只能用指针了,郁闷就郁闷在这里,我得在检查检查再向你请教,谢谢你这么关注,随时向你报告进展,呵呵... 呵呵,我也是菜鸟,不知道能不能榜上你的忙,我知道那种碰到问题孤立无援的心情,我现在也被VS1003困扰着呢? 好,共同努力,以后有问题相互帮助 好 MARK 一下 我用wihex打不开啊,点击"OPEN"后就弹出一个对话框,说需要格式化,我晕了,你们怎么打开的,wihex是不是只能打开文件格式的东西? xiaocainiao 兄,你是怎么打开的啊? 哦,打开了,按F9打开的,直接点击"open"打不开。 我是从第1个扇区,也就是第512个字节处开始写的,但是打开后却发现数据写在第0个扇区里,也就是"offset"从0开始的,这是怎么回事呢? 你是不是写的时候把FAT搞坏了,导致需要格式化 那可能你是打开的逻辑磁盘而不是物理磁盘在看 不能吧?我每次写完数据,然后用winhex(SD卡用读卡器连接到电脑的)直接打开的话它都提示需要格式化,但是不点击"open",只要直接按F9,就可以打开啊,但是只在第0个扇区有数据,其他扇区都没数据,而我写的是第n个扇区(n != 0),怎么回事呢?
“那可能你是打开的逻辑磁盘而不是物理磁盘在看 ”,那怎么打开物理磁盘啊 不能乱写的,如果破坏了BPB 或者是文件分配表,你就得格式化了,打开物理磁盘,你按F9之后仔细看一下,该选哪个就知道了 xiaocainiao,能不能加你啊 我打开的是物理磁盘啊physical Media,没错的 但是如果直接点"File"菜单下的“open ”就提示要格式化,直接按F9就没问题,只是我的数据为什么永远写在0扇区呢? zxb1717 :“我是从第1个扇区,也就是第512个字节处开始写的,但是打开后却发现数据写在第0个扇区里,也就是"offset"从0开始的,这是怎么回事呢?”
写程序我不太了解,你0扇区是什么内容呢?想写入的1扇区又是什么内容呢?能贴出来么? 0扇区就是我要写入的数据(里面有几个是错误的),1扇区就全是0,我再查一查我的程序,可能有bug,你有没有QQ,方便的话我加你,打扰你工作了,同时对你说谢谢! 好了,是我程序的问题,参数传递不对,呵呵。这个问题解决了,但是数据写入时有几个字节是错误的,继续攻克.... 0扇区不要乱写,一般是MBR所在的地方,破坏就不好了,估计应该是你的程序有问题,最好你还是把文件系统FAT16/32的spec看一遍
QQ贴在这里可能有点不方便,我马上要考试了,这个东西可能要放一放,你有问题我们就在这讨论吧 好的。 你是研究生? 请问xiaocainiao ,连续写多块的时候块地址会自动增加吗,还是需要手动调整地址? 不好意思,我没有做写的程序,只是把读和文件系统搞了一下,你做的写的程序,是想做什么东西呢? 哦,我是用单片机读写SD卡,主要存放一些比较大的数据,比如将一些彩色图片数据通过单片机写到SD卡中,需要的时候再读出来。那看来我只能摸黑走了,老板催的紧啊...... 你在给老板做事啊,那你可比我强多了,这个论坛上高手很多的,你再发个贴问问他们吧 帮忙不在于高手,在于热心啊,再次谢谢! 我在19楼“CMD0+CMD1足以初始化,包括kingston在内”的观点错了-----这是旧版规范
新版规范是“CMD0+CMD55+ACMD41” 学习 回复【楼主位】xiaocainiao
-----------------------------------------------------------------------
请问一下楼主你最后是哪里出问题了,最好具体一点,我遇到了和你一摸一样的问题,读数据块的时候等不到0xfe的标志,等到的全是0xff,十万火急,望楼主看到了能及时回复! 我最近也在读sd卡,初始化什么的都可以了,cmd17也能收到0xfe的数据令牌,但所有的数据都是0x00啊,不知道为什么
求解
页:
[1]