智能车制作

标题: xs128接sd卡调试的一点资料 [打印本页]

作者: cfanfrank    时间: 2009-5-20 20:22
标题: xs128接sd卡调试的一点资料
本帖最后由 cfanfrank 于 2009-5-20 20:26 编辑


呵呵,网上没有现成资料,自己动手做的一点东西,共享一下。希望高手指正批评啊。

硬件:
S125v)可以跟sd卡模块(3.3v)直接连接。这个是冒着俺手机里的sd卡被烧的危险试的!
sd卡模块是在淘宝上买的,icdev网站出的那种,20多块。

Sd <-> S12
MISO <-> MISO
MOSI <-> MOSI
3.3V <-> 任意一个PWM,这个也可以直接接5V,接PWM的目的是可以通过程序控制sd卡重新启动。但是不能接3.3V!因为试过接3.3V,不大正常!
GND <-> GND
SCK <-> SCK
CS <-> 任意一个通用io

软件:

Spi读取和写入函数:

  1. #define spi_write(x) \
  2. {   \
  3.     while (!SPI0SR_SPTEF);   \
  4.     SPI0DRL = (x);    \
  5.     while (!SPI0SR_SPIF);    \
  6.     spi_tmp_var = SPI0DRL;   \
  7. }   

  8. #define spi_read(x)  \
  9. {   \
  10.     while (!SPI0SR_SPTEF);   \
  11.     SPI0DRL = 0xff;   \
  12.     while (!SPI0SR_SPIF);    \
  13.     (x) = SPI0DRL;    \
  14. }
复制代码




这样写是为了避免函数调用,浪费时间。

作者: cfanfrank    时间: 2009-5-20 20:23
本帖最后由 cfanfrank 于 2009-5-20 20:28 编辑

Sd卡发送命令函数:




  1. byte sd_send_cmd(byte cmd, dword arg, byte crc)
  2. {
  3.     unsigned char r1;
  4.     unsigned char Retry = 0;

  5.     //????????
  6.     spi_write(0xff);
  7.     //片选端置低,选中SD卡
  8.     SD_CS = 0;

  9.     //发送
  10.     spi_write(cmd | 0x40);                         //分别写入命令
  11.     spi_write(arg >> 24);
  12.     spi_write(arg >> 16);
  13.     spi_write(arg >> 8);
  14.     spi_write(arg);
  15.     spi_write(crc);

  16.     //等待响应,或超时退出
  17.     do {
  18.        Retry++;
  19.        if(Retry > 200)
  20.        {
  21.            break;
  22.        }
  23.        spi_read(r1);
  24.     } while(r1 == 0xFF);

  25.     //关闭片选
  26.     SD_CS = 1;

  27.     //在总线上额外增加个时钟,让SD卡完成剩下的工作
  28.     spi_write(0xFF);

  29.     //返回状态值
  30.     return r1;
  31. }
复制代码


Sd卡初始化:

1.首先是要把连sd卡电源的那个pwm端口调成5v,也就是占空比100%,要让它先0v一会儿,再调成5v,这样sd卡就会重启了。这方法有点笨,占用了一个pwm口,谁有的比较好的方法呢?



  1.     // power down
  2.     PWMDTY6 = 100;
  3.     delay(200);

  4.     // power up
  5.     PWMDTY6 = 0;
  6.     delay(200);
复制代码

作者: cfanfrank    时间: 2009-5-20 20:23
本帖最后由 cfanfrank 于 2009-5-20 20:29 编辑

2.然后就是设置spi参数了,发些0xff,给一些时间让sd卡初始化。注意,初始化的时候spi时钟是很慢的。别人说,最好350K以下。


  1. // set low speed
  2. SPI0CR1 = 0x5e; //CPOL=1,CPHA=1
  3. SPI0CR2 = 0x10;
  4. SPI0BR  = 0x07;  // 80M / 256 = 312.5k
  5.                     
  6. // > 74 clock cycle init
  7. for (i = 0; i < 10; i++)
  8.    spi_write(0xff);
复制代码


