elefan 发表于 2005-9-4 10:58:06

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

经过一段时间的努力,搞定了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

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

1CS    ---> 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编辑过

myjnj 发表于 2005-9-4 11:00:47

期待中

y6807 发表于 2005-9-4 11:07:51

收藏先。。。

armok 发表于 2005-9-4 11:12:20

谢谢共享!



给elefan的共享精神加200分!

elefan 发表于 2005-9-4 11:25:41

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

elefan 发表于 2005-9-4 11:38:58

呵呵,是系统错误吧! 现在OK!

makesoft 发表于 2005-9-4 12:14:50

编程风格不错,是值得大家学习的程序。

elefan 发表于 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了,请参考程序:)

greatsnows 发表于 2005-9-4 12:33:24

支持!有时间好好研究

kinsey 发表于 2005-9-4 20:21:26

不错。

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

谢谢!

SanDragon 发表于 2005-9-4 21:08:31

http://www.ulrichradig.de/site/atmel/avr_mmcsd/index.htm

elefan 发表于 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编辑过

hebj 发表于 2005-9-5 20:23:22

好东西,辛苦了。

kinggink888 发表于 2005-9-5 21:51:17

哗,好东西,多谢共享

armandusb 发表于 2005-9-6 08:52:30

向elefan这种无私的精神致敬!什么时候MP3的测试整体出来啊!期待!

ljd166 发表于 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): reference to `volatile unsigned char' elided

!W mmc.c(25): 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): reference to `volatile unsigned char' elided

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

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

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

ljd166 发表于 2005-9-6 09:28:09

好像是头文件中结构体出错,后来我又加了IO162V.H文件,可是依旧不能通过

elefan 发表于 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中做了详细描述. 可以进行'.'操作,就是位操作.

ljd166 发表于 2005-9-6 10:32:43

谢谢楼主,看来我可能需要重新编这段程序,不过楼主的这种风格我很喜欢,所以才保留下来,没有修改。

elefan 发表于 2005-9-6 10:35:01

Toljd166 :

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

pengkewei 发表于 2005-9-8 21:41:56

借问楼主:

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

myhk007 发表于 2005-9-27 11:16:18

问一下楼主,你用的那个软SPI中间的Init_Flag那个量是干什么用的啊?

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

elefan 发表于 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 = 0x41; //Command 1

   CMD = 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);   

}

}

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

elefan 发表于 2005-9-27 14:20:18

读数据先送0XFF,实际上上发clk脉冲.你应该知道SPI是同步的,发数据时候,SPI也在接收数据,所以数据0XFF被送出后,在SPDR中就得到了要接收的数据.请参考上面的代码:)

myhk007 发表于 2005-9-28 10:38:03

多谢ELEFAN!今天就准备上电调试了,估计会遇到不少问题啊.

zqulwd 发表于 2005-12-4 14:14:13

是用我喜欢的CVAVR啊。

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

可惜最近没空啊。

谢谢啦

eagle_soar 发表于 2005-12-9 15:19:28

谢谢共享,我在21ic上的AVR 论坛还找不到关于AVR 开发技术上的那么详细的讲解.

也谢谢站主.

hygbeyond 发表于 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测试通过的

elefan 发表于 2006-1-7 11:56:58

to hygbeyond:

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

avrlover 发表于 2006-1-8 13:48:00

avr-libc中就有源码.

ljd166 发表于 2006-2-24 11:02:47

elefan 代码中初始化到SPI模式,少了个MMC_ENABLE.

jimo 发表于 2006-2-24 11:29:16

初始化时速度慢, 我估计是sd和mmc的兼容性的原因, sd卡不知道设备是否支持高速, 所以用低速来初始化, 初始化完成后确定可以支持高速, 才进入到高速模式

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

谢了...

ljd166 发表于 2006-2-24 14:53:46

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

elefan 发表于 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的说明书,那里说的比较详细,资料就在本论坛.

ljd166 发表于 2006-2-26 22:35:24

唉,刚开始像无头苍蝇一样,胡乱试,结果出了错,不过还好我又把它给修好了。

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

ljd166 发表于 2006-2-28 14:30:48

请教楼主一个问题,为什么我的SD卡在读写的时候,地址会有19的偏移,包括读和写

freny 发表于 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);这样才能得到高位块地址吧?

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

elefan 发表于 2006-4-26 00:15:44

toljd166 : 能详细描述下吗?



to freny:



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



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

jackrich 发表于 2006-4-26 08:07:45

好,谢谢!

freny 发表于 2006-4-26 10:40:48

非常感谢elefan!

lsz_avr 发表于 2006-8-10 08:59:59

谢谢各位工程师!希望能看到硬件电路,便于新手学习啊!

dengzhao1982 发表于 2006-8-21 14:42:12

硬件是利用SPI总线连接的,不会很复杂。关键是软件的调试部分。

elecfans 发表于 2006-8-29 17:55:46

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

