搜索
bottom↓
回复: 202

[原创]资源共享:开放我的mmc/sd操作原代码

[复制链接]

出0入0汤圆

发表于 2005-9-4 10:58:06 | 显示全部楼层 |阅读模式
经过一段时间的努力,搞定了mmc/sd卡mp3 player,经过测试,320kbps文件极其流畅:). 这个上面SD成功的人不少,但是始终不见有人open source,见于这种情况,我准备开放我的mmc.c&mmc.h代码给大家,也表示对ouravr做些贡献.希望大家在弄mmc/sd mp3时候少走弯路.希望大家喜欢:).



所有代码我都经通过了我的测试.我分别采用了software spi和hardware spi访问mmc/sd,软件spi速度很慢,我只能采用16mhz的时钟才能播放320kbps的文件:(. 硬件SPI速度极其快,速度有质的飞跃:)



下面是我对低层代码的一些测试:

My hardware:

CPU: ATnega162

Clock:8MHz

Data Source: Kingston 128MB High-Speed SD Card(white colour)



Test 1:

---------------------------------------------------

SPI:Software SPI

DATA block: 1MB

Time: 35s

Speed:about 28KB/s=224kbps



Test 2:

----------------------------------------------------

SPI:Hardware SPI

DATA block: 1MB

Time: 10s

Speed:about 100KB/s=800kbps. Very fast ^_^.



Test 3:

-----------------------------------------------------

The crystal of cpu has been changed!

Clock : 16MHz

SPI : Hardware SPI + software SPI(init mmc/sd)

DATA BLOCK: 1MB

Data Source : Kingston 128MB High-Speed SD

Time : 5.5S

Speed: about 200KB/S. Oh,my god,very very fast^_^!



Notice: Here I use software SPI to initialize mmc/sd,or I can't do it:(



先上传我的使用software spi操作mmc/sd代码给大家:)(硬件的稍后):

点击此处下载armok0167408.rar



说明:我没有画电子版本的sch,也没有时间画,当初就是在纸上画的:) 请仔细看mmc.h,看明白硬件连接.我先简单给个连接图:

   SD       M162 Port

----------------------------

1  CS    ---> PORTA.0

2 CMD/DI ---> PORTA.1

3 GND    ---> NC(接相应的3.3V电源地)

4 Vcc    ---> NC(接3.3V电源正)

5 CLK    ---> PORTA.4

6 GND    ---> NC(接相应的3.3V电源地)

7 DO     ---> PORTA.6

8 NC     ---> PORTA.7(MMC busy LED)

9 NC     ---- 未连接



注意:8脚连上一个1K的电阻和一个LED送到PORTA.7上去作为MMC_BUSY_LED.忙信号是低电平驱动的.

另外连接到SD卡要进行电平转换.如下:

   _________________ PORTA.0

  |

|-|

| | 1.2K

|_|

  |_________________CMD/DI(MMC/SD PIN)

  |

|-|

| |2.2k

|_|

  |

  |

  |_________________GND

          |

         ---

          -

另外SD的DATA OUT脚,也就是7脚DO不需要转换,直接连到CPU的PORTA.6.



编译环境cvavr.移植到GCC需要做些修改了:)



1. 在初始化时候要注意SPI速度,在初始化时候尽量降低SPI速度.我的卡(kingston 128MB)如果没有降低速度在发CMD0正常,发CMD1时候总出错!这个很重要一定要注意!!!! 在初始化成功后,尽可能提高SPI速度,我是将AVR的SPI速度提升到了极限,SPI2X也ENABLE.



2. 在操作mmc/sd之前,先发送80个脉冲给它.(/cs先禁止)



Good luck to all:)



















-----此内容被elefan于2005-09-04,10:59:26编辑过


-----此内容被elefan于2005-09-04,11:02:31编辑过

出0入0汤圆

发表于 2005-9-4 11:00:47 | 显示全部楼层
期待中

出0入0汤圆

发表于 2005-9-4 11:07:51 | 显示全部楼层
收藏先。。。
头像被屏蔽

出0入0汤圆

发表于 2005-9-4 11:12:20 | 显示全部楼层
谢谢共享!



给elefan的共享精神加200分!

出0入0汤圆

 楼主| 发表于 2005-9-4 11:25:41 | 显示全部楼层
谢谢armok:).写代码那几天天天熬到晚上1点. 是真的,花了我不少时间. 主要是MMC/SD操作很奇怪,初始化要用很低的SPI速度,害了我浪费了好几天时间,在这里再次提醒大家.咦,怎么加了200分才170呢? 怎么少了呢?

出0入0汤圆

 楼主| 发表于 2005-9-4 11:38:58 | 显示全部楼层
呵呵,是系统错误吧! 现在OK!

出10入120汤圆

发表于 2005-9-4 12:14:50 | 显示全部楼层
编程风格不错,是值得大家学习的程序。

出0入0汤圆

 楼主| 发表于 2005-9-4 12:27:54 | 显示全部楼层
程序包括基本操作部分外,还加了MMC_get_volume_info(void),调用能读出SD型号和容量:

eg: Product:SD512

    Total: 512MB

另外有很所实用的供参考的程序.例如在m8515中操作mmc/sd,不可能缓冲一个sector,因此利用MMC_Start_Read_Sector()就可以打开一个LBA地址的512字节,接下来就是clock all data out了,请参考程序:)

出0入0汤圆

发表于 2005-9-4 12:33:24 | 显示全部楼层
支持!有时间好好研究

出0入0汤圆

发表于 2005-9-4 20:21:26 | 显示全部楼层
不错。

楼主DIY MP3多久了,一般需要什么开发工具?能指点一下吗?

谢谢!

出0入0汤圆

发表于 2005-9-4 21:08:31 | 显示全部楼层
http://www.ulrichradig.de/site/atmel/avr_mmcsd/index.htm

出0入0汤圆

 楼主| 发表于 2005-9-4 23:10:43 | 显示全部楼层
To kinsey: 做MP3将近一年:) 做这个其实也不需要什么特别工具.就我来说:

1. 硬件:

  一块实验板,带STA013和CS4334,你也可以自己做和STA013和CS4334小板,然后与自己做的实验板子或者是站上马潮老师的实验板配合,接口就行了:)

2. 软件环境

  关于编程环境,可以按自己熟悉的环境来GCC,CVAVR,ICCAVR,IAR都行.关键是自己觉得好用就行,因为C的移植性很强,所以也不要刻意去找编译器.

3. 其他资料

  要找到好的参考资料,你不可能整天抱着那个datasheet去看.多看看别人怎么做,结合datasheet看,这样理解最快.

4. 最后就靠自己时间摸索能力,包括调试程序能力和硬件能力.出现问题要会迅速定位错误范围,不是瞎搞.那样你永远不知道在什么地方出错. 也就是说多动脑子比多动手要强的多.
-----此内容被elefan于2005-09-04,23:12:37编辑过

出0入0汤圆

发表于 2005-9-5 20:23:22 | 显示全部楼层
好东西,辛苦了。

出0入0汤圆

发表于 2005-9-5 21:51:17 | 显示全部楼层
哗,好东西,多谢共享

出0入0汤圆

发表于 2005-9-6 08:52:30 | 显示全部楼层
向elefan这种无私的精神致敬!什么时候MP3的测试整体出来啊!期待!

出0入0汤圆

发表于 2005-9-6 09:26:28 | 显示全部楼层
我正在测试楼主的程序,遇到一个问题,希望楼主不吝赐教,

我用ICC6.31A,在调用MMC端口初始化时,老是报错:

void MMC_Port_Init(void)

//****************************************************************************

