二、MMC/SD卡的模型和工作原理 PIN脚、SD卡总线、SD卡结构、SD卡寄存器、上电过程 SD卡寄存器:

 OCR:操作电压寄存器: 只读,32位 第31位: 表示卡上电的状态位 
 CID: 卡身份识别寄存器 只读 128位 生产厂商、产品ID,生产日期和串号等 
 CSD: 部分可写 128位 卡的容量、擦出扇区大小、读写最大数据块的大小、读操作的电流、电压等等
 CSR: 卡配置寄存器 64位 数据位宽 
 RCA: 16位 相关的卡地址寄存器,卡识别过程中主控器和卡协商出来的一个地址 
 三、SD卡命令和响应格式 命令和相应格式 SD卡命令,命令类型,ACMD命令 响应类型、卡类型、卡状态转换表 命令的格式: 48位 起始位0 方向位(host to card: 1, card to host: 0) 内容 CRC7 结束位1· 
响应的格式:48位 或者136位 
卡命令: 命令的类型:
 bc: broadcast without Response 无响应的广播 
 bcr: broadcast with Response 有响应的广播 
 ac: Address(point-to-point) Command: 点对点,DATA0~DATA3数据线上无数据 
 adtc: Adress(point-to-point) Data Transfer Commands 点对点,DATA0~DATA3数据线上有数据
 
 CMD0, CMD2, CMD3, CMD55, ACMD41 命令可能会导致卡的状态发生变化 
 响应类型: R1,R1b, R2, R3,R6(SD2.0扩展了R7) 
 扩展内容: 
SPI工作模式: 要知道的特点:只支持一个卡,没有RCA,命令只是MMC/SD的基本的子集 
 SDHC:(支持2GB~32GB):理解CMD8的作用,命令格式和响应,了解CSDV2.0寄存器做了扩展   SDIO WIFI: 增加CMD52, CMD53  
 
CMD8可以通过重新定义先前保留的位,来扩展一些已经存在的命令的新功能。ACMD41扩大到支持高容量SD记忆卡的初始化
 
上面介绍了一个控制寄存器等信息 
 
绿色表示sd和mmc的不同点
 