ahui 发表于 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 = ((addr & 0xFF000000) >>24 );

   CMD = ((addr & 0x00FF0000) >>16 );

   CMD = ((addr & 0x0000FF00) >>8 );



   temp=MMC_Read_Block(CMD,Buffer,512);

   

   return(temp);

}

其中的

unsigned long addr

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

http://cache.amobbs.com/bbs_upload782111/files_6/armok01128648.jpg



http://cache.amobbs.com/bbs_upload782111/files_6/armok01128647.jpg



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


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

whimsy 发表于 2006-9-12 13:28:50

我的一张MMC卡在NOKIA手机上被锁了,是不是可以这样的程序对它的扇区进行格式化?

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

gl516 发表于 2006-9-12 23:35:53

那位大虾有没有用CVAVR编译器写的SD/MMC的读写程序啊?论坛上都是ICC和GCC的。

gl516 发表于 2006-9-12 23:49:12

to:elefan

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

jiuzhuaxiong 发表于 2006-10-3 11:48:52

请教一下,你用的那个查看分区的还一些详细资料的软件的名字叫什么??谢谢!

elefan 发表于 2006-10-3 22:23:42

编辑工具: UltraEdit 功能很强大,你试着用下吧!

elefan 发表于 2006-10-3 22:25:14

to whimsy:



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

ahui 发表于 2006-10-28 13:45:08

接【43楼】



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

pdwde 发表于 2006-10-28 18:07:39

上面那个直接读磁盘数据的软件应该是winHex吧

gl516 发表于 2006-11-7 11:16:28

怎么我用MMC_get_volume_info()来读一个32M的MMC卡 读出来的结果是这样的

Product:32***

Total: MB

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

wentao 发表于 2006-11-7 11:49:17

收藏一下,谢谢楼主共享

gl516 发表于 2006-11-7 13:54:57

怎么我用MMC_get_volume_info()来读一个32M的MMC卡 读出来的结果是这样的

Product:32***

Total: MB

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

knightdead 发表于 2006-11-8 17:29:32

仔细研究中...

9810956 发表于 2006-11-8 17:37:01

收下

xiaotanlan 发表于 2006-11-12 12:13:23

顶一下楼主的好贴,我正好要用。

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

elefan 发表于 2006-11-12 23:07:55

to gl516: 可能是你的显示函数有问题,你再看看.



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

elefan 发表于 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例子很好.

xiaotanlan 发表于 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编辑过

knightdead 发表于 2006-11-24 14:24:11

我把程序修改,以便ICC平台编译,可是没有delay_us(8)的定义,我不熟悉CVAVR,不知道这个delay_us(8)是不是延迟8us的意思?

elefan 发表于 2006-11-25 14:42:17

toxiaotanlan: 对,上面的程序是最底层操作,如果自己不想写USB驱动,直接使用mass storage方式查看,确实需要使用FAT系统。按照FAT系统写入数据,否则,电脑不认的。



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



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



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

knightdead 发表于 2006-11-29 17:01:59

谢谢你的解答.

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

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

高兴!

xiaotanlan 发表于 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

flyhemcu 发表于 2006-12-14 16:53:45

楼主,你好。



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



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

zergl 发表于 2007-3-22 14:33:46

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

zzzzy 发表于 2007-3-22 16:01:23

0扇区是MBR,记录了分区表,读BPB应该在第一个分区的“0扇区"

zzzzy 发表于 2007-3-22 16:17:35

0扇区是MBR,记录了分区表,读BPB应该在第一个分区的“0扇区"

zpwang 发表于 2007-3-22 23:04:18

多谢楼主!我下来学习.

evilangell 发表于 2007-3-25 01:23:08

"多动脑子比多动手要强的多"



顶这句话

sd01101230 发表于 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 P4bit0 */

#define   p4_1      p4_addr.b.b1      /* Port P4bit1 */

#define   p4_2      p4_addr.b.b2      /* Port P4bit2 */

#define   p4_3      p4_addr.b.b3      /* Port P4bit3 */

#define   p4_4      p4_addr.b.b4      /* Port P4bit4 */

#define   p4_5      p4_addr.b.b5      /* Port P4bit5 */

#define   p4_6      p4_addr.b.b6      /* Port P4bit6 */

#define   p4_7      p4_addr.b.b7      /* Port P4bit7 */



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

    Port P4 direction register

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

union byte_def pd4_addr;

#define   pd4   pd4_addr.byte



#define   pd4_0       pd4_addr.b.b0       /* P4 direction registerbit0 */

#define   pd4_1       pd4_addr.b.b1       /* P4 direction registerbit1 */

#define   pd4_2       pd4_addr.b.b2       /* P4 direction registerbit2 */

#define   pd4_3       pd4_addr.b.b3       /* P4 direction registerbit3 */

#define   pd4_4       pd4_addr.b.b4       /* P4 direction registerbit4 */