{

   //Config ports

   MMC_Direction_REG.SPI_DI=0;          //Set Pin MMC_DI as Input      MMC_Direction_REG.SPI_Clock=1;       //Set Pin MMC_Clock as Output

   MMC_Direction_REG.SPI_DO=1;          //Set Pin MMC_DO as Output

   MMC_Direction_REG.MMC_Chip_Select=1; //Set Pin MMC_Chip_Select as Output

   //busy led port init

   MMC_Direction_REG.SPI_BUSY=1;        //Set spi busy led port output

   MMC_BUSY_LED=1;                      //busy led off

   

   MMC_CS_PIN=1;                        //Set MMC_Chip_Select to High,MMC/SD Invalid.

}

报错内容如下:

!E mmc.c(25): field name expected

!W mmc.c(25):[warning] reference to `volatile unsigned char' elided

!W mmc.c(25):[warning] expression with no effect elided

!E mmc.c(25): syntax error; found `6' expecting `;'

!E mmc.c(25): lvalue required

!E mmc.c(26): field name expected

!W mmc.c(26):[warning] reference to `volatile unsigned char' elided

!W mmc.c(26):[warning] expression with no effect elided

!E mmc.c(26): too many errors

Done: there are error(s). Exit code: 1

出0入0汤圆

发表于 2005-9-6 09:28:09 | 显示全部楼层
好像是头文件中结构体出错,后来我又加了IO162V.H文件,可是依旧不能通过

出0入0汤圆

 楼主| 发表于 2005-9-6 10:07:51 | 显示全部楼层
To ljd166:

ICCAVR好象没有CVAVR中方便的位操作功能.例如:



//PORTB init

DDRB.0=1; //output mode

PORTB.0=1; //high status



你需要做些修改以适应ICCAVR编译器,具体我不是很熟悉,请仔细参考其user manual.

像程序中:MMC_Direction_REG.SPI_DI=0;          //Set Pin MMC_DI as Input

我在mmc.h中做了详细描述. 可以进行'.'操作,就是位操作.

出0入0汤圆

发表于 2005-9-6 10:32:43 | 显示全部楼层
谢谢楼主,看来我可能需要重新编这段程序,不过楼主的这种风格我很喜欢,所以才保留下来,没有修改。

出0入0汤圆

 楼主| 发表于 2005-9-6 10:35:01 | 显示全部楼层
To  ljd166 :

谢谢!你很喜欢,就可以在mmc.h中做些define就行了,可以继续使用:) Good luck to you:)

出0入0汤圆

发表于 2005-9-8 21:41:56 | 显示全部楼层
借问楼主:

怎么没有使用硬件SPI接口,而是用软件模拟的.

出0入0汤圆

发表于 2005-9-27 11:16:18 | 显示全部楼层
问一下楼主,你用的那个软SPI中间的Init_Flag那个量是干什么用的啊?

我也在做MP3,现在有个疑问,就是SPI口什么时候可以读取外部的数据,因为它没有向I2C那样读到了数据就把相应的标志置位啊?

出0入0汤圆

 楼主| 发表于 2005-9-27 14:12:46 | 显示全部楼层
To myhk007:

Init flag是用来降低SPI速度的,我使用了SPI的最低速度但是还是初始化失败了,无赖,先换成软件SPI初始化SD,成功后,然后把AVR的硬件SPI速度提升到极限.请参考下面的代码:

//****************************************************************************

//Routine for Init MMC/SD card(SPI-MODE)

unsigned char MMC_Init(void)

//****************************************************************************

{  

   unsigned char retry,temp;

   unsigned char i;

   unsigned char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};

   

   //MMC_Port_Init(); //Init SPI port  



   for(i=0;i<200;i++) //Wait MMC/SD ready...

   {

      #asm("nop");

   }

   

   //Active SPI bus at low speed

   //SPCR=0x53; //SPI Master,MSB First

   //SPSR=0x00; //double speed disable,Fsck=Fosc/128

   

   SPCR=0x00; //Disable SPI bus

   Init_Flag=1; //Set Init flag



   for (i=0;i<0x0f;i++)

   {

      Write_Byte_MMC(0xff); //send 74 clock at least!!!

   }

       

   //Send Command CMD0 to MMC/SD Card

   retry=0;

   do

   { //retry 200 times to send CMD0 command

     temp=Write_Command_MMC(CMD);

     retry++;

     if(retry==200)

     { //time out

       return(INIT_CMD0_ERROR);//CMD0 Error!

     }

   }

   while(temp!=1);

   

   //Send Command CMD1 to MMC/SD-Card

   CMD[0] = 0x41; //Command 1

   CMD[5] = 0xFF;

   retry=0;

   do

   { //retry 100 times to send CMD1 command

     temp=Write_Command_MMC(CMD);

     retry++;

     if(retry==100)

     { //time out

       return(INIT_CMD1_ERROR);//CMD1 Error!

     }

   }

   while(temp!=0);

   

   Init_Flag=0; //Clear the flag and use hardware SPI port

   //Active High-speed SPI mode(Fsck=Fosc/2)

   SPCR=0x50;

   SPSR=0x01;

   

   MMC_Disable();  //set MMC_Chip_Select to high

   return(0); //All commands have been taken.

}



//****************************************************************************

//Routine for reading a byte from MMC/SD-Card

unsigned char Read_Byte_MMC(void)

//****************************************************************************

{

  unsigned char i,temp=0;



  MMC_BUSY_LED=0;

  if(Init_Flag)

  { //Software SPI

    for (i=0; i<8; i++) //MSB First

    {

      SPI_SCK_PIN=0; //Clock Impuls (Low)

      MMC_clk_delay();

      temp = (temp << 1) + SPI_DI_PIN; //read mmc data out pin

      SPI_SCK_PIN=1; //set Clock Impuls High

      MMC_clk_delay();       

    }

    MMC_BUSY_LED=1;

    return(temp);

  }

  else

  { //Hardware SPI   

    SPDR=0xFF;

    while(!(SPSR & 0x80)){};

    MMC_BUSY_LED=1;

    return (SPDR);   

  }

}

你看看我代码就知道,我知道我为什么要这样做(之前硬件初始化程序我屏蔽了).

出0入0汤圆

 楼主| 发表于 2005-9-27 14:20:18 | 显示全部楼层
读数据先送0XFF,实际上上发clk脉冲.你应该知道SPI是同步的,发数据时候,SPI也在接收数据,所以数据0XFF被送出后,在SPDR中就得到了要接收的数据.请参考上面的代码:)

出0入0汤圆

发表于 2005-9-28 10:38:03 | 显示全部楼层
多谢ELEFAN!今天就准备上电调试了,估计会遇到不少问题啊.

出0入0汤圆

发表于 2005-12-4 14:14:13 | 显示全部楼层
是用我喜欢的CVAVR啊。

强烈支持elefan的无私奉献精神。

可惜最近没空啊。

谢谢啦

出0入0汤圆

发表于 2005-12-9 15:19:28 | 显示全部楼层
谢谢共享,我在21ic上的AVR 论坛还找不到关于AVR 开发技术上的那么详细的讲解.

也谢谢站主.

出0入0汤圆

发表于 2006-1-7 11:19:58 | 显示全部楼层
elefan 你的程序可能不是最优化的 这个可能是和你的电路有关系 我在网上查了不少的SD读写程序都没有你那么复杂 你可以试着把你的SPI接口与SD卡的下偏电阻去掉 初始化就不会那么困难了 其实它们之间是可以直接连接的 但是为了防止出现损坏SD卡 建议加上隔离电阻10~500欧之间 其他的没有什么区别

下面是我改写后的代码

点击此处下载armok0196526.rar



i = 3;

while(i--)

{

    temp = MMC_Init();

    if(temp == TRUE)break;

    OSTimeDly(10);

}

if(i == 0)err_out(temp);



上面的代码是初始化SD卡 一般读写的时候和上面的代码一样



以上代码都是在M128 16M测试通过的

出0入0汤圆

 楼主| 发表于 2006-1-7 11:56:58 | 显示全部楼层
to hygbeyond:

谢谢你的意见,目前我的代码速度在16MHZ下测试为200KB/S.按照SPI速度:8MBPS计算,SD卡应该具有1MB/S字节传输速度,代码速度还不够理想.应该跟硬件有关(代码会在命令发送失败后会自动retry,估计这个有点耽误速度)我试着优化下硬件.

出0入0汤圆

发表于 2006-1-8 13:48:00 | 显示全部楼层
avr-libc中就有源码.

出0入0汤圆

发表于 2006-2-24 11:02:47 | 显示全部楼层
elefan 代码中初始化到SPI模式,少了个MMC_ENABLE.

出0入0汤圆

发表于 2006-2-24 11:29:16 | 显示全部楼层
初始化时速度慢, 我估计是sd和mmc的兼容性的原因, sd卡不知道设备是否支持高速, 所以用低速来初始化, 初始化完成后确定可以支持高速, 才进入到高速模式

我有一个闲置的32mSD, 拿来研究研究

谢了...

出0入0汤圆

发表于 2006-2-24 14:53:46 | 显示全部楼层
我用的也是32MB,因为刚开始不太明白SD的扇区操作,所以把SD的引导扇区给写坏,结果任何设备都无法对其格式化(包括DC,PC),最后没有办法,自己硬着头皮把引导扇区的开头的那几十个数据,一个一个地输进去,才救活了我的SD卡。

出0入0汤圆

 楼主| 发表于 2006-2-24 19:37:50 | 显示全部楼层
to ljd166 and all:

为了保护你的SD卡不被程序误写引导和FAT扇区,请不要乱call mmc_write_sector()函数,初学者多call mmc_read_sector()就可以了,搞坏了0扇区和FAT扇区就很麻烦了.确实要写,确保你所写的扇区在DATA区域中,并且SD中没有重要文件.



不懂FAT多看看sd的说明书,那里说的比较详细,资料就在本论坛.

出0入0汤圆

发表于 2006-2-26 22:35:24 | 显示全部楼层
唉,刚开始像无头苍蝇一样,胡乱试,结果出了错,不过还好我又把它给修好了。

谢谢楼主鞭笞,下次一定不敢随便乱试了:)

出0入0汤圆

发表于 2006-2-28 14:30:48 | 显示全部楼层
请教楼主一个问题,为什么我的SD卡在读写的时候,地址会有19的偏移,包括读和写

出0入0汤圆

发表于 2006-4-25 16:33:39 | 显示全部楼层
感谢,但我有一个地方看不懂,就是

uint8 MMC_write_sector(uint32 addr,uint8 *Buffer)和

uint8 MMC_read_sector(uint32 addr,uint8 *Buffer)函数,其中的:

temp = Write_Command_MMC(MMC_READ_BLOCK,addr<<9);看样子是传送块地址吧,块地址应该是在addr的BIT10以后的高字节把,应该

temp = Write_Command_MMC(MMC_READ_BLOCK,addr>>9);这样才能得到高位块地址吧?

希望高人能讲讲这是咋回事,谢谢.

出0入0汤圆

 楼主| 发表于 2006-4-26 00:15:44 | 显示全部楼层
to  ljd166 : 能详细描述下吗?



to freny:



address<<9 意思是说address * 512.



SD/MMC卡是用字节定位来寻址. 不是常见的logic block address, 这里实际是把LBA地址转换为字节地址.

出0入0汤圆

发表于 2006-4-26 08:07:45 | 显示全部楼层
好,谢谢!

出0入0汤圆

发表于 2006-4-26 10:40:48 | 显示全部楼层
非常感谢elefan!

出0入0汤圆

发表于 2006-8-10 08:59:59 | 显示全部楼层
谢谢各位工程师!希望能看到硬件电路,便于新手学习啊!

出0入0汤圆

发表于 2006-8-21 14:42:12 | 显示全部楼层
硬件是利用SPI总线连接的,不会很复杂。关键是软件的调试部分。

出0入0汤圆

发表于 2006-8-29 17:55:46 | 显示全部楼层
这是我在ouravr的处女帖,跟楼主很有缘啊,以前在21ic和dianyuan网,我都是用elecfans注册的用户名,今次在ouravr注册elecfans可以顺便借楼主威名的光了呵呵。今年暑假我尝试用89s52模拟spi时序驱动sd卡,参考arm的程序自己编写了一小段,也制作了硬件,上电时序是通过了,其后的指定block长度的指令总是的不到response,至今没能解决,回学校之后,开始学习avr,打算借鉴楼主的程序,等测试通过了再发贴报告。谢谢elecfan先!

出0入0汤圆

发表于 2006-9-12 13:15:11 | 显示全部楼层
请教:

unsigned char MMC_read_sector(unsigned long addr,unsigned char *Buffer)

{       

   //Command 16 is reading Blocks from MMC/SD-Card

   unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};

   unsigned char temp;

   

   asm("cli"); //clear all interrupt.

   //Address conversation(logic block address-->byte address)  

   addr = addr << 9; //addr = addr * 512



   CMD[1] = ((addr & 0xFF000000) >>24 );

   CMD[2] = ((addr & 0x00FF0000) >>16 );

   CMD[3] = ((addr & 0x0000FF00) >>8 );



   temp=MMC_Read_Block(CMD,Buffer,512);

   

   return(temp);

}

其中的

unsigned long addr

是指图中哪个,我要读的是123。TXT文件,不用FAT16系统的









-----此内容被ahui于2006-09-12,13:17:30编辑过


-----此内容被ahui于2006-09-12,13:18:49编辑过

出0入0汤圆

发表于 2006-9-12 13:28:50 | 显示全部楼层
我的一张MMC卡在NOKIA手机上被锁了,是不是可以这样的程序对它的扇区进行格式化?

(用MMC卡的格式化工具不行)

出0入0汤圆

发表于 2006-9-12 23:35:53 | 显示全部楼层
那位大虾有没有用CVAVR编译器写的SD/MMC的读写程序啊?论坛上都是ICC和GCC的。

出0入0汤圆

发表于 2006-9-12 23:49:12 | 显示全部楼层
to:elefan

你上面共享出来的SD/MMC程序好像就是CVAVR的吧!刚刚上面的我发的贴子还以为是ICC,GCC写的了,谢谢了!

出0入0汤圆

发表于 2006-10-3 11:48:52 | 显示全部楼层
请教一下,你用的那个查看分区的还一些详细资料的软件的名字叫什么??谢谢!

出0入0汤圆

 楼主| 发表于 2006-10-3 22:23:42 | 显示全部楼层
编辑工具: UltraEdit 功能很强大,你试着用下吧!

出0入0汤圆

 楼主| 发表于 2006-10-3 22:25:14 | 显示全部楼层
to whimsy:



我没有写格式化函数,需要自己写一个,不要乱格式化.

出0入0汤圆

发表于 2006-10-28 13:45:08 | 显示全部楼层
接【43楼】



上次OK后,忘记接着发了,是上面的757

出0入0汤圆

发表于 2006-10-28 18:07:39 | 显示全部楼层
上面那个直接读磁盘数据的软件应该是winHex吧

出0入0汤圆

发表于 2006-11-7 11:16:28 | 显示全部楼层
怎么我用MMC_get_volume_info()来读一个32M的MMC卡 读出来的结果是这样的

Product:32***

Total: MB

请问哪位大虾也遇到我这种情况????希望高手指点。谢了

出0入0汤圆

发表于 2006-11-7 11:49:17 | 显示全部楼层
收藏一下,谢谢楼主共享

出0入0汤圆

发表于 2006-11-7 13:54:57 | 显示全部楼层
怎么我用MMC_get_volume_info()来读一个32M的MMC卡 读出来的结果是这样的

Product:32***

Total: MB

请问哪位大虾也遇到我这种情况????希望高手指点。谢了 .怎么没有人HELP ME !

出0入0汤圆

发表于 2006-11-8 17:29:32 | 显示全部楼层
仔细研究中...

出0入0汤圆

发表于 2006-11-8 17:37:01 | 显示全部楼层
收下

出0入0汤圆

发表于 2006-11-12 12:13:23 | 显示全部楼层
顶一下楼主的好贴,我正好要用。

刚开始接触SD卡,向楼主和大家请教一些基本的问题:我采用MEGA16单片机,因AD采样的数据很多,我打算将采样的数据保存在SD卡中,数据采集完后用读卡器将数据读到电脑上分析,不知道这样用是不是要了解SD卡的文件系统规范?希望大家指教。
-----此内容被xiaotanlan于2006-11-12,12:15:30编辑过

出0入0汤圆

 楼主| 发表于 2006-11-12 23:07:55 | 显示全部楼层
to gl516: 可能是你的显示函数有问题,你再看看.



to 楼上: 需要了解FAT系统基本结构,你所有的数据读写要在FAT下进行

出0入0汤圆

 楼主| 发表于 2006-11-12 23:14:19 | 显示全部楼层
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=198102&bbs_page_no=1&bbs_id=1000



这个FAT例子很好.

出0入0汤圆

发表于 2006-11-15 22:07:00 | 显示全部楼层
非常感谢楼主的热心!

画了一个简单的MEGA16L连SD卡的电路图,点击此处打开armok01135376.pdf

我打算程序先这样写以验证写入SD卡中的数据是否正确:连续写数据00H~FFH到SD卡中,并以文本文件(*.txt)的方式保存,不知一个文件能容纳多少次00H~FFH。然后用读卡器将写到SD卡中的数据读到电脑上显示,看是否为我写入的数据。我想应该了解FAT16文件系统原理就可以了吧,FAT32可以暂时不去管吧.另外楼主的程序读写SD卡是不在任何文件系统下进行的,楼主是否只是将SD卡当做普通EEPROM来用,这样的话读卡器是没办法读出里面的数据吧?另外,MEGA162也有SPI,楼主怎么没用硬件SPI,硬件SPI速度应该快吧?
-----此内容被xiaotanlan于2006-11-15,22:07:32编辑过

出0入0汤圆

发表于 2006-11-24 14:24:11 | 显示全部楼层
我把程序修改,以便ICC平台编译,可是没有delay_us(8)的定义,我不熟悉CVAVR,不知道这个delay_us(8)是不是延迟8us的意思?

出0入0汤圆

 楼主| 发表于 2006-11-25 14:42:17 | 显示全部楼层
to  xiaotanlan: 对,上面的程序是最底层操作,如果自己不想写USB驱动,直接使用mass storage方式查看,确实需要使用FAT系统。按照FAT系统写入数据,否则,电脑不认的。



开始为了调试方便,使用了软SPI,个人习惯罢了,不必深究。



后来在初始化的时候使用硬件SPI出问题,换了软SPI初始化,完成后,切换到硬件SPI方式读写数据。现在论坛上很多网友都调出了硬件SPI,我就没有放硬件SPI的代码,只需要稍微修改就可以了。



to knightdead: delay_us(8)是延迟8us,这个函数是cv系统库函数,你可以自己写个函数代替。

出0入0汤圆

发表于 2006-11-29 17:01:59 | 显示全部楼层
谢谢你的解答.

根据你共享的源码,我已经能够读取CSD ,CID .

调了我三天,都是硬件电路出的问题.

高兴!

出0入0汤圆

发表于 2006-12-8 21:57:42 | 显示全部楼层
非常感谢elefan,

通过参考楼主的程序我已经读出SD卡的0扇区,和用winhex读出的一样:

EB 58 90 4D 53 44 4F 53 35 2E 30 00 02 02 22 00



02 00 00 00 00 F8 00 00 3F 00 FF 00 00 00 00 00



00 CE 03 00 C7 03 00 00 00 00 00 00 02 00 00 00



01 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00



00 00 29 DB 5F 39 B8 4E 4F 20 4E 41 4D 45 20 20



20 20 46 41 54 33 32 20 20 20 33 C9 8E D1 BC F4



7B 8E C1 8E D9 BD 00 7C 88 4E 02 8A 56 40 B4 08



CD 13 73 05 B9 FF FF 8A F1 66 0F B6 C6 40 66 0F



B6 D1 80 E2 3F F7 E2 86 CD C0 ED 06 41 66 0F B7



C9 66 F7 E1 66 89 46 F8 83 7E 16 00 75 38 83 7E



2A 00 77 32 66 8B 46 1C 66 83 C0 0C BB 00 80 B9



01 00 E8 2B 00 E9 48 03 A0 FA 7D B4 7D 8B F0 AC



84 C0 74 17 3C FF 74 09 B4 0E BB 07 00 CD 10 EB



EE A0 FB 7D EB E5 A0 F9 7D EB E0 98 CD 16 CD 19



66 60 66 3B 46 F8 0F 82 4A 00 66 6A 00 66 50 06



53 66 68 10 00 01 00 80 7E 02 00 0F 85 20 00 B4



41 BB AA 55 8A 56 40 CD 13 0F 82 1C 00 81 FB 55



AA 0F 85 14 00 F6 C1 01 0F 84 0D 00 FE 46 02 B4



42 8A 56 40 8B F4 CD 13 B0 F9 66 58 66 58 66 58



66 58 EB 2A 66 33 D2 66 0F B7 4E 18 66 F7 F1 FE



C2 8A CA 66 8B D0 66 C1 EA 10 F7 76 1A 86 D6 8A



56 40 8A E8 C0 E4 06 0A CC B8 01 02 CD 13 66 61



0F 82 54 FF 81 C3 00 02 66 40 49 0F 85 71 FF C3



4E 54 4C 44 52 20 20 20 20 20 20 00 00 00 00 00



00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00



00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00



00 00 00 00 00 00 00 00 00 00 00 00 0D 0A 52 65



6D 6F 76 65 20 64 69 73 6B 73 20 6F 72 20 6F 74



68 65 72 20 6D 65 64 69 61 2E FF 0D 0A 44 69 73



6B 20 65 72 72 6F 72 FF 0D 0A 50 72 65 73 73 20



61 6E 79 20 6B 65 79 20 74 6F 20 72 65 73 74 61



72 74 0D 0A 00 00 00 00 00 AC CB D8 00 00 55 AA

出0入0汤圆

发表于 2006-12-14 16:53:45 | 显示全部楼层
楼主,你好。



  我把MMC.C和MMC.H两个文件直接加到一个新工程中,怎么总编译不过。(我用的是codevision环境,你的两个文件什么都没有更改。)



   产生的错误非常多。- 这个不是主文件吧?怎么没有发现MAIN函数。

出0入0汤圆

发表于 2007-3-22 14:33:46 | 显示全部楼层
我在调试中发现不同的sd卡的逻辑扇区0和物力扇区的对应关系不一样吗,我在16M的卡上READ_BLOCK(0+0X39)可以读到BPB,但在128M的MINI SD看上相同为制读出的数据全部为0,它的BPB的数据在READ_BLOCK(0+77)才可以读出,我真的搞不清楚,从那里可以看到这个偏移量呀?请给我一下指导,谢谢

出0入0汤圆

发表于 2007-3-22 16:01:23 | 显示全部楼层
0扇区是MBR,记录了分区表,读BPB应该在第一个分区的“0扇区"

出0入0汤圆

发表于 2007-3-22 16:17:35 | 显示全部楼层
0扇区是MBR,记录了分区表,读BPB应该在第一个分区的“0扇区"

出0入0汤圆

发表于 2007-3-22 23:04:18 | 显示全部楼层
多谢楼主!我下来学习.

出0入0汤圆

发表于 2007-3-25 01:23:08 | 显示全部楼层
"多动脑子比多动手要强的多"



顶这句话

出0入0汤圆

发表于 2007-3-26 10:06:05 | 显示全部楼层
终于找到了。

各位,偶是新手。想请教几个问题。

折磨我好几个星期了。

先写过!



我第一开发SD FAT16驱动。

是一个电梯刷卡系统的一部分。



现在对SD卡硬件方面简直是无从入手;

目前,已经拿到MCU和SD卡了。

代码也参考了以上各位的。

但是我不知道应该如何开始着手。



以下是问题:

客户告诉我针脚如下:

CS      p4_7

DI      p4_6

CLK     p4_5

DO      p7_0



p4是一个Byte的地址,p4_7是这个Byte的最高位,p7也一样。

另外pd4是一个direct地址,pd7也一样。



是否还缺少什么呢??

看了一些例程,上面几乎没有写 针脚的一些信息。



小弟是第一次接触这个,帮帮我呀。

谢谢了。



#pragma ADDRESS     p4_addr         03e8h       /* Port P4 register */

#pragma ADDRESS     pd4_addr        03eah       /* Port P4 direction register */

direction 是干嘛用的??



/*------------------------------------------------------

    Port P4 register

------------------------------------------------------*/

union byte_def p4_addr;

#define     p4      p4_addr.byte



#define     p4_0        p4_addr.b.b0        /* Port P4  bit0 */

#define     p4_1        p4_addr.b.b1        /* Port P4  bit1 */

#define     p4_2        p4_addr.b.b2        /* Port P4  bit2 */

#define     p4_3        p4_addr.b.b3        /* Port P4  bit3 */

#define     p4_4        p4_addr.b.b4        /* Port P4  bit4 */

#define     p4_5        p4_addr.b.b5        /* Port P4  bit5 */

#define     p4_6        p4_addr.b.b6        /* Port P4  bit6 */

#define     p4_7        p4_addr.b.b7        /* Port P4  bit7 */



/*------------------------------------------------------

    Port P4 direction register

------------------------------------------------------*/

union byte_def pd4_addr;

#define     pd4     pd4_addr.byte



#define     pd4_0       pd4_addr.b.b0       /* P4 direction register  bit0 */

#define     pd4_1       pd4_addr.b.b1       /* P4 direction register  bit1 */

#define     pd4_2       pd4_addr.b.b2       /* P4 direction register  bit2 */

#define     pd4_3       pd4_addr.b.b3       /* P4 direction register  bit3 */

#define     pd4_4       pd4_addr.b.b4       /* P4 direction register  bit4 */

#define     pd4_5       pd4_addr.b.b5       /* P4 direction register  bit5 */

#define     pd4_6       pd4_addr.b.b6       /* P4 direction register  bit6 */

#define     pd4_7       pd4_addr.b.b7       /* P4 direction register  bit7 */

                  

-----此内容被sd01101230于2007-03-26,10:18:27编辑过


-----此内容被sd01101230于2007-03-26,10:47:23编辑过

出0入0汤圆

发表于 2007-3-26 22:19:41 | 显示全部楼层
有人吗??

上面的PORTB是什么类型的针脚阿?

DDR又是什么针脚?

DATAPIN是???

反正那些阵脚是什么意思呀?



赐教阿。

能否发个给我啊。。。kakueiken@126.com

万分感谢。

出0入0汤圆

发表于 2007-3-27 18:52:29 | 显示全部楼层
完了 用 瑞萨的 M16C/6N4

不知道如何初始化SPI模式。

找了2天也没找到。



我以前从未接触过此类东西。有知道吗?

出0入0汤圆

发表于 2007-4-11 14:59:37 | 显示全部楼层
谢谢楼主的开源,,,

出0入0汤圆

发表于 2007-5-21 13:05:21 | 显示全部楼层
请教:



    为什么在这里出现死循环:



    uint8 MMC_read_sector(uint32 addr,uint8 *Buffer)

//****************************************************************************

{

        uint8 temp;

        uint16 i;

        

        SPI_TransferByte(0xff);

        

        MMC_Enable();

        

        temp = Write_Command_MMC(MMC_READ_BLOCK,addr<<9);

        

        if(temp != 0x00)

        {

                MMC_Disable();

                return(READ_BLOCK_ERROR);

        }

        

        while(SPI_TransferByte(0xff) != 0xfe);//就这里

        

        for(i=0;i<512;i++)

        {

                *Buffer++ = SPI_TransferByte(0xff);

        }

        

        SPI_TransferByte(0xff);

        SPI_TransferByte(0xff);

        

        MMC_Disable();

        return(TRUE);

}

出0入0汤圆

发表于 2007-5-21 13:05:27 | 显示全部楼层
请教:



    为什么在这里出现死循环:



    uint8 MMC_read_sector(uint32 addr,uint8 *Buffer)

//****************************************************************************

{

        uint8 temp;

        uint16 i;

        

        SPI_TransferByte(0xff);

        

        MMC_Enable();

        

        temp = Write_Command_MMC(MMC_READ_BLOCK,addr<<9);

        

        if(temp != 0x00)

        {

                MMC_Disable();

                return(READ_BLOCK_ERROR);

        }

        

        while(SPI_TransferByte(0xff) != 0xfe);//就这里

        

        for(i=0;i<512;i++)

        {

                *Buffer++ = SPI_TransferByte(0xff);

        }

        

        SPI_TransferByte(0xff);

        SPI_TransferByte(0xff);

        

        MMC_Disable();

        return(TRUE);

}

出0入0汤圆

发表于 2007-5-21 13:05:55 | 显示全部楼层
请教:



    为什么在这里出现死循环:



    uint8 MMC_read_sector(uint32 addr,uint8 *Buffer)

//****************************************************************************

{

        uint8 temp;

        uint16 i;

        

        SPI_TransferByte(0xff);

        

        MMC_Enable();

        

        temp = Write_Command_MMC(MMC_READ_BLOCK,addr<<9);

        

        if(temp != 0x00)

        {

                MMC_Disable();

                return(READ_BLOCK_ERROR);

        }

        

        while(SPI_TransferByte(0xff) != 0xfe);//就这里

        

        for(i=0;i<512;i++)

        {

                *Buffer++ = SPI_TransferByte(0xff);

        }

        

        SPI_TransferByte(0xff);

        SPI_TransferByte(0xff);

        

        MMC_Disable();

        return(TRUE);

}

出0入0汤圆

发表于 2007-5-26 13:17:49 | 显示全部楼层
楼主你好,不知道你还会不会回来这里逛逛,我现在在尝试用MEGA16来读写SD卡,但对你的程序有些不明白的地方,首先,您为什么要像下面进行电平转换?其次SD读写数据的扇区地址从哪里开始呢?我接触单片机只有一个多月的时间,是个很菜的菜鸟,呵~望不吝赐教...不胜感激....

  _________________ PORTA.0

  |

|-|

| | 1.2K

|_|

  |_________________CMD/DI(MMC/SD PIN)

  |

|-|

| |2.2k

|_|

  |

  |

  |_________________GND

          |

         ---

          -

出0入0汤圆

发表于 2007-5-26 14:37:03 | 显示全部楼层
楼主你好,不知道你还会不会回来这里逛逛,我现在在尝试用MEGA16来读写SD卡,但对你的程序有些不明白的地方,首先,您为什么要像下面进行电平转换?其次SD读写数据的扇区地址从哪里开始呢?我接触单片机只有一个多月的时间,是个很菜的菜鸟,呵~望不吝赐教...不胜感激....

  _________________ PORTA.0

  |

|-|

| | 1.2K

|_|

  |_________________CMD/DI(MMC/SD PIN)

  |

|-|

| |2.2k

|_|

  |

  |

  |_________________GND

          |

         ---

          -

出0入0汤圆

 楼主| 发表于 2007-5-26 14:39:53 | 显示全部楼层
上面整个图是做TTL逻辑与CMOS逻辑转换,SD卡数据扇区需要看FAT,格式化成不同的FAT系统,数据扇区就不一样。

出0入0汤圆

 楼主| 发表于 2007-5-26 14:44:43 | 显示全部楼层
to flyhemcu :



上面的只是代码,需要你自己去建立工程,谢谢!



to zergl :物理扇区和逻辑扇区是不一样的,我们做底层最好看物理扇区,而非逻辑



to sd01101230 :你好像在51上移植,这个我没有试过,应该没有问题的。



to st_hb:我还没有遇到过死循环。

出0入0汤圆

发表于 2007-5-31 23:43:42 | 显示全部楼层
楼主真好人,谢谢,我现在没有接那个CMOS转换电路了,直接用3.3V的电压来供电,我现在用楼主给的代码来初始化SD卡(软件SPI模式)可以通过,初始化后我改成进入硬件SPI模式来读写数据,但没有反应,估计是程序有点问题吧,现在还在研究,发现单片机有点好玩了,呵,还是谢谢楼主...

出0入0汤圆

发表于 2007-7-14 14:34:15 | 显示全部楼层
有没有SD模式(4线模式)的初始化?请大虾指点?

出0入0汤圆

发表于 2007-7-17 21:32:25 | 显示全部楼层
elefan:

    你好,我看完SD卡的数据手册和参考网站里的一些sd卡原程序,因为我的编译系统是CVAVR,所以我用你的程序来初始化我的mmc卡,按照你的方法连接电路,不过我是按照硬件SPI的端口连接的(实际上还是软件SPI),以便以后用硬件SPI,在运行过程,我发觉CM0都写不进去,恳请大家帮帮忙,看是否程序问题。



* 编译软件:CodeVision AVR C 版本:1.24.48d 以上

* MCU     : Atmega32-16PU    晶振: 7.37286MHz

**********************************************************************/

#include <mega32.h>

#include <delay.h>          //延时函数的头文件   



#define uint8   unsigned char

#define int8    signed char

#define uint16  unsigned int

#define int16   signed int

#define uint32  unsigned long

#define int32   signed long



/*----------------------MCU and MMC pins define------------------------*/  

//SPI pins define

#define MMC_Write                    PORTB        //SPI port register

#define MMC_Read                    PINB    //Data PIN

#define MMC_Direction_REG        DDRB    //Direction register



#define SPI_DI                        6        //-->MMC_DO_PIN

#define SPI_DO                        5        //-->MMC_DI_PIN

#define SPI_Clock                7        //-->MMC_CLK_PIN

#define MMC_Chip_Select        4        //-->MMC_CS_PIN



#define MMC_DO_PIN      MMC_Read.SPI_DI

#define MMC_DI_PIN      MMC_Write.SPI_DO

#define MMC_CLK_PIN     MMC_Write.SPI_Clock

#define MMC_CS_PIN      MMC_Write.MMC_Chip_Select      



//LED pins define

#define CMD_LED                    PORTA   //LED LIGHT

#define CMD_LED_Direction          DDRA    //Direction register

   

#define CMD0_OK         0   //CMD 0 complete light

#define CMD1_OK         1   //CMD 1 complete light

#define CMD17_OK        2   //CMD 17 complete light

#define CMD24_OK        3   //CMD 24 complete light

#define SPI_BUSY        7   //busy led

                                                   

#define CMD0_OK_LED     CMD_LED.CMD0_OK

#define CMD1_OK_LED     CMD_LED.CMD1_OK

#define CMD17_OK_LED    CMD_LED.CMD17_OK

#define CMD24_OK_LED    CMD_LED.CMD24_OK

#define MMC_BUSY_LED    CMD_LED.SPI_BUSY   //busy led for spi port



/*--------------------------Error define-----------------------------*/

#define INIT_CMD0_ERROR     0x01

#define INIT_CMD1_ERROR                0x02

#define WRITE_BLOCK_ERROR        0x03

#define READ_BLOCK_ERROR           0x04



/*--------------------------MMC_CS_select define-----------------------------*/

//set MMC_Chip_Select to high (MMC/SD-Card Invalid)

#define MMC_Disable() MMC_Write.MMC_Chip_Select=1;

//set MMC_Chip_Select to low (MMC/SD-Card Active)

#define MMC_Enable() MMC_Write.MMC_Chip_Select=0;



#define nop() #asm("nop"); //asm nop defined in CVAVR

  

//---------------------------------------------------------------

// Prototypes

//---------------------------------------------------------------

// usart initialize

void usart_init(void);

// port initialize

void MMC_Port_Init(void);

//read a byte from MMC

uint8 Read_Byte_MMC(void);

//write a byte to MMC

void Write_Byte_MMC(uint8 value);

//read a block from MMC

uint8 MMC_Read_Block(uint8 *CMD,uint8 *Buffer,uint16 Bytes);

//MMC initialize

uint8 MMC_Init(void);

//write data sector to MMC

uint8 MMC_write_sector(uint32 addr,uint8 *Buffer);  

//write a command to MMC

uint8 Write_Command_MMC(uint8 *CMD);   

//read MMC CSD

uint8 Read_CSD_MMC(uint8 *Buffer);

//read MMC CID

uint8 Read_CID_MMC(uint8 *Buffer);  



//---------------------------------------------------------------------

static uint8  Init_Flag;    //Set it to 1 when Init is processing.



/*---------------------------------------------------------------------

函数功能:    本函数用于串行口的初始化操作。

备注:        本函数仅在主函数中调用一次即可。

----------------------------------------------------------------------*/

void usart_init(void)

{   /*设置波特率*/      

    UBRRL=0x03;  //波特率=115200

    /*接收、发送器使能*/

    UCSRB=0x18;

    /*设置帧格式: 8个数据位, 1个停止位*/

    UCSRC=0x86;

}



/*---------------------------------------------------------------------

函数功能    :port initialize

函数入口参数:NO

函数出口参数:NO

说明        :

----------------------------------------------------------------------*/

void MMC_Port_Init(void)

{

    //Config ports

    MMC_Direction_REG.SPI_DI = 0;          //Set Pin MMC_DI as Input

    MMC_Direction_REG.SPI_Clock = 1;       //Set Pin MMC_Clock as Output

    MMC_Direction_REG.SPI_DO = 1;          //Set Pin MMC_DO as Output

    MMC_Direction_REG.MMC_Chip_Select = 1; //Set Pin MMC_Chip_Select as Output

   

    //busy led port init

    CMD_LED_Direction.CMD0_OK = 1;         //set pin CMD0_LED as output

    CMD_LED_Direction.CMD1_OK = 1;         //set pin CMD0_LED as output

    CMD_LED_Direction.CMD17_OK = 1;        //set pin CMD0_LED as output

    CMD_LED_Direction.CMD24_OK = 1;        //set pin CMD0_LED as output

    CMD_LED_Direction.SPI_BUSY = 1;        //Set spi busy led port output

   

    MMC_BUSY_LED = 1;                      //busy led off

    CMD0_OK_LED = 1;                       //cmd0_ok_led off

    CMD1_OK_LED = 1;                       //cmd0_ok_led off

    CMD17_OK_LED = 1;                      //cmd0_ok_led off

    CMD24_OK_LED = 1;                      //cmd0_ok_led off

   

    MMC_CS_PIN = 1;                        //Set MMC_Chip_Select to High,MMC/SD Invalid.

}



//****************************************************************************

//Routine for Init MMC/SD card(SPI-MODE)

//****************************************************************************

uint8 MMC_Init(void)

{  

    uint8 retry,temp;

    uint8 i;

    uint8 CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};

   

    //MMC_Port_Init(); //Init SPI port  



    for(i=0;i<200;i++) //Wait MMC/SD ready...

    {

        #asm("nop");

    }

   

    Init_Flag=1; //Set the init flag



    for (i=0;i<0x0f;i++)

    {

        Write_Byte_MMC(0xff); //send 74 clock at least!!!

    }

       

    //Send Command CMD0 to MMC/SD Card

    retry=0;

    do

    { //retry 200 times to send CMD0 command

        temp=Write_Command_MMC(CMD);

        retry++;

        if(retry==200)

        { //time out

            UDR = INIT_CMD0_ERROR;

            while (!(UCSRA&0x20));

            return(INIT_CMD0_ERROR);//CMD0 Error!

        }

    }

    while(temp!=1);

     

    UDR = ~INIT_CMD0_ERROR;

    while (!(UCSRA&0x20));

    CMD0_OK_LED = 0;   //CMD 0 sent to MMC sucessful

   

    //Send Command CMD1 to MMC/SD-Card

    CMD[0] = 0x41; //Command 1

    CMD[5] = 0xFF;

    retry=0;

    do

    { //retry 100 times to send CMD1 command

        temp=Write_Command_MMC(CMD);

        retry++;

        if(retry==100)

        { //time out

            UDR = INIT_CMD1_ERROR;

            while (!(UCSRA&0x20));

            return(INIT_CMD1_ERROR);//CMD1 Error!

        }

    }

    while(temp!=0);

   

    CMD1_OK_LED = 0;   //CMD 1 sent to MMC sucessful

   

    Init_Flag=0; //Init is completed,clear the flag

   

    MMC_Disable();  //set MMC_Chip_Select to high

    return(0); //All commands have been taken.

}  



//****************************************************************************

//Send a Command to MMC/SD-Card

//Return: the second byte of response register of MMC/SD-Card

//****************************************************************************

uint8 Write_Command_MMC(uint8 *CMD)

{

    uint8 tmp;

    uint8 retry=0;

    uint8 i;



    //set MMC_Chip_Select to high (MMC/SD-Card disable)

    MMC_Disable();

    //send 8 Clock Impulse

    Write_Byte_MMC(0xFF);

    //set MMC_Chip_Select to low (MMC/SD-Card active)

    MMC_Enable();



    //send 6 Byte Command to MMC/SD-Card

    for (i=0;i<0x06;i++)

    {

        Write_Byte_MMC(*CMD++);

    }

   

    //get 16 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_MMC();

        retry++;

    }

    while((tmp==0xff)&&(retry<100));

    return(tmp);

}



//****************************************************************************

//Routine for reading a byte from MMC/SD-Card

//****************************************************************************

uint8 Read_Byte_MMC(void)

{

    uint8 temp=0;

    uint8 i;



    MMC_BUSY_LED=0;

    //Software SPI

    for (i=0; i<8; i++) //MSB First

    {

        MMC_CLK_PIN=0; //Clock Impuls (Low)

        if(Init_Flag) delay_us(10);

        temp = (temp << 1) + MMC_DO_PIN; //read mmc data out pin

        MMC_CLK_PIN=1; //set Clock Impuls High

        if(Init_Flag) delay_us(10);       

    }

    MMC_BUSY_LED=1;

    return (temp);

}



//****************************************************************************

//Routine for sending a byte to MMC/SD-Card   

//****************************************************************************

void Write_Byte_MMC(uint8 value)

{

    uint8 i;

   

    MMC_BUSY_LED=0;

    //Software SPI

    for (i=0; i<8; i++)

    {  //write a byte

        if (((value >> (7-i)) & 0x01)==0x01) MMC_DI_PIN=1; //Send bit by bit(MSB First)

        else MMC_DI_PIN=0;

        MMC_CLK_PIN=0; //set Clock Impuls low

        if(Init_Flag) delay_us(10);

        MMC_CLK_PIN=1; //set Clock Impuls High

        if(Init_Flag) delay_us(10);     

    }//write a byte

    MMC_DI_PIN=1;        //set Output High

    MMC_BUSY_LED=1;

}



//****************************************************************************

//Routine for writing a Block(512Byte) to MMC/SD-Card

//Return 0 if sector writing is completed.                        

//****************************************************************************

uint8 MMC_write_sector(uint32 addr,uint8 *Buffer)

{  

    uint8 tmp,retry;

    uint16 i;

    //Command 24 is a writing blocks command for MMC/SD-Card.

    uint8 CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF};

   

    #asm("cli"); //clear all interrupt.

    addr = addr << 9; //addr = addr * 512

       

    CMD[1] = ((addr & 0xFF000000) >>24 );

    CMD[2] = ((addr & 0x00FF0000) >>16 );

    CMD[3] = ((addr & 0x0000FF00) >>8 );



    //Send Command CMD24 to MMC/SD-Card (Write 1 Block/512 Bytes)

    retry=0;

    do

    {  //Retry 100 times to send command.

        tmp=Write_Command_MMC(CMD);

        retry++;

        if(retry==100)

        {

            return(tmp); //send commamd Error!

        }

    }

    while(tmp!=0);

   

    //Before writing,send 100 clock to MMC/SD-Card

    for (i=0;i<100;i++)

    {

        Read_Byte_MMC();

    }

       

    //Send Start Byte to MMC/SD-Card

    Write_Byte_MMC(0xFE);       

       

    //Now send real data Bolck (512Bytes) to MMC/SD-Card

    for (i=0;i<512;i++)

    {

        Write_Byte_MMC(*Buffer++); //send 512 bytes to Card

    }



    //CRC-Byte

    Write_Byte_MMC(0xFF); //Dummy CRC

    Write_Byte_MMC(0xFF); //CRC Code

   

    tmp=Read_Byte_MMC();   // read response

    if((tmp & 0x1F)!=0x05) // data block accepted ?

    {

        MMC_Disable();

        return(WRITE_BLOCK_ERROR); //Error!

    }

    //Wait till MMC/SD-Card is not busy

    while (Read_Byte_MMC()!=0xff){};

       

    //set MMC_Chip_Select to high (MMC/SD-Card Invalid)

    MMC_Disable();

    return(0);

}



//****************************************************************************

//Routine for reading data Registers of MMC/SD-Card

//Return 0 if no Error.                        

//****************************************************************************

uint8 MMC_Read_Block(uint8 *CMD,uint8 *Buffer,uint16 Bytes)

{  

    uint16 i; uint8 retry,temp;

   

    //Send Command CMD to MMC/SD-Card

    retry=0;

    do

    {  //Retry 100 times to send command.

        temp=Write_Command_MMC(CMD);

        retry++;

        if(retry==100)

        {

            return(READ_BLOCK_ERROR); //block write Error!

        }

    }

    while(temp!=0);

                          

    //Read Start Byte form MMC/SD-Card (FEh/Start Byte)

    while (Read_Byte_MMC() != 0xfe){};

       

    //Write blocks(normal 512Bytes) to MMC/SD-Card

    for (i=0;i<Bytes;i++)

    {

        *Buffer++ = Read_Byte_MMC();

    }

   

    //CRC-Byte

    Read_Byte_MMC();//CRC - Byte

    Read_Byte_MMC();//CRC - Byte

       

    //set MMC_Chip_Select to high (MMC/SD-Card invalid)

    MMC_Disable();

    return(0);

}



//***************************************************************************

//Routine for reading CID Registers from MMC/SD-Card (16Bytes)

//Return 0 if no Error.  

//***************************************************************************

uint8 Read_CID_MMC(uint8 *Buffer)

{

    //Command for reading CID Registers

    uint8 CMD[] = {0x4A,0x00,0x00,0x00,0x00,0xFF};

    uint8 temp;

    temp=MMC_Read_Block(CMD,Buffer,16); //read 16 bytes



    return(temp);

}



//***************************************************************************

//Routine for reading CSD Registers from MMC/SD-Card (16Bytes)

//Return 0 if no Error.

//***************************************************************************

uint8 Read_CSD_MMC(uint8 *Buffer)

{       

    //Command for reading CSD Registers

    uint8 CMD[] = {0x49,0x00,0x00,0x00,0x00,0xFF};

    uint8 temp;

    temp=MMC_Read_Block(CMD,Buffer,16); //read 16 bytes



    return(temp);

}



void main(void)

{

    usart_init();

    MMC_Port_Init();

    MMC_Init();

    while (1)

    {

        MMC_Init();

    };

}

出0入0汤圆

发表于 2007-9-19 16:27:09 | 显示全部楼层
最近想用8051来采集GPS模块的经纬度数据存储在SD卡,SPI模式。我不了解AVR单片机,也不想重新学习了。不知道有谁移植过?请贴上程序。谢谢!!在网络上面找了好久,AVR的还有一些资料。

    还有就是发送给SD卡的命令中有CRC位。程序中好象没有关注。CRC位不用管吗???等待ING!

出0入0汤圆

发表于 2007-9-19 17:30:48 | 显示全部楼层
看见了。CRC直接得出来了,就不用计算了。大致上应该这样移植到8051。
经过Keil检验,没有语法错误。逻辑错误就不知道了!赶明白上电测试就知道了!!
楼主都不给main函数。初始化有点难度。
欢迎给我邮件!
代码如下:(附件同样!)
点击此处下载armok01173896.zip


//2007-9-12 10:43  redFe开始写
//联系我:wb4916@sohu.com

#include <AT89x52.H>

sbit spiSDCS  = P2^7;
sbit spiSDDI  = P2^6;
sbit spiSDDO  = P2^4;
sbit spiSDCLK = P2^5;
sbit spiSDLED = P2^3;

#define uchar unsigned char        //one byte
#define uint  unsigned int         //two bytes
#define ulong unsigned long        //four bytes
#define slong signed long          //four bytes

uchar CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};

//向SD卡写入一个字节。
void writeByteSD(uchar value)
{
    uchar i;
   
    spiSDLED = 0;
   
    for(i=0;i<8;i++)
    {
        if(value&0x80)
            spiSDDI = 1;
        else
            spiSDDI = 0;
        
        spiSDCLK = 0;
        ;
        spiSDCLK = 1;
        ;
        
        value <<= 1;
    }
    spiSDDI  = 1;
    spiSDLED = 1;
}

//从SD卡读取一个字节。
uchar readByteSD(void)
{
    uchar i;
    uchar dataRead = 0x00;
   
    spiSDLED = 0;
   
    for(i=0;i<8;i++)
    {
        spiSDCLK = 0;
        ;
        
        if(spiSDDO)
            dataRead += 1;
        spiSDCLK = 1;
        ;
        
        dataRead <<= 1;
    }
    spiSDLED = 1;
    return(dataRead);
}

uchar writeCommandSD(void)
{
    uchar temp;
    uchar retry=0;
    uchar i;
   
    spiSDCS = 1;
    writeByteSD(0xFF);
    spiSDCS = 0;
   
    //发6个字节的命令
    for(i=0;i<6;i++)
    {
        writeByteSD(CMD[i++]);
    }
   
    //响应16位,第1个字节丢弃
    readByteSD();
    do{
        temp = readByteSD();
        retry++;
    }while((0xFF==temp)&&(retry<100));
   
    return(temp);
}

//使SD卡由SD模式切换到SPI模式
uchar initSD(void)
{
    uchar i;
    uchar temp;
    uchar retry = 0x00;
   
    for(i=0;i<200;i++)
        ;
    //在上电后,主机启动 SCK 及在 CMD 线上发送 74 个高电平的信号,
    //接着发送 CMD0 进入 SPI模式,然后发送 CMD1 激活初始化进程。
    for(i=0;i<0x0F;i++)
        writeByteSD(0xFF);
   
    do{
        temp = writeCommandSD();
        retry++;
        if(200 == retry)
            return(1);
    }while(temp != 1);
   
    //发送CMD0
    CMD[0] = 0x41;
    CMD[5] = 0xFF;
    retry = 0x00;
    do{
        temp = writeCommandSD();
        retry++;
        if(200 == retry)
            return(2);
    }while(temp != 0);
   
    spiSDCS = 1;
    return(0);
}

void main(void)
{   
    initSD();
}

出0入4汤圆

发表于 2007-9-25 10:19:15 | 显示全部楼层
我用了楼主的程序,能够读CID 正确       但是调用
void MMC_get_data_LBA(unsigned long lba, unsigned int Bytes,unsigned char *buffer)
读出来的数据不正确。

出0入4汤圆

发表于 2007-9-25 12:12:18 | 显示全部楼层
MMC_GotoSectorOffset(0,500);

void MMC_get_data_LBA(unsigned long lba, unsigned int Bytes,unsigned char *buffer)
读出来的数据 ,55 AA是有的 其他的都没有

出0入4汤圆

发表于 2007-9-25 12:15:05 | 显示全部楼层
FA 33 C0 8E D0 BC 00 7C 8B F4 50 07 50 1F FB FC BF 00 06 B9 00 01 F2 A5 EA 1D 06 00 00 BE BE 07 B3 04 80 3C 80 74 0E 80 3C 00 75 1C 83 C6 10 FE CB 75 EF CD 18 8B 14 8B 4C 02 8B EE 83 C6 10 FE CB 74 1A 80 3C 00 74 F4 BE 8B 06 AC 3C 00 74 0B 56 BB 07 00 B4 0E CD 10 5E EB F0 EB FE BF 05 00 BB 00 7C B8

这是执行
MMC_GotoSectorOffset(0,0);
MMC_get_data_LBA(0,100,buf);

中前100个字节的数据,
而WINHEX读出来的数据是

EB 58 90......

出0入0汤圆

发表于 2007-9-25 12:22:46 | 显示全部楼层
【89楼】 ilan2003 小松工程
WINHEX应该去读物理磁盘才能读到你列出的数据

FA 33 C0 8E D0 BC
一看就是到这是MBR的数据
EB 58 90......
是DBR的数据

要读到必须先去处理MBR才能知道DBR在哪,不过有的卡是没有MBR的,所以程序还要去判断是否有MBR

出0入4汤圆

发表于 2007-9-25 12:46:29 | 显示全部楼层
哦  谢谢了 看来程序的确是调通了

EB 58 90......  是分区一的数据

FA 33 C0 8E D0 BC  。。是启动分区的数据。

用物理分区打开,找到FA 33 C0 8E D0 BC  ...这些数据,


EB 58 90......在地址 0000CA00中发现了

所以物理分区包含了包括DBR,和MBR的数据,而打开逻辑分区只有DBR的数据  对吧

出0入0汤圆

发表于 2007-9-25 13:08:01 | 显示全部楼层
可以这么理解。
“EB 58 90......在地址 0000CA00中发现了”
中的地址在MBR中会有记载的,就是在MBR中的分区表中的记录着。所以可以根据MBR的分区表找到分区1

出0入4汤圆

发表于 2007-9-25 13:11:29 | 显示全部楼层
我已经通过程序能够访问EB 58 90......的数据了,
但是奇怪的是
调用函数
MMC_get_data_LBA(0,100,buf);//中间的那个参数最大只能到达107  超过  程序就死机了

出0入0汤圆

发表于 2007-9-25 13:18:33 | 显示全部楼层
这个代码我没看过
中间那个参数是什么?数据长度?难道是数组溢出了?

出0入4汤圆

发表于 2007-9-25 14:04:45 | 显示全部楼层
数据长度  我定义数组

uint08 ddd[];
这样会益处吗?我用的M8 有1k的ram

出0入0汤圆

发表于 2007-9-25 14:40:29 | 显示全部楼层
那奇怪了,你看看是不是程序里面也用了数组,如果来两个ddd[512]不就挂了,
我都是动态分配内存的,用malloc 和 free来操作

出0入4汤圆

发表于 2007-9-25 17:28:49 | 显示全部楼层
C学的不好 malloc 和 free重来都不用的

出0入0汤圆

发表于 2007-12-15 21:26:16 | 显示全部楼层
LZ能否给出CAVR的硬件SPI,我正需要啊,谢谢!

出0入0汤圆

发表于 2007-12-17 10:25:40 | 显示全部楼层
ding
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-5-6 09:44

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

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