对于计算卡的容量 要注意
对于sd 卡 可以参考Simplified_Physical_Layer_Spec v2.0.pdf手册上面有
对于mmc  可以参考JESD84-A441.pdf 注意对于大卡的mmc 是通过发送8号命令 来获取ext_csd  中的212到215位置来得到的
---------------------------------------------------------------------------
static void sd_init(void)
{
int retries;
u8 *resp;
unsigned int cardaddr;
/
resp = mmc_cmd(, , MSC_CMDAT_RESPONSE_R2, MSC_CMDAT_RESPONSE_R2);
//serial_puts("  SD carsd CID  =R2=  ");  serial_dump_data(resp, 15);
resp = mmc_cmd(, , MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1);
cardaddr = (resp[] << ) | resp[];  //发生3命令 来或者rca
rca = cardaddr << ;
//serial_puts("rca="); serial_puts_hex(rca);

resp = mmc_cmd(, rca, MSC_CMDAT_RESPONSE_R2, MSC_CMDAT_RESPONSE_R2);
sd2_0 = (resp[] & ;
//serial_puts("sd2_0====="); serial_puts_hex(sd2_0);
//serial_puts("  SD carsd CSD Register =R2= ");  serial_dump_data(resp, 16);

OUTREG16(A_MSC_CLKRT(), );
resp = mmc_cmd(, rca, MSC_CMDAT_BUSY | MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1);
resp = mmc_cmd(, rca, MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1);
resp = mmc_cmd(, 0x2, MSC_CMDAT_BUS_WIDTH_4BIT | MSC_CMDAT_RESPONSE_R1|MSC_CMDAT_BUSY, MSC_CMDAT_RESPONSE_R1);//应答类型R1b
//while(!(INREG16(A_MSC_STAT(0))&(1<<13)));//等待编程完成
}
------------------------------------------------------------
//从这儿开始看
int  mmc_init(void) //
{
int retries;
u8 *resp;
OUTREG32(A_CPM_MSCCDR,);
SETREG32(A_CPM_CPCCR, CPCCR_CHANGE_EN);

MMC_INIT_GPIO();
__msc_reset();
MMC_IRQ_MASK();
OUTREG32(A_MSC_CLKRT(), );//extclk/128
//OUTREG32(A_MSC_LPM(0),0x01);
//sd2_0 = 0; //默认为标准SD卡
resp = mmc_cmd(, , , ); //先80个时钟
resp = mmc_cmd(, 0x1aa, 0x1, MSC_CMDAT_RESPONSE_R1); //判断是sd2(返回0x1)以后的卡还是sd1(返回0x5)现在基本都是sd2以后 的所以都没有对返回值判断
resp = mmc_cmd(, , MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1); //根据cmd55来判断是mmc卡还是sd卡,只有卡才有55命令 才能正确有返回值 返回值有command index =0x37=55 的话说明是sd
//serial_puts(" Application Specific Commands =R1= "); serial_dump_data(resp, 6);
] != 0x37) {  //是mmc卡
//serial_puts("MMC card found!\n");
retries = ;
do{
resp = mmc_cmd(, 0x40ff8000, MSC_CMDAT_RESPONSE_R3, MSC_CMDAT_RESPONSE_R3); //匹配电压 mmc卡是CMD1  SD卡是CMD41  因为上电是要一个时间的 所以就利用一个do{}while 来延时
sd_mdelay();
}
] & 0x80)); //直到r3中的ocr回复值中的31位为1的时候表示上电完成了
]&0x40)//电压验证最后一次应答中带有数据访问模式位,如果为1,则类似SDHC卡基于块地址访问
{
sd2_0 = ;  // 也可以利用r3 返回值中的ocr的30位来检查是高容量卡(>2G)还是标准卡  其实也可以利用cmd9命令读取cds来判断 在sd就是这么做的
}
#if 0
serial_puts();
]& 0x80)
serial_puts("\n\nMMC init ok\n\n");// 表示上电完成
else
serial_puts("\n\nMMC init fail\n\n");
#endif
resp = mmc_cmd(, , MSC_CMDAT_RESPONSE_R2, MSC_CMDAT_RESPONSE_R2); //获取CID
//serial_puts("  CID CSD =R2= ");  serial_dump_data(resp, 16);
resp = mmc_cmd(, 0x10, MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1); //这个东西就很恶心了  在sd卡和mmc卡的参数不一样  mmc卡的参数是自己设定一个rca值 ,但是sd卡是通过回复值中读取rca,上面sd卡的初始化中有描述
OUTREG16(A_MSC_CLKRT(), );
resp = mmc_cmd(, 0x10, MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1);//设置新地址为有效地址  这样就进入了tarnsport mode .只有发送了7号命令 还有设置位宽CMD6  才能发生正在的进行读写发生16 17 18等
resp = mmc_cmd(, 0x3b70101, MSC_CMDAT_BUS_WIDTH_4BIT|MSC_CMDAT_RESPONSE_R1|MSC_CMDAT_BUSY, MSC_CMDAT_RESPONSE_R1);//应答类型R1b,设置位宽  为4BIT模式

resp = mmc_cmd(, rca, MSC_CMDAT_RESPONSE_R1, MSC_CMDAT_RESPONSE_R1);
card_status = (resp[] << ) | (resp[] << ) | (resp[] << ) | resp[];
serial_puts("mmc_cmd 13\n");
if((card_status & 0x900) != 0x900) //ready && tran
{
return OPEN_CARD_INIT_CHECK_STATUS_ERROR;
}
//对于mmc卡经常要加CMD13,不然经常会出现问题的,CMD13在发生玩cmd3后就可以随时发送
))&(<<)));//等待编程完成
}
else//如果是sd卡
sd_init();
;

