xxx_mmc_init流程:
|power up sd_card|给卡上电
|
\|/
|reset controller/fifo/dma|执行控制器复位/fifo复位
|
\|/
|清除所有状态寄存器|实际是复位硬件的状态机
|
\|/
|屏蔽中断寄存器| 比如设置中断掩码及使能寄存器
|
\|/
|FIFO相关设置|
|
\|/
|禁止时钟|
注意:这个init函数可能被重复调用,比如需要重新初始化SD控制器时,比如altera的preloader初始化一次后,u-boot中也会再次初始化一次,共两次。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Q:为什么使用内部DMA之后,传输速度可以提升?
A:因为在u-boot中CPU访问SD控制器寄存器和数据内存没有开cache,性能不高,但是dma完全不受MMU管控,直接和内存打交道
并可以配置DMA burst,获取比cpu更高的访问内存性能.
一般DMA对源和目标地址有要求,比如32位地址对齐之类的。u-boot中用宏ALLOC_CACHE_ALIGN_BUFFER定义这样的buffer。
Q: sd 卡识别模式最大频率是多少?
A: 最大设置为400k,因为某些卡识别模式时,有工作频率限制。
命令类型:
I)广播命令
II)寻址命令
数据格式:
I)数据包格式--常规数据 先发送低地址的字节,然后发送高地址的字节;字节内部先放高位(bit7 bit6...bit1 bit0),再发低位。
II)宽幅数据---SD寄存器 先发最高位,依次发送到最低位。比如bit
class 0 :初始化,识别命令
CMD0 复位SD卡
CMD1 用来识别MMC卡的命令,用在CMD8命令之后,CMD8命令探测到卡既不是SD2.0又不是SD1.X,则用CMD1探测是否为MMC卡
ACMD41:
I)读取OCR寄存器(cmdarg 中电压窗口的值为0);
II)执行卡的初始化序列(窗口电压非零),同时在R3响应中也包含OCR寄存器,所以实际代码中直接使用这个功能
CMD9 读取CSD寄存器
CMD2 读取CID寄存器
CMD12 停止读多块数据是的数据传输
CMD13 读card_status寄存器
class 2: 读卡操作命令
CMD16 设置块的长度
CMD17 读单个块
CMD18 读多个块,直到主机发送CMD12为止
class 4: 写卡操作命令
CMD24 写单块
CMD25 写多块
CMD27 写CSD寄存器
class 5: 擦除命令
CMD32 设定擦除块的起始地址
CMD33 设定擦除块的结束地址
CMD38 擦除选择的块
class 6: 写保护操作
CMD28 设置写保护块地址 (标准容量卡支持,SDHC不支持)
CMD29 清除写保护块地址 (标准容量卡支持,SDHC不支持)
CMD30 写保护
ACMD51 读取SCR寄存器,即卡配置寄存器
CMD6 在SD1.10以上是必须支持的命令,该命令用于切换或扩展内存卡功能的。比如支持高速卡的功能,在group1 fucntion 1 SDR25即50MHz
CMD6是带数据读命令,需要传输的数据有512bit,16个字节。MODE 0(Check Function), MODE 1(Set Function)
CMD6是宽幅数据格式(512),先发送的是bit511....bit0;用8个32位的整数数组接收这样的数据时要注意了。
u32 switch_status[16];
32bit 32bit
bit487~bit480 bit495~bit488 bit503~bit496 bit511~bit504 ...... bit7~bit0 bit15~bit8 bit23~bit16 bit31~bit24
switch_status[0] ...... switch_status[16]
每个32位内存单元存储低地址放的高位数据(大端格式),这是由SD协议决定的;所以需要转成cpu格式的,在u-boot中调用字节调换宏。即大端转小端格式。
而CMD2和CMD9读CID和CSD寄存器时,是从response中得到数据的,而且response是从SD控制器的响应的寄存器中得到的,实际上已经被控制器调整完顺序了。
-------SD2.0-----
SDR12 --- 25MHZ 12.5MB/s
SDR25 --- 50MHz 25MB/s
-------SD3.0-----
SDR50 --- 100MHz 50MB/s
SDR104 --- 208MHz 104MB/s
DDR50 --- 50MHz 50MB/s
MMC卡
标准 26MHz
高速 52MHz
SDSC(<=2GB),SDHC(2GB-32GB), SDXC(32GB-2TB) CMD17,CMD18 对应的cmdarg是32位块地址,所以4G(块地址)x512 = 2TB max
SPI模式下的CRC校验是忽略的,但是CRC码也是要发送的,可以初始化为0x0或0xff
命令格式:48位
0 1 content CRC7 1
start bit transmission bit cmd + cmd_arg 7bit stop bit
响应格式:48位或136位
48位:
0 0 content CRC7 1
start bit transmission bit stop bit
136位:
0 0 CID or CSD CRC7 1
start bit transmisssion bit 7bit stop bit
SD响应类型:
谁的响应 长度 CRC7
R1 48 有
R1b 48 有
R2 CID,CSD 136 有
R3 OCR(ACMD41的响应) 48 无----------特例
R6 RCA 48 有
R7 CMD8的响应 48 有
1、CSD寄存器的版本?作用?
CMD9访问;首先读取CSD的版本号(bit127-bit126);有v1.0和V2.0两个版本;从CSD寄存器可以获取卡的读写块大小(一般512),容量大小,频率。
2、OCR寄存器作用?
ACMD41访问;可以获取SD卡的工作电压;以及容量信息(CCS--Card Capacity Status)
3、SCR寄存器的作用?
ACMD6访问;可以用来切换总线宽度,1bit或4bit;返回的数据(SCR寄存器内容)是大端格式的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SD识别过程:
调用具体sd controller的初始化函数
|
\|/
CMD0复位SD CARD
|
\|/
CMD8(send_if_cond查询卡电压范围)发送版本查询命令(resp = 0x01表示SD2.0;resp = 0x05表示SD1.0),ACMD41之前必须发此命令。
|
\ |/
ACMD41(初始化SD卡,同时获取ocr寄存器(R7))
|
\|/
CMD2(读取CID信息) (identify mode)
|
|
CMD3(SD卡则读取RCA寄存器,取RCA寄存器高16位作为RCA地址
|
\|/
成功的话则进入(standby mode)
|
\|/
CMD9(读CSD信息)
|
\|/
CMD13(读CARD_STATUS),确认一下卡的状态
|
\|/
CMD7(转卡进入transfer mode)
|
\|/
ACMD51(读取SCR寄存器,是否支持4bit)
|
\|/
CMD6查询是否支持高速模式
|
\|/
如果支持高速,CMD6设置高速模式
|
\|/
可以发送其他读写和擦除命令了,比如读取MBR块的数据,分析SD的分区表信息
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sending CMD0 ---复位SD 卡
Sending CMD8 ---查询卡状态
Sending CMD55 ---应用命令
Sending CMD41 ---
Sending CMD55
Sending CMD41
Sending CMD55
Sending CMD41
Sending CMD2 --- CID 读卡的厂商信息
Sending CMD3 --- 设置RCA 给sd卡分配一个地址
Sending CMD9 --- CSD
Sending CMD13 --- 读卡状态
Sending CMD7
Sending CMD55
Sending CMD51
Sending CMD6
Sending CMD6
Sending CMD55
Sending CMD6
freq=50000000
Sending CMD16
Sending CMD17
Sending CMD16
Sending CMD18
Sending CMD12
上面命令的具体分析:
------------------识别模式------------------------------------------------------------------------------------------------------------------------------------------------------------
freq=400000
Sending CMD0,cmdarg=0x0 ---复位SD 卡;卡处于默认相对卡地址,一个默认时钟400KHz;(IDLE模式)
*********** 没有response
Sending CMD8,cmdarg=0x1aa ---查询卡状态,SD 2.0新增命令,可以判断是否为sd 2.0;同时检查SD卡工作电压范围是否在2.7-3.6V之间(bit8 = 1),是的话,返回R7响应
response[0] =0x1aa *********** R7 (aa是check pattern,协议建议值)
Sending CMD55,cmdarg=0x0 ---应用命令
response[0] =0x120 *********** R1
Sending CMD41,cmdarg=0x40300000 ---这里u-boot直接设定驱动中的电压,这里启动初始化序列,而不是读取OCR寄存器操作(cmdarg : OCR_HCS = 1(bit30), bit20,bit21 == 3.2~3.3V, 3.3V~3.4V)
response[0] =0xff8000 ***********响应表示卡忙bit31(busy) == 0 OCR寄存器的值包含在R3中,即响应中(R3)
Sending CMD55,cmdarg=0x0
response[0] =0x120
Sending CMD41,cmdarg=0x40300000
response[0] =0xc0ff8000 ***********响应表示卡不忙bit31(busy) == 1; (大容量卡 > 2GB), (标准卡 <= 2GB) (R3)
Sending CMD2,cmdarg=0x0 --- 读CID(读卡的厂商信息),不需要arg参数,是针对所有挂载SD总线上的SD卡的;CMD10用于读取特定RCA地址的卡CID信息;(Identify Mode)
response[3 2 1 0]=0xf500d297 0x2198033 0x43617264 0x824a544e
注意U-boot中 bit31~bit0 bit63~bit32 bit95~bit64 bit127~bit96
*********** response[0]存放的bit127~bit96,因为SD卡协议规定响应是从高位开始传输的,
所以接收到应该从高32开始,但是奇怪的是32位数据不是大端格式的,而是小端格式的 (R2)
应该是SD控制器的response寄存器已经调整了每个32位数据的大小端格式的
Sending CMD3,cmdarg=0x0 --- 设置RCA 给sd卡分配一个地址(16位地址);这里成功后,卡进入数据传输模式
response[0] =0x59b40520 *********** SD卡通常可以从RCA寄存器中读到,而MMC卡一定要我们自己设定,u-boot中设定为1(R6)
------------------------进入standby mode-------------------------------------------------------------------------------------------------------------------------
Sending CMD9,cmdarg=0x59b40000 --- 读CSD
response[3 2 1 0]=0xa4000c1 0x75cd7f80 0x5b590000 0x400e0032
bit31~bit0 bit63~bit32 bit95~bit64 bit127~bit96
*********** 容量((0x75cd + 1)<<(8+2))*512 = 16GB (R2)
Sending CMD13,cmdarg=0x59b40000 --- 读卡状态,响应格式请参考卡SD卡规范的4.10.1;这里主要检查卡是否处于准备接受数据(MMC_STATUS_RDY_FOR_DATA(bit8)),以及确定当前的状态不是program状态(bit9-bit12)
response[0] =0x700 *********** R1
Sending CMD7,cmdarg=0x59b40000 --- 选中RCA = 0x59b4的SD卡,把它的状态置为传输模式(transfer mode),任何时刻只能有一个卡处在传输模式(这个命令很重要),否则卡standby mode
response[0] =0x700 *********** R1
-------------------数据传输模式(从这里开始,必须使用RCA地址访问SD卡了)------------------------------------------------------------------------------------------------
Sending CMD55,cmdarg=0x59b40000 --- 卡寻址(点对点寻址)
response[0] =0x920
Sending CMD51,cmdarg=0x0 --- ACMD51,SCR寄存器;这里采用的是数据传输(大端格式);是从dat线上返回的数据;而respone是在cmd线上传输的
response[0] =0x920 *********** R1
Sending CMD6,cmdarg=0xfffff1 --- CMD6 check function,总共有6个组(group 1~6, 4 bits per group),每个组16个功能;这里也是采用数据传输的方式(大端格式)
response[0] =0x900
Sending CMD6,cmdarg=0x80fffff1 --- CMD6 set function设置功能;这里设置group1, function 1(SDR25即50MHz)
response[0] =0x900 *********** R1
Sending CMD55,cmdarg=0x59b40000 --- CMD55
response[0] =0x920 *********** R1
Sending CMD6,cmdarg=0x2 --- ACMD6,用于切换数据线宽度的,默认是bus_width = 1; 可以使用它切到bus_width = 4;cmdarg[10]=00(1bit),10(4bit);
且数据宽度的顺序是:I)应该先用ACMD6且SD卡的数据宽度;II)然后把SD控制器这边对应的控制寄存器位改成4bit
response[0] =0x920 *********** R1
freq=50000000
Sending CMD16,cmdarg=0x200 --- 设定块长度,这里设定块长为512字节;(这里是init_part函数调用使用的命令,读取MBR数据)
response[0] =0x900
Sending CMD17,cmdarg=0x0 --- 单个块读命令,cmdarg指定从第0块(32位块地址)读;注意标准容量和大容量卡对cmdarg地址解析不同;
大容量卡以块为单位,而标准容量卡以字节为单位
response[0] =0x900
Sending CMD16,cmdarg=0x200 --- 设置块长度
response[0] =0x900
Sending CMD18,cmdarg=0x1 --- 多块读命令,cmdarg是指定读块地址(32位),这里从第1块
response[0] =0x900
Sending CMD12,cmdarg=0x0 --- CMD12 多块读停止命令
response[0] =0xb00
================================================================================================================
SD卡信息:
SONY 16G CLASS 10:
SOCFPGA_CYCLONE5 # mmcinfo
Device: ALTERA DWMMC
Manufacturer ID: 82
OEM: 4a54
Name: NCard
Tran Speed: 50000000
Rd Block Len: 512
SD version 2.0
High Capacity: Yes
Capacity: 14.7 GiB
Bus Width: 4-bit
Kingston 4GB class 4:
SOCFPGA_CYCLONE5 # mmcinfo
Device: ALTERA DWMMC
Manufacturer ID: 41
OEM: 3432
Name: SD4GB
Tran Speed: 50000000
Rd Block Len: 512
SD version 2.0
High Capacity: Yes
Capacity: 3.7 GiB
Bus Width: 4-bit
=================================================================================================================
列出文件系统里的文件:
SOCFPGA_CYCLONE5 # fatls mmc 0:1
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20d851
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
2694296 uimage
7999 socfpga.dtb
11075584 jffs2.img
3 file(s), 0 dir(s)
===========================================================================================
读取文件至内存:
SOCFPGA_CYCLONE5 # fatload mmc 0:1 0x4000000 socfpga.dtb
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x0
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
reading socfpga.dtb
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20d800
response[0] =0x900
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20d851
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20d801
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD18,cmdarg=0x20ed05
response[0] =0x900
Sending CMD12,cmdarg=0x0
response[0] =0xb00
Sending CMD16,cmdarg=0x200
response[0] =0x900
Sending CMD17,cmdarg=0x20ed14
response[0] =0x900
7999 bytes read in 110 ms
(70.3 KiB/s)
7999 bytes read
===================================================================================================