3.发送cmd0cmd55acmd41,让卡初始化。这俺也不懂,网上搬过来的。



  1.     retry = 0;
  2.     do
  3.     {
  4.        //发送CMD0,让SD卡进入IDLE状态
  5.        r1 = sd_send_cmd(0, 0, 0x95);
  6.        retry++;
  7.     } while ((r1 != 0x01) && (retry < 200));

  8.     //发卡初始化指令CMD55+ACMD41
  9.     do
  10.     {
  11.        r1 = sd_send_cmd(55, 0, 0);
  12.        if (r1 != 0x01) {
  13.            uart_printf("cmd55 failed %x\n\r", r1);
  14.            return;
  15.        }
  16.        r1 = sd_send_cmd(41, 0x40000000, 0);
  17.        if (retry > 200) {
  18.            uart_printf("cmd41 failed %x\n\r", r1);
  19.            return;  //超时则返回r1状态
  20.        }
  21.     } while (r1 != 0);
复制代码

4.现在就要把spi时钟调到最快了。初始化的时候spi时钟是很慢的,但是传输的时候,当然越快越好。这里spi的频率已经是最快了,40M。手册上说最多25m的,但是这里调40m也没事,不知道是nokiasd卡质量好还是咋的。




  1.     // set high speed
  2.     SPI0BR  = 0x00;  // 80M / 2 = 40M
复制代码

作者: cfanfrank    时间: 2009-5-20 20:24
本帖最后由 cfanfrank 于 2009-5-20 20:30 编辑

5.读数据。Cmd17是读单块命令,一次读512字节(默认是512,如果你调了块大小,这里就可能不止512了)。

sd_send_cmd(17, 0x00, 0)就是说,命令sd卡读从地址0x00开始的512字节,第二个参数是地址,需要512字节对齐(如果你的是sdhc卡,传进去的是块的编号,编号1代表地址512,编号4代表地址2048。。。)。

接下来的sd_recv_data(buf, 512);就是说,接受字节流,把它们放到buf里。

还有一个命令是多块一起读的,有需要的话,查下手册自己写吧。
一块被格式化好的sd卡,上面一般是fat文件系统,所以buf[510]buf[511]里的值是0x55, 0xaa。这个是拿来测试的。




  1. byte sd_recv_data(byte *data, word len)
  2. {
  3.     static word retry;
  4.     static byte r1;

  5.     // 启动一次传输
  6.     SD_CS = 0;
  7.     //等待SD卡发回数据起始令牌xFE
  8.     retry = 0;
  9.     do
  10.     {
  11.        spi_read(r1);
  12.        retry++;
  13.        if(retry>2000)  //2000次等待后没有应答,退出报错
  14.        {
  15.            SD_CS = 1;
  16.            return 1;
  17.        }
  18.     } while (r1 != 0xFE);

  19.     //开始接收数据
  20.     while (len--) {
  21.        spi_read(*data);
  22.        data++;
  23.     }
  24.     //下面是个伪CRC(dummy CRC)
  25.     spi_read(r1);
  26.     spi_read(r1);

  27.     //传输结束
  28.     SD_CS = 1;
  29.     spi_write(0xFF);

  30.     return 0;
  31. }

  32.     // 测试读
  33.     r1 = sd_send_cmd(17, 0x00, 0);//读命令
  34.     if (r1 != 0x00) {
  35.        uart_printf("cmd17 failed %x\n\r", r1);
  36.        return;
  37.     }
  38.     r1 = sd_recv_data(buf, 512);
  39.     if(r1 != 0)   {
  40.        uart_printf("recv data failed %x\n\r", r1);
  41.        return;
  42.     }
  43.     uart_printf("%x %x\n\r", buf[510], buf[511]);
复制代码

作者: cfanfrank    时间: 2009-5-20 20:24
本帖最后由 cfanfrank 于 2009-5-20 20:31 编辑