上图就是我在手册上面截取的初始化部分图片 系统上电后发生cmd0命令后就进入idle 状态,CMD1检查电压,然后就进入Ready state -->cmd2 (读取cid)进入Ident状态  --> CMD3(设置rca)进入stand state状态---》cmd7进入transport状态 在这里还可以利用CMD6设置位宽的大小  sd不支持8BIT mmc支持

当卡发生完CMD3后进入待机状态(stand-by state),cmd7可以让卡进入transport状态,

 
---------------------------------------------------------------------------------------
SD卡调试关键点:
 
1.      上电时要延时足够长的时间给SD卡一个准备过程,在我的程序里是5秒,根据不同的卡设置不同的延时时间。SD卡初始化第一步在发送CMD命令之前,在片选有效的情况下首先要发送至少74个时钟,否则将有可能出现SD卡不能初始化的问题。
 
2.      SD卡发送复位命令CMD0后,要发送版本查询命令CMD8,返回状态一般分两种,若返回0x01表示此SD卡接受CMD8,也就是说此SD卡支持版本2;若返回0x05则表示此SD卡支持版本1。因为不同版本的SD卡操作要求有不一样的地方,所以务必查询SD卡的版本号,否则也会出现SD卡无法正常工作的问题。
 
3.      理论上要求发送CMD58获得SD卡电压参数,但实际过程中由于事先都知道了SD卡的工作电压,因此可省略这一步简化程序。协议书上也建议尽量不要用这个命令。
 
4.      SD卡读写超时时间要按照协议说明书书上的给定值(读超时:100ms;写超时:250ms),这个值要在程序中准确计算出来,否则将会出现不能正常读写数据的问题。我自己定义了一个计算公式:超时时间=(8/clk)*arg。 
 
5.      2GB以内的SD卡(标准卡)和2GB以上的SD卡(大容量卡)在地址访问形式上不同,这一点尤其要注意,否则将会出现无法读写数据的问题。如标准卡在读写操作时,对读或写命令令牌当中的地址域符初值0x10,表示对第16个字节以后的地址单元进行操作(前提是此SD卡支持偏移读写操作),而对大容量卡读或写命令令牌当中的地址域符初值0x10时,则表示对第16块进行读写操作,而且大容量卡只支持块读写操作,块大小固定为512字节,对其进行字节操作将会出错。
 
6.      对某一块要进行写操作时最好先执行擦出命令,这样写入的速度就能大大提高。进行擦除操作时不管是标准卡还是大容量卡都按块操作执行,也就是一次擦除至少512字节。
 
7.      对标准卡进行字节操作时,起始和终止必须在一个物理扇区内,否则将不能进行读写操作。实际操作过程中建议用块操作以提高效率。不管是标准卡还是大容量卡一个读写命令只能对一个块进行操作,不允许跨物理层地址操作。
 
8.      在写数据块前要先写入若干个dummy data字节,写完一个块数据时,主机要监测MISO数据线,如果从机处于忙状态这根数据线会保持低电平,这样主机就可以根据这根数据线的状态以决定是否发送下一个命令,在从机没有释放MISO数据线之前,主机绝对不能执行其他命令,否则将会导致写入的数据出错,而且从机也不会响应主机的命令。
 
9.      在SPI模式下,CRC校验是被忽略的,但依然要求主从机发送CRC码,只是数值可以是任意值,一般主机的CRC码通常设为0x00或0xFF。
 