#define   pd4_5       pd4_addr.b.b5       /* P4 direction registerbit5 */

#define   pd4_6       pd4_addr.b.b6       /* P4 direction registerbit6 */

#define   pd4_7       pd4_addr.b.b7       /* P4 direction registerbit7 */

                  

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


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

sd01101230 发表于 2007-3-26 22:19:41

有人吗??

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

DDR又是什么针脚?

DATAPIN是???

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



赐教阿。

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

万分感谢。

sd01101230 发表于 2007-3-27 18:52:29

完了 用 瑞萨的 M16C/6N4

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

找了2天也没找到。



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

pcj203 发表于 2007-4-11 14:59:37

谢谢楼主的开源,,,

st_hb 发表于 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);

}

st_hb 发表于 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);

}

st_hb 发表于 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);

}

xiaohua4758 发表于 2007-5-26 13:17:49

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

_________________ PORTA.0

|

|-|

| | 1.2K

|_|

|_________________CMD/DI(MMC/SD PIN)

|

|-|

| |2.2k

|_|

|

|

|_________________GND

          |

         ---

          -

xiaohua4758 发表于 2007-5-26 14:37:03

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

_________________ PORTA.0

|

|-|

| | 1.2K

|_|

|_________________CMD/DI(MMC/SD PIN)

|

|-|

| |2.2k

|_|

|

|

|_________________GND

          |

         ---

          -

elefan 发表于 2007-5-26 14:39:53

上面整个图是做TTL逻辑与CMOS逻辑转换,SD卡数据扇区需要看FAT,格式化成不同的FAT系统,数据扇区就不一样。

elefan 发表于 2007-5-26 14:44:43

to flyhemcu :



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



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



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



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

xiaohua4758 发表于 2007-5-31 23:43:42

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

HuaHuaZi 发表于 2007-7-14 14:34:15

有没有SD模式(4线模式)的初始化?请大虾指点?

moqiaobo 发表于 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 uint16unsigned int

#define int16   signed int

#define uint32unsigned 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 uint8Init_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 = 0x41; //Command 1

    CMD = 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 = ((addr & 0xFF000000) >>24 );

    CMD = ((addr & 0x00FF0000) >>16 );

    CMD = ((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();

    };

}

wb4916 发表于 2007-9-19 16:27:09

最近想用8051来采集GPS模块的经纬度数据存储在SD卡,SPI模式。我不了解AVR单片机,也不想重新学习了。不知道有谁移植过?请贴上程序。谢谢!!在网络上面找了好久,AVR的还有一些资料。

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

wb4916 发表于 2007-9-19 17:30:48

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


//2007-9-12 10:43redFe开始写
//联系我: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 uintunsigned 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);
    }
   
    //响应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 = 0x41;
    CMD = 0xFF;
    retry = 0x00;
    do{
      temp = writeCommandSD();
      retry++;
      if(200 == retry)
            return(2);
    }while(temp != 0);
   
    spiSDCS = 1;
    return(0);
}

void main(void)
{   
    initSD();
}

ilan2003 发表于 2007-9-25 10:19:15

我用了楼主的程序,能够读CID 正确       但是调用
void MMC_get_data_LBA(unsigned long lba, unsigned int Bytes,unsigned char *buffer)
读出来的数据不正确。

ilan2003 发表于 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是有的 其他的都没有

ilan2003 发表于 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......

bozai 发表于 2007-9-25 12:22:46

【89楼】 ilan2003 小松工程
WINHEX应该去读物理磁盘才能读到你列出的数据

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

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

ilan2003 发表于 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的数据对吧

bozai 发表于 2007-9-25 13:08:01

可以这么理解。
“EB 58 90......在地址 0000CA00中发现了”
中的地址在MBR中会有记载的,就是在MBR中的分区表中的记录着。所以可以根据MBR的分区表找到分区1

ilan2003 发表于 2007-9-25 13:11:29

我已经通过程序能够访问EB 58 90......的数据了,
但是奇怪的是
调用函数
MMC_get_data_LBA(0,100,buf);//中间的那个参数最大只能到达107超过程序就死机了

bozai 发表于 2007-9-25 13:18:33

这个代码我没看过
中间那个参数是什么?数据长度?难道是数组溢出了?

ilan2003 发表于 2007-9-25 14:04:45

数据长度我定义数组

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

bozai 发表于 2007-9-25 14:40:29

那奇怪了,你看看是不是程序里面也用了数组,如果来两个ddd不就挂了,
我都是动态分配内存的,用malloc 和 free来操作

ilan2003 发表于 2007-9-25 17:28:49

C学的不好 malloc 和 free重来都不用的

zqljg 发表于 2007-12-15 21:26:16

LZ能否给出CAVR的硬件SPI,我正需要啊,谢谢!

zlw_str 发表于 2007-12-17 10:25:40

ding
页: [1] 2 3
查看完整版本: [原创]资源共享:开放我的mmc/sd操作原代码