6.写数据
写数据用的是批量写,也一定要用这个,不然你写完512字节又要发命令,很慢。那把块大小调大点行不行呢?我试过,我的sd卡是不行的,最大512,手册里也没说明最大多少。你可以自己试试,如果能调大,最好调大。



  1.     //发多块写入指令
  2.     r1 = sd_send_cmd(25, 0x00, 0x00);
  3.     if (r1 != 0x00) {
  4.        uart_printf("cmd25 failed %x\n\r", r1);
  5.        return;  //应答不正确,直接返回
  6.     }

  7.     //开始准备数据传输
  8.     SD_CS = 0;

  9.     //先放个空数据,等待SD卡准备好
  10.     spi_write(0xff);
  11.     spi_write(0xff);
复制代码


发送完命令以后,就可以写了。下面的代码是每次写512字节,你可以放到你的主循环里。



  1.            spi_write(0xFC);

  2.            //放一个sector的数据
  3.            i = 512;
  4.            while (i--)
  5.               spi_write(*ptr++);

  6.            //发个Byte的dummy CRC
  7.            spi_write(0xff);
  8.            spi_write(0xff);
  9.    
  10.            spi_read(r1);
  11.            if ((r1 & 0x0F) != 0x05) {
  12.               // 如果数据出错,死机..
  13.               PORTB = 0xff;
  14.               while (1);
  15.            }
复制代码

作者: cfanfrank    时间: 2009-5-20 20:24
本帖最后由 cfanfrank 于 2009-5-20 20:50 编辑

经测试,40mspi频率下,连续spi_write六次,大概是256个总线时钟,还是能接受的。

在执行算法的同时,写6*512B的数据,周期是40ms,摄像头周期是20ms
光执行算法,周期是20ms,跟摄像头一样。
所以这跟上海大学那份技术报告里说得一样,如果加上sd调试,就只能是40ms周期了。

这也有些不爽。我也想过用一块arm同时读取摄像头数据,存在ram里,但是那样成本高,又麻烦。
北京科技大学的技术报告提到用无线影音模块的方法,可行是可行,不过估计数据处理又够麻烦,毕竟是模拟传输。如果用spi接口无线模块,估计速度也上不去。

如果有谁有好的方法,不用另外一块mcu,能在20ms内完成6*512B数据的读写,希望兄弟都能贴出来共享下!

补充几点:

sd卡的里的数据怎么组织,可以比较随便,可以没有文件系统,可以省很多事的。

VC里,CreateFile可以直接打开盘符。路径名为“\\.\X”,“X”就是你想要的盘符了。mfc里的CFile也行。


  1. CFile fp;

  2. if (!fp.Open("\\\\.\\H:", CFile::modeRead))
  3.   return;
复制代码


s12跟x86平台存在“大端小端”的问题,8bit以上的字段,要转换。给个宏:
  1. #define be16_to_cpu(x) ((x) = (((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
复制代码



作者: 星空下的学生    时间: 2009-5-21 09:21
不错,虽然现在没有时间做。不过还是要谢谢楼主这么大方哦
作者: HCS12    时间: 2009-5-21 18:14
谢谢楼主奉献啊
作者: pengzhen_lin    时间: 2009-5-24 19:15
谢谢楼主奉献啊
作者: zdhly0401    时间: 2009-5-24 23:33
谢谢楼主奉献啊
作者: yjchen    时间: 2009-6-29 13:34
多谢LZ啊~~~~~~
作者: miaozaoyang    时间: 2009-6-29 20:16
不知道,楼主有没有 一些宏定义的 资料啊?
可否发一份能用的程序,谢谢!
作者: miaozaoyang    时间: 2009-8-5 17:27
谢谢楼主,很缺乏这东西。
作者: zhangq062336    时间: 2009-8-6 22:11
可谓是踏破铁靴无觅处,还是楼主比较大方,比上海大学有气度多了,谢了!!!!
作者: liuyiran    时间: 2009-8-7 22:52
首先电气连接上必须严格按照SD手册上说的去做,该3.3的3.3,该上拉的上拉,还必须解决信号完整性问题,SD卡选用高速卡,读写程序用汇编,并且可以忽略校验机制,我们车子5KB的图像数据是在4ms内存完的。还有就是程序中必须把SD卡存储的优先级设置最低,即使存储跳帧也不会影响正常程序的运行。
   建议没有一定时间和精力的队伍不要盲目去开发,因为SD卡的作用并没有想象的那么大,看上去眩点罢了,还会导致很多额外的问题。要做这套系统,把硬件,单片机存储软件,FAT协议,上位机全部搞定,每项都是庞大工程,得花多长时间?值得么。。。