读多块操作和写多块操作的传输停止形式不一样,读多块操作时用用命令CMD12终止传输,而写多块操作时用Stop Tran Token(停止传输令牌,值为0xFD)终止传输。
----------------------------------------------------------------------------------------
1、初始化步骤:
(1)    延时至少74clock,等待SD卡内部操作完成,在MMC协议中有明确说明。
(2)CS低电平选中SD卡。
(3)发送CMD0,需要返回0x01,进入Idle状态
(4)为了区别SD卡是2.0还是1.0,或是MMC卡,这里根据协议向上兼容的原理,首先发送只有SD2.0才有的命令CMD8,如果CMD8返回无错误,则初步判断为2.0卡,进一步发送命令循环发送CMD55+ACMD41,直到返回0x00,确定SD2.0卡初始化成功,进入Ready状态,再发送CMD58命令来判断是HCSD还是SCSD,到此SD2.0卡初始化成功。如果CMD8返回错误则进一步判断为1.0卡还是MMC卡,循环发送CMD55+ACMD41,返回无错误,则为SD1.0卡,到此SD1.0卡初始成功,如果在一定的循环次数下,返回为错误,则进一步发送CMD1进行初始化,如果返回无错误,则确定为MMC卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始结束。
(5)CS拉高。
 
 
我们在读写的前面可以最好 读取下状态CMD13来检查状态位,判断上一次的命令是否传输完了
2、读步骤:
(1)    发送CMD17(单块)或CMD18(多块)读命令,返回0x00
(2)    接收数据开始令牌0xfe(或0xfc)+正式数据512Bytes + CRC校验2Bytes默认正式传输的数据长度是512Bytes,可用CMD16设置块长度。
 
3、写步骤:
(1)    发送CMD24(单块)或CMD25(多块)写命令,返回0x00
(2)    发送数据开始令牌0xfe(或0xfc)+正式数据512Bytes + CRC校验2Bytes
 
4、擦除步骤:
(1)    发送CMD32,跟一个参数来指定首个要擦除的起始地址(SD手册上说是块号)
(2)    发送CMD33,,指定最后的地址
(3)    发送CMD38,擦除指定区间的内容此3步顺序不能颠倒。最后说一下我的一点体会:SD卡就是一个存储器,只不过用命令的方式来进行操作,我们只要掌握了各条命令及操作方式,就可以灵活的操作SD卡了,另外我所了解的IC卡也是类似的原理,还有就是建议开始看MMC的协议,简单明了易懂些,有了对MMC卡的一些了解后看SD卡协议就容易多了。
SD卡命令共分为12类,分别为class0到class11,不同的SDd卡,主控根据其功能,支持不同的命令集 如下
Class0 :(卡的识别、初始化等基本命令集)CMD0:复位SD 卡.CMD1:读OCR寄存器.CMD9:读CSD寄存器.CMD10:读CID寄存器.CMD12:停止读多块时的数据传输CMD13:读 Card_Status 寄存器
Class2 (读卡命令集):CMD16:设置块的长度CMD17:读单块.CMD18:读多块,直至主机发送CMD12为止 .
Class4(写卡命令集) :CMD24:写单块.CMD25:写多块.CMD27:写CSD寄存器 .
Class5 (擦除卡命令集):CMD32:设置擦除块的起始地址.CMD33:设置擦除块的终止地址.CMD38: 擦除所选择的块.
Class6(写保护命令集):CMD28:设置写保护块的地址.CMD29:擦除写保护块的地址.CMD30: Ask the card for the status of the write protection bits
class7:卡的锁定,解锁功能命令集 
class8:申请特定命令集 。
class10 -11 :保留
其中class1,class3,class9:SPI模式不支持 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

