搜索
bottom↓
回复: 64

调了很多天了,SD卡读数据出错!!!!求助

[复制链接]

出0入0汤圆

发表于 2008-4-16 13:24:55 | 显示全部楼层 |阅读模式
最近在研究SD卡的驱动,有几个问题弄不太明白,发CMD0回复0x01,然后发CMD1回复0x00应该是初始化正确了吧,下面我在发送CMD17,可是一直等不到0xfe,是什么原因呢,我已经调了很多天了,哪位高手帮我看一下我的程序,帮我分析一下哪里出了问题谢谢

#include"include.h"

u08 sector[512]={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[6]={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[0]=0x41;
  cmd[5]=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[0]=59|0x40;
  mmc_send_cmd(cmd);*/
  

  cmd[0]=16|0x40;//main函数传递512给arg,CMD16设定读取块长为512字节
  cmd[1]=arg>>24;
  cmd[2]=arg>>16;
  cmd[3]=arg>>8;
  cmd[4]=arg;
  cmd[5]=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[1]=((addr & 0xFF000000) >>24 );
cmd[2]=((addr & 0x00FF0000) >>16 );
cmd[3]=((addr & 0x0000FF00) >>8 );
cmd[4]=addr;   //cmd[4]应该为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



}

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入4汤圆

发表于 2008-4-16 15:19:07 | 显示全部楼层
看看我的FAT文件系统.可能有用

出0入0汤圆

 楼主| 发表于 2008-4-16 15:50:13 | 显示全部楼层
不好意思我还没有搞文件系统,现在还在还没把SD卡的驱动搞好。刚刚调试程序搞的很乱,现在整理一下,待会把我写的程序发上来,希望大家帮我分析一下

出0入0汤圆

发表于 2008-4-16 17:55:03 | 显示全部楼层
CMD0后可以先用 ACMD41(应该是这个了)看看,注意发ACMD前要先发 CMD55的。  CMD1有的卡可能不支持。
另外 CMD0  ACMD41这些不要只发一次不成功就认为不成功。 卡也是需要时间去准备的。

出0入0汤圆

 楼主| 发表于 2008-4-16 18:05:27 | 显示全部楼层
谢谢BOZAI的提醒,我是看了你和elefan的程序流程后写的,你们的都是CMD0+CMD1,所以我也没多想,今晚就试一试,我想问一下,SD SPEC上面说只有CMD0需要CRC校检,之后CRC校检被忽略掉,即为发送方无需关心和接收方忽略它,而SD卡默认的read_bl_block是512,所以CMD16也应该是不必要的,不知道我说的对不对,还有一个问题,就是看了你的程序里面发送CMD之后CS线都抬高,那么在发送CMD17之后CS抬高,再拉低等待0xfe会不会造成接受0XFE数据的不同步而产生错误呢,我不是高手,只是有点疑问,不知你能否解答一下??谢谢

出0入0汤圆

发表于 2008-4-16 18:11:30 | 显示全部楼层
关于CRC,你说的没错
不过CMD16最好还是加上
512也是的,不过为了保险起见,都加上

CS只是充当传输数据的控制,所以之间停顿一下也没关系的。至少目前我程序跑的都很好。

出0入0汤圆

 楼主| 发表于 2008-4-16 21:03:08 | 显示全部楼层
刚下课,现在终于有时间调试了,继续~~~~

出0入0汤圆

 楼主| 发表于 2008-4-16 21:09:04 | 显示全部楼层
bozai你说的加CMD55+CMD41是不是说CMD1回复0x00也并不代表它结束了初始化呢?那什么样的回复可以代表真正的初始化?
现在更晕了,能收到0xfe但是却读不到数据

出0入0汤圆

 楼主| 发表于 2008-4-18 12:07:09 | 显示全部楼层
问题解决,oh yeah!!!!

出0入0汤圆

发表于 2008-4-18 13:09:59 | 显示全部楼层
对我有用,留个记号!

出0入0汤圆

发表于 2008-6-13 16:56:50 | 显示全部楼层
请教xiaocainiao ,你后来怎么解决的,我也是参考章其波高手的程序改写的,我也调了很多天了,读出来的数据总出错,而且是有规律的出错,比如说每8个字节的第1个数据字节是错的,快疯了,请各位帮帮帮忙。我的 QQ:147360206,邮箱:zxb1717@126.com,或在此论坛上留言也行,谢谢了

出0入0汤圆

 楼主| 发表于 2008-6-13 21:34:55 | 显示全部楼层
每个人的碰到的问题都不一样,我那是头文件定义有错误,改了就好了,你这个情况我倒是没听说过,“每8个字节的第1个数据字节是错的”??是什么意思,能讲清楚一点么?

出0入0汤圆

发表于 2008-6-14 09:53:56 | 显示全部楼层
每读取8个字节中首字节是错误数据,后来我又改了一下程序,这种现象好了一点。
我用的是kingston 的2G的SD卡,发现如果在初始化完成后先擦除要写入的块再写数据的话,就报错,写命令反馈为无效命令,只能是初始化后直接写了,不知道大家是什么操作流程?

出0入0汤圆

 楼主| 发表于 2008-6-14 10:09:44 | 显示全部楼层
发现如果在初始化完成后先擦除要写入的块再写数据的话
到底是读的问题还是写的问题啊?
如果是读的问题的话,CMD0+CMD1之后就可以直接CMD17读取扇区了

出0入0汤圆

发表于 2008-6-14 11:52:43 | 显示全部楼层
谢谢xiaocainiao 兄的关注!
1:我第一遍初始化不能使用CMD0+CMD1,否则永远初始化不了,只能用CMD0+CMD55+ACMD41.
2:如果我先执行擦除命令,以后的写命令就无法执行,一律报错。
3:我不敢确定数据全部写正确了,只能通过读出来的数据来确认写没写正确,但总是出现8个字节当中第一个字节错误的现象,就是第一,第九,第十七....个字节是错误的,原来的数据被替换为01,04,07,08当中的其中一个。

出0入0汤圆

 楼主| 发表于 2008-6-14 12:26:50 | 显示全部楼层
不好意思,对于写的问题我不太了解。
你直接读扇区的时候,是否正确呢?就是说你直接读扇区里面的内容跟你用winhex看到的扇区数据是否一致?

出0入0汤圆

发表于 2008-6-14 13:53:05 | 显示全部楼层
winhex???我不懂这个东东,反正我读出来的数据和我写进去的数据有些是不一样的,如果和实际数据不一样,那些值就是01,04,07,08当中的其中一个。

出0入0汤圆

发表于 2008-6-14 13:56:41 | 显示全部楼层
哦,我查了一下winhex是什么了,我没用这个软件,就是用读函数读出来的数据和我写进去的数据比较一下,就发现哪里数据又错了

出0入0汤圆

发表于 2008-6-14 14:04:39 | 显示全部楼层
CMD0+CMD1足以初始化,包括kingston在内

出0入0汤圆

发表于 2008-6-14 14:10:20 | 显示全部楼层
CMD1是针对MMC或厚度为1.4mm的SD卡的,我看协议上也这么说,而我是调试中也发现这个问题,我一开始就是参照网上例程用CMD0+CMD1,后来怎么都不行,仔细阅读数据手册后改为CMD0+CMD55+ACMD41就可以了

出0入0汤圆

 楼主| 发表于 2008-6-14 14:42:19 | 显示全部楼层
怎么能读和写的程序一起调试的呢?你怎么知道写进去的就是自己读出来的,最好还是一步一步来,先用wihex看看自己想读的那个扇区的数据,再把它读出来比对,很简单的,那个软件不难使用,把读调通再调写的就容易些了

出0入0汤圆

发表于 2008-6-14 16:54:31 | 显示全部楼层
是不是把SD卡用USB转换器插到电脑上然后用wihex软件打开观察某一扇区的数据啊,xiaocainiao兄非常热心,再次感谢!
因为我一开始没想到其他的办法,所以只能读出来观察数据是否正确,假设我写的全部正确嘿嘿!

出0入0汤圆

 楼主| 发表于 2008-6-14 16:56:48 | 显示全部楼层
把读卡器查到USB接口上,打开winhex看就行了,你先读扇区看看,最后出来的是55AA的话就差不多了,在比对一下是否完全一样

出0入0汤圆

发表于 2008-6-14 17:23:22 | 显示全部楼层
明天去买一个SD卡USB接口,按你的方法试一下,谢谢

出0入0汤圆

发表于 2008-6-14 17:39:49 | 显示全部楼层
顺便再问一个语法问题,如果要接受的数据比较大,是定义一个数组如aa[1024],还是定义一个指针*aa后为这个指针申请内存,以上哪个比较好,我目前是定义了一个全局型指针变量来接受数据,不知会不会对接收产生影响

出0入0汤圆

 楼主| 发表于 2008-6-14 20:41:02 | 显示全部楼层
不会有什么影响,就看你的RAM够不够大,1024?512就够了吧 刚好一个扇区啊

出0入0汤圆

发表于 2008-6-14 21:47:50 | 显示全部楼层
嗯,我知道了,谢谢!
我是这么做的

BYTE xdata *pt;

..................


BYTE SD_ReadBlockData(uint32 len, BYTE *recbuf)
{
      
.......
      for (i = 0; i < len; i++)
                   recbuf = SPI_Rec_Byte();                        /* 接收数据 receive data */
      ......


}

出0入0汤圆

发表于 2008-6-14 21:47:53 | 显示全部楼层
嗯,我知道了,谢谢!
我是这么做的

BYTE xdata *pt;

..................


BYTE SD_ReadBlockData(uint32 len, BYTE *recbuf)
{
      
.......
      for (i = 0; i < len; i++)
                   recbuf = SPI_Rec_Byte();                        /* 接收数据 receive data */
      ......


}

出0入0汤圆

发表于 2008-6-14 21:52:41 | 显示全部楼层
我的读数据函数:
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,够大了

出0入0汤圆

发表于 2008-6-14 21:56:45 | 显示全部楼层
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的,足够了

出0入0汤圆

发表于 2008-6-14 21:57:27 | 显示全部楼层
搞了这么多天还没搞定,真是郁闷!

出0入0汤圆

 楼主| 发表于 2008-6-14 22:13:45 | 显示全部楼层
BYTE xdata *pt; ??
全局指针??pt只是个指针而已,他跟p[512]区别是,p是地址,不能自加减,而pt是指针可以,
recbuf = pt;指针=指针何必搞的那么麻烦呢用个p[512],不就已经分配内存了么,在用个指针指向他就好了?
我不太明白你的意思,读一个扇区需要开辟1024个字节的内存?

出0入0汤圆

发表于 2008-6-14 22:22:49 | 显示全部楼层
我没开辟1024,那刚才那只是举例,我用数组居然出错,所以只能用指针了,郁闷就郁闷在这里,我得在检查检查再向你请教,谢谢你这么关注,随时向你报告进展,呵呵...

出0入0汤圆

 楼主| 发表于 2008-6-14 22:29:09 | 显示全部楼层
呵呵,我也是菜鸟,不知道能不能榜上你的忙,我知道那种碰到问题孤立无援的心情,我现在也被VS1003困扰着呢?

出0入0汤圆

发表于 2008-6-14 22:38:23 | 显示全部楼层
好,共同努力,以后有问题相互帮助

出0入0汤圆

发表于 2008-6-16 00:25:58 | 显示全部楼层
好 MARK 一下

出0入0汤圆

发表于 2008-6-16 09:14:14 | 显示全部楼层
我用wihex打不开啊,点击"OPEN"后就弹出一个对话框,说需要格式化,我晕了,你们怎么打开的,wihex是不是只能打开文件格式的东西?

出0入0汤圆

发表于 2008-6-16 09:16:45 | 显示全部楼层
xiaocainiao 兄,你是怎么打开的啊?

出0入0汤圆

发表于 2008-6-16 09:37:32 | 显示全部楼层
哦,打开了,按F9打开的,直接点击"open"打不开。

出0入0汤圆

发表于 2008-6-16 10:11:46 | 显示全部楼层
我是从第1个扇区,也就是第512个字节处开始写的,但是打开后却发现数据写在第0个扇区里,也就是"offset"从0开始的,这是怎么回事呢?

出0入0汤圆

 楼主| 发表于 2008-6-16 10:12:04 | 显示全部楼层
你是不是写的时候把FAT搞坏了,导致需要格式化

出0入0汤圆

 楼主| 发表于 2008-6-16 10:14:55 | 显示全部楼层
那可能你是打开的逻辑磁盘而不是物理磁盘在看

出0入0汤圆

发表于 2008-6-16 10:34:05 | 显示全部楼层
不能吧?我每次写完数据,然后用winhex(SD卡用读卡器连接到电脑的)直接打开的话它都提示需要格式化,但是不点击"open",只要直接按F9,就可以打开啊,但是只在第0个扇区有数据,其他扇区都没数据,而我写的是第n个扇区(n != 0),怎么回事呢?

“那可能你是打开的逻辑磁盘而不是物理磁盘在看 ”,那怎么打开物理磁盘啊

出0入0汤圆

 楼主| 发表于 2008-6-16 10:42:35 | 显示全部楼层
不能乱写的,如果破坏了BPB 或者是文件分配表,你就得格式化了,打开物理磁盘,你按F9之后仔细看一下,该选哪个就知道了

出0入0汤圆

发表于 2008-6-16 10:47:29 | 显示全部楼层
xiaocainiao,能不能加你啊

出0入0汤圆

发表于 2008-6-16 10:48:42 | 显示全部楼层
我打开的是物理磁盘啊physical Media,没错的

出0入0汤圆

发表于 2008-6-16 10:50:28 | 显示全部楼层
但是如果直接点"File"菜单下的“open ”就提示要格式化,直接按F9就没问题,只是我的数据为什么永远写在0扇区呢?

出0入0汤圆

 楼主| 发表于 2008-6-16 10:56:53 | 显示全部楼层
zxb1717 :“我是从第1个扇区,也就是第512个字节处开始写的,但是打开后却发现数据写在第0个扇区里,也就是"offset"从0开始的,这是怎么回事呢?”
写程序我不太了解,你0扇区是什么内容呢?想写入的1扇区又是什么内容呢?能贴出来么?

出0入0汤圆

发表于 2008-6-16 11:14:03 | 显示全部楼层
0扇区就是我要写入的数据(里面有几个是错误的),1扇区就全是0,我再查一查我的程序,可能有bug,你有没有QQ,方便的话我加你,打扰你工作了,同时对你说谢谢!

出0入0汤圆

发表于 2008-6-16 11:31:16 | 显示全部楼层
好了,是我程序的问题,参数传递不对,呵呵。这个问题解决了,但是数据写入时有几个字节是错误的,继续攻克....

出0入0汤圆

 楼主| 发表于 2008-6-16 11:34:02 | 显示全部楼层
0扇区不要乱写,一般是MBR所在的地方,破坏就不好了,估计应该是你的程序有问题,最好你还是把文件系统FAT16/32的spec看一遍
QQ贴在这里可能有点不方便,我马上要考试了,这个东西可能要放一放,你有问题我们就在这讨论吧

出0入0汤圆

发表于 2008-6-16 11:59:23 | 显示全部楼层
好的。

出0入0汤圆

发表于 2008-6-16 11:59:59 | 显示全部楼层
你是研究生?

出0入0汤圆

发表于 2008-6-16 15:13:30 | 显示全部楼层
请问xiaocainiao ,连续写多块的时候块地址会自动增加吗,还是需要手动调整地址?

出0入0汤圆

 楼主| 发表于 2008-6-16 15:21:49 | 显示全部楼层
不好意思,我没有做写的程序,只是把读和文件系统搞了一下,你做的写的程序,是想做什么东西呢?

出0入0汤圆

发表于 2008-6-16 15:30:35 | 显示全部楼层
哦,我是用单片机读写SD卡,主要存放一些比较大的数据,比如将一些彩色图片数据通过单片机写到SD卡中,需要的时候再读出来。那看来我只能摸黑走了,老板催的紧啊......

出0入0汤圆

 楼主| 发表于 2008-6-16 21:29:03 | 显示全部楼层
你在给老板做事啊,那你可比我强多了,这个论坛上高手很多的,你再发个贴问问他们吧

出0入0汤圆

发表于 2008-6-16 21:53:27 | 显示全部楼层
帮忙不在于高手,在于热心啊,再次谢谢!

出0入0汤圆

发表于 2008-6-18 21:44:48 | 显示全部楼层
我在19楼“CMD0+CMD1足以初始化,包括kingston在内”的观点错了-----这是旧版规范

新版规范是“CMD0+CMD55+ACMD41”

出0入0汤圆

发表于 2009-8-22 10:21:40 | 显示全部楼层
学习

出0入0汤圆

发表于 2010-10-8 14:30:55 | 显示全部楼层
回复【楼主位】xiaocainiao  
-----------------------------------------------------------------------

请问一下楼主你最后是哪里出问题了,最好具体一点,我遇到了和你一摸一样的问题,读数据块的时候等不到0xfe的标志,等到的全是0xff,十万火急,望楼主看到了能及时回复!

出0入0汤圆

发表于 2012-11-3 20:50:10 | 显示全部楼层
我最近也在读sd卡,初始化什么的都可以了,cmd17也能收到0xfe的数据令牌,但所有的数据都是0x00啊,不知道为什么
求解
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 07:17

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表