作者: October    时间: 2009-8-19 22:17
谢谢LZ~
作者: vallis    时间: 2009-8-24 21:15
楼主你好:我再使用你的程序,遇到如下问题:
我在做SD卡的时候,能够正确的初始化,和读取里面的数据,但是不能写数据,在执行写函数以后,再也不能初始化和读取数据了,只有把sd卡的引脚全部断开(包括电源)才能重新初始化和读取,但是还是不能写数据。我的写函数如下:
unsigned char SD_WriteData(byte *Write_Buff,dword length)
{
   static byte r1;
   dword i;
   r1=SD_SendCMD(25,0x00,0x00); //发多块写入指令
   if(r1!=0x00)
   {
      putstr("CMD25 faild\r\n");
      return 0;
   }
   SD_CS=0;
   //等待SD卡准备好
   SPI_WriteByte(0xff);
   SPI_WriteByte(0xff);
   
   SPI_WriteByte(0xfc);
   for(i=0;i<512;i++)
   {
      SPI_WriteByte(*Write_Buff);
      Write_Buff++;
   }
  
   SPI_WriteByte(0xff);   
   SPI_WriteByte(0xff);   
      
   r1=SPI_ReadByte();

   if((r1&0x0f)!=0x05)
   {
       putstr("write data error\r\n");
       return 0 ;        //数据如果数据出错,死机。。。。。。
   }

   SD_CS=1;
   putstr("write data seccussful\r\n");
   return 1;
}
作者: vallis    时间: 2009-8-26 17:13
楼主有个地方是错的吧~~~害的我好惨哦

应该是spi_write(0xfe)  ////////////
#   spi_write(0xFC);
#

#            //放一个sector的数据
#            i = 512;
#            while (i--)
#               spi_write(*ptr++);
#

#            //发个Byte的dummy CRC
#            spi_write(0xff);
#            spi_write(0xff);
#   
#            spi_read(r1);
#            if ((r1 & 0x0F) != 0x05) {
#               // 如果数据出错,死机..
#               PORTB = 0xff;
#               while (1);
#            }
作者: 新兴MCU    时间: 2009-9-13 20:48
好东西~~~~~~~~~~~谢谢~~正想学的东西~~~
作者: chiusir    时间: 2009-9-19 09:28
这代码风格很熟悉
作者: 786892880    时间: 2009-9-19 22:01
强大。。。
作者: zxzxy1988    时间: 2009-10-10 11:06
顶楼主,呵呵!
作者: chihua    时间: 2009-12-7 21:53
感谢楼主
作者: xab1987    时间: 2009-12-10 17:40
提示: 作者被禁止或删除 内容自动屏蔽
作者: DEMOK    时间: 2010-1-24 00:01
楼主分析得很详细啊 学习了  最近正在鼓捣SD卡
作者: louis    时间: 2010-1-24 12:39
不错哦 !!!!
作者: 807569039    时间: 2010-1-24 13:02
谢谢楼主奉献啊

作者: qicai    时间: 2010-2-7 18:33
多谢了  安逸可以对SD卡研究咯
作者: chengyongji    时间: 2010-2-26 18:15
感谢楼主的资料!
作者: abfgrab    时间: 2010-2-28 16:19

作者: abfgrab    时间: 2010-2-28 16:19
但是我不懂
作者: abfgrab    时间: 2010-2-28 16:19
这个论坛
作者: abfgrab    时间: 2010-2-28 16:20
什么都限制
作者: abfgrab    时间: 2010-2-28 16:20
搞定
作者: abfgrab    时间: 2010-2-28 16:20
简直是
作者: yourchen    时间: 2010-3-2 20:55
回复 1# cfanfrank


    楼主有没有写FAT的程序呢?直接这样写SD,电脑无法识别的吧?还有对单片机有什么作用呢?