SD/MMC卡初始化及读写流程的更多相关文章

  1. 在SD/MMC卡上实现hive (Implement WinCE HIVE&ROM system on NAND or SD system )

    本是个很简单的topic,但无奈的是很多客户都没有实现.所以只能写一个guide给客户,让他们依葫芦画瓢. 在SD卡上实现hive以及实现binfs最精髓的思想是,在boot stage 1依次加载s ...

  2. (linux)MMC 卡驱动分析

    最近花时间研究了一下 MMC 卡驱动程序,开始在网上找了很多关于 MMC 卡驱动的分析文章,但大都是在描述各个层,这对于初学者来讲帮助并不大,所以我就打算把自己的理解写下来,希望对大家有用.个人觉得理 ...

  3. MA8621带SD读卡的USB 2.0高速3端口HUB方案芯片|MA8621中文规格书|USB 2.0方案

    MA8621说明 MA8621是USB 2.0高速3端口集线器的高性能解决方案,带有SD卡控制器,完全符合通用串行总线规范2.0.控制器继承了先进的串行接口技术,当3个DS(下游)端口同时工作时,功耗 ...

  4. 带SD读卡的USB HUB方案芯片MA8621|用于带读卡的USB HUB拓展坞方案芯片MA8621

    MA8621是一款带SD读卡器控制器的USB 2.0高速3端口集线器方案芯片,主要用在USB TYPEC拓展坞或者USB typec扩展底座上面. 1. MA8621功能概述 MA8621是USB 2 ...

  5. SD卡spi读写流程

    SD卡spi读写流程 1.SD卡的命令格式: SD卡的指令由6字节(Byte)组成,如下: Byte1:0 1 x x x x x x(命令号,由指令标志定义,如CMD39为100111即16进制0x ...

  6. SD卡初始化以及命令详解

    SD卡是嵌入式设备中很常用的一种存储设备,体积小,容量大,通讯简单,电路简单所以受到很多设备厂商的欢迎,主要用来记录设备运行过程中的各种信息,以及程序的各种配置信息,很是方便,有这样几点是需要知道的 ...

  7. 单元测试+内存、SD卡、SP读写+XmlPullParser

    测试: 测试的相关概念 1.根据是否知道源代码分类: 黑盒测试: a - b - c 边值测试 测试逻辑业务 白盒测试: 根据源代码写测试方法 或者 测试用例; 2.根据测试的粒度分类: 方法测试:写 ...

  8. Smart210学习记录-----SD/MMC/SDIO驱动

    转自:http://jingpin.jikexueyuan.com/article/23369.html http://blog.csdn.net/evilcode/article/details/7 ...

  9. Linux SD/MMC/SDIO驱动分析

    一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(MultimediaCard) SD 是一种 flash memory card 的标准,也就是一般常见的 SD 记忆 ...

随机推荐

  1. 《Programming WPF》翻译 第3章 4.我们进行到哪里了?

    原文:<Programming WPF>翻译 第3章 4.我们进行到哪里了? 控件是由应用程序创建的块.它们描述了用户用来交互的界面特征.控件提供了行为,依赖样式和模板来表示一个外观.输入 ...

  2. PowerShell远程连接主机进行会话

    Get-ExecutionPolicy #脚本的执行策略set-ExecutionPolicy 枚举值 不同的策略,执行脚本的权限不同 允许开启远程 Enable-PSRemoting 添加域账户或者 ...

  3. bzoj1615 [Usaco2008 Mar]The Loathesome Hay Baler麻烦的干草打包机

    Description Farmer John新买的干草打包机的内部结构大概算世界上最混乱的了,它不象普通的机器一样有明确的内部传动装置,而是,N (2 <= N <= 1050)个齿轮互 ...

  4. CSS3 新特性 开放字体格式WOFF

    疑问 上面这是虾米玩意?    \e806 是在自定义字体表中的字体位置.    好嘛 现在问题来了 WOFF里面是什么东西呢? 怎么才能看到? 用这个:FontCreatorPortable     ...

  5. Hdu3640-I, zombie(模拟+二分)

    The "endless" model in "I, zombie" of "Plants vs. Zombies" is my favou ...

  6. Openstack REST API

    There are some high quality resources that already cover the OpenStack API, so this is a YEA (yet an ...

  7. 相似文档查找算法之 simHash 简介及其 java 实现 - leejun_2005的个人页面 - 开源中国社区

    相似文档查找算法之 simHash 简介及其 java 实现 - leejun_2005的个人页面 - 开源中国社区 相似文档查找算法之 simHash 简介及其 java 实现

  8. WPF ICommand 用法

    基础类,继承与ICommand接口 using System; using System.Collections.Generic; using System.Linq; using System.Te ...

  9. sqlserver练习

    1.基本表的练习: create table Test( name ), age int, sex ) ) alter table Test ) alter table Test ) alter ta ...

  10. CreateFile使用方法和样例

    函数原型: HANDLE CreateFile( LPCTSTR lpFileName, //指向文件名称的指针 DWORD dwDesiredAccess, //訪问模式(写/读) DWORD dw ...