作者: lxh7792    时间: 2010-3-20 20:40
谢谢哈
作者: 时代还怪    时间: 2010-3-25 10:52
楼主,谢啦,我想做呢!
作者: lansedeyueliang    时间: 2010-3-26 09:16
谢谢楼主奉献啊
作者: zhuzhu0    时间: 2010-3-28 18:12
谢谢楼主奉献
作者: xixiangfeng0733    时间: 2010-4-4 15:20
谢谢你了!!
作者: 霜~哀伤    时间: 2010-4-4 17:00
还没到用SD的阶段,谢谢分享。
作者: pknew    时间: 2010-4-15 16:54
谢谢
作者: pknew    时间: 2010-4-15 16:54
谢谢
作者: huachou    时间: 2010-5-1 20:56
感谢楼主
作者: zyhqq    时间: 2010-5-30 16:52
谢谢楼主!
作者: 1160927    时间: 2010-6-13 19:15
对楼主表示无比的膜拜,
作者: qbh319    时间: 2010-7-4 17:26
很嫉妒你的40M~~
作者: yoyokeen    时间: 2010-8-13 22:56
多谢,多谢。
作者: wwei    时间: 2010-8-29 20:14
本帖最后由 wwei 于 2010-8-29 20:16 编辑

谢谢楼主分享,提个问题,为什么读卡器只要4个接口???菜鸟指教
作者: pika    时间: 2010-8-30 18:39
谢谢楼主奉献
很详细
作者: 梦的点滴    时间: 2010-10-10 20:52
好东西啊,谢谢楼主分享
作者: jiang1101    时间: 2010-11-2 15:24
顶!有时间一定要做做看!
作者: yijingjing    时间: 2010-11-5 20:06
xieixie,正研究呢,谢谢!!!!!!!!!!!!!!!!!!!!!
作者: sy373466062    时间: 2010-11-22 09:26
非常感谢
作者: wp1989    时间: 2010-12-4 14:55
谢谢
作者: JINLIANG    时间: 2010-12-8 19:52
xiexie
作者: GuySunYang    时间: 2010-12-13 10:38
很好的东西哦啊
作者: zhang54188    时间: 2011-1-3 04:58

作者: zhang54188    时间: 2011-1-3 04:58

作者: kakasky    时间: 2011-3-13 18:19
感谢楼主的分享!
作者: mengyaowuxiang    时间: 2011-4-2 16:39
好人啊
作者: wenziheni    时间: 2011-10-21 23:51
谢谢楼主奉献啊
作者: 清明    时间: 2011-11-12 20:58
kankan
作者: longhunlanxue    时间: 2011-11-20 15:53

作者: lihang29    时间: 2011-11-23 12:10
谢谢分享
作者: beandy    时间: 2011-12-4 20:47
楼主参考龙丘的吧?
作者: 逍遥锐锋    时间: 2012-1-2 13:52
厉害
作者: DOUBLE-L-    时间: 2012-5-5 10:21
正好需要,谢谢楼主了。
作者: DOUBLE-L-    时间: 2012-5-7 13:02
请问楼主,我们的pwm口都用作电机控制了,是买的s12上面自带的,没有多余的pwm可以控制怎么办?
作者: 我是谁2011    时间: 2012-9-3 21:56
楼主好人
作者: Move123456    时间: 2012-9-27 21:13
感谢楼主分享
作者: 二硫碘化钾    时间: 2013-4-2 17:57
谢谢 LZ
作者: 二硫碘化钾    时间: 2013-4-20 22:17
谢谢LZ
作者: 葱葱哥    时间: 2014-4-20 16:41
有没有电路啊
作者: ⊙Lin⊙    时间: 2014-4-24 11:01
楼主能整理一下吗?
作者: 李祖勇    时间: 2014-10-28 16:57

作者: @@@#@!    时间: 2014-10-29 07:12
zan

作者: 车神帅杰    时间: 2014-11-3 18:46
就是自己还不懂  特郁闷




欢迎光临 智能车制作 (http://111.231.132.190/) Powered by Discuz! X3.2