weiqi7777

cortex-a8裸机系列:第十六章 iNand与SD

0
阅读(1310) 评论(0)

一、            iNand介绍

1.    iNand/eMMC/SDCard/MMCCard的关联

最早出现的是MMC卡,卡片式结构,按照MMC协议设计。相比于Nand来说,MMC有两个优势:第一卡片化,便于拆装;第二是统一了协议接口,兼容性好。

后来出现的SD卡,兼容MMC协议。SD卡较MMC卡有一些改进,如写保护,速率,容量等。SD卡遵循SD协议,有多个版本。多个版本之间是向前兼容。

iNand/eMMCSD卡的基础上发展起来,较SD卡的区别就是将SD卡芯片化了(解决卡的接触不良问题,便于设备迷你化)。

iNandeMMC的关联:MMC是协议,eMMC具备MMC协议的芯片。iNandSandisk公司符合MMC协议的一种芯片系列名称。

2.    iNand/eMMC的结构框图及其与Nand的区别

iNand内部也是由存储系统和接口电路构成(那Nand结构特性类似,不同之处在于接口电路功能不同)

iNand的接口电路负责,功能较多。如:

第一:提供eMMC接口协议,和soc的的eMMC接口控制器通信对接

第二:提供块的ECC校验相关的逻辑,也就是iNand本身自己完成存储系统的ECC功能,soc使用iNand时自己不用写代码进行ECC相关操作,大大简化了soc的编程难度。

第三:iNand芯片内部使用MLC Nand颗粒,所以性价比很高。

第四:iNand接口电路提供了cache机制,所以iNand的操作速度很快。

3.    iNand/eMMC的物理接口与SD卡物理接口区别

iNand/eMMC接口,8根数据线,一根时钟线,一根命令线。

clip_image002

SD卡,4根数据线,1根时钟线,一根命令线,一根使能线。

clip_image004

 

S5pv210本身支持4通道的SD/MMC,在九鼎开发板上,通道0接了iNand芯片,在通道2接了SD卡,通道3也接了SD卡。

对比两个的物理接口接线,结论:两个接口几乎一样,唯一的区别是SDIO线有4根,iNandIO线有8根。

因此,操作iNand芯片时和操作SD卡时几乎是一样的(物理接线几乎一样,软件操作协议几乎一样)。

 

结论:iNand/eMMC其实就是芯片化的SD/MMC卡,软件操作和SD卡相同。

分析iNand芯片的操作代码时,其实就是以前的SD卡的操作代码。一些细节的区别就是为了区分各种不同版本的SD卡、iNand的细节差异。

二、            SD/iNand操作

1.    硬件接口:DATACLKCMD

iNandDATA8根,支持148并行传输模式;SDDATA4根,支持14并行数据传输。

CMD用来传输命令,CLK用来传输时钟。

接口有CLK线,工作时主机soc通过CLK线传输时钟信号给SD/iNand芯片。说明:SD/iNand是工作在同步模式下,SD/iNand的工作速率是由主机给他的CLK频率决定的。

2.    命令响应的操作模式

命令从主机发到卡,响应从卡到主机。

clip_image006

         SD协议事先定义了很多标准命令(CMD0CMD1,。。。。),每个命令都有它的作用和使用条件和对应的响应。SD卡工作的时候就是一个一个的命令周期组合起来的,在一个命令周期中,主机先发送CMDSD卡,然后SD卡解析这个命令并且执行这个命令,然后SD卡根据结果回发给主机soc一个响应。(有些命令是不需要响应的,这时候SD卡不会给主机回发响应,主机也不用等待响应)。标准的命令+响应的周期中,主机发完一个命令后,应该等待SD卡的响应而不是接着发下一条命令。

 

clip_image008

三、            SD/iNand的体系结构图

clip_image010

         SD卡内部有一个接口控制器,这个控制器类似于一个单片机(据说是51单片机),这个单片机的程序功能就是通过CMD线接收外部主机soc发给SD卡的命令码,然后执行这个命令并且回发响应给数据soc。这个单片机处理命令及回发响应遵循的就是SD协议。这个单片机同时可以控制SD卡内部的存储单元,可以读写存储单元。

四、            SD/iNand的寄存器(重点是RCA寄存器)

这里的寄存器是指SD卡内部的寄存器,而不是主机socSD控制器的寄存器。(很多外置芯片内部都是有寄存器的,这些寄存器可以按照一定的规则访问,访问这些寄存器可以得知芯片的一些信息)

寄存器如下:

                  clip_image011

         RCArelative address,相对地址寄存器)。访问SD卡时,实际上SD内部的存储单元的地址没有绝对数字,都是使用相对地址。相对地址由SD卡自己决定的,存放在RCA寄存器中。

五、            SocSD/MMC/iNand控制器简介

不同的soc可能在SD/MMC/iNand等支持方面有差异,但是如果支持都是通过内部提供SD控制器来支持的。

         S5pv210SD卡控制器在1031页。特性如下:

clip_image013

六、            SD/iNand程序分析

1.    SD卡工作在命令码+响应的模式下

使用宏定义进行命令的定义。

SD协议的命令分两种:CMDxACMDxCMD是单命令,就是单独发一个CMD可表示一个意思。ACMD是一种扩展,就是发两个CMD加起来表示一个意思。可以认为ACMDx = CMDy y一般是55+ CMDz

clip_image014

 

2.    卡类型识别SD or MMC

MMC协议、SD协议、eMMC协议本身是一脉相承的,所以造成了一定的兼容性,所以当soc控制器工作时连接到soc的可能是一个MMC卡、也可能是SD卡、也可能是iNand芯片。主机的soc需要取识别这个卡到底是什么版本的卡。

clip_image016

使用宏定义定义了一些类型。

因为不同版本的卡内部协议是不同的,所以对卡识别命令的响应也是不同的,soc通过发送一些命令,听取响应就可以根据不同的响应判断卡的版本

3.    卡状态

SD卡内部的接口控制器类似于一个单片机,这个单片机的工作其实是一个状态机。所以SD卡任何时候都有一种状态(空闲状态、准备好状态、读写状态、出错状态。。。都是实现定义好的),在这种状态下,能够接收的命令是一定的,接收到命令后执行一定的操作然后根据操作结果会跳转为其他状态。如果主机发送的命令和当前状态不符合,那状态机就不响应。如果收到的命令和当前状态相符,就会执行响应操作,执行完毕后,根据结果跳转为另外的状态。

clip_image018

如上图,有若干个状态,在每个状态可以执行特定的操作。

使用宏定义卡的状态

clip_image020

 

4.    卡回复类型

一般来说,SD卡的命令都属于:命令+响应的模式。也是有极少数的SD卡命令是不需要回复的。

卡回复有多种类型,每种卡回复类型都有自己的解析规则。然后卡在特定状态下响应特定命令时有可能回复的响应都是SD协议事先规定好的。

如下,使用宏定义定义响应。

clip_image022

 

5.    Linux内核风格的寄存器定义

使用基地址加偏移来进行寄存器的定义。

clip_image024

使用以下四种方式来定义寄存器。

clip_image025

其中vu_xxx,是通过typedef定义的别名。

clip_image026

 

6.    SD控制器初始化  int Hsmmc_Init(void)

1)     GPIO初始化

clip_image028

使用宏编译,选择编译哪一通道的SD/MMC的代码。

以通道0为例,查看原理图,得知接到通道0iNandMMC接口和GPG0GPG1复用,所以首先要设置这些GPIOSD/MMC功能。

clip_image030

         查看210数据手册,GPG0,SD有关。

clip_image032

GPG1,可以当做SDDATA[7:4]:

clip_image034

设置管脚为SD功能,开启上拉,设置驱动强度为最强

clip_image036

 

2)     SD控制器时钟设置

两个寄存器比较重要,SRC寄存器(控制源时钟选择),DIV(控制对源时钟的分频)。

clip_image038

clip_image040

CLK_SRC4的最低16位控制SD/MMC4个通道的时钟源选择。

clip_image042

         CLK_DIV416位控制SD/MMC4个通道的对时钟源分频。

clip_image044

clip_image046

选择时钟源为SLCKEPLL,分频值为2,所以SCLK_MMCC0-3的时钟是48M

 

3)     SD控制器进行全复位

这个复位不是复位SD卡,复位SD卡需要发送命令,而是复位SD控制器,并判断复位是否结束。这一步操作和socSD控制器有关,有的不需要复位。

clip_image048

SWRSTx寄存器有4个,每个对应各自的通道。

clip_image049

3种复位,一种是复位数据,一种是复位命令,一种是都复位。这里是进行都复位,也就是将寄存器的最低位置1。在复位期间这一位一直为1,当复位结束后,这一位会为0,所以判断这一位为0,说明复位结束。

clip_image051

clip_image053

 

4)     设置SD卡的时钟

SD卡内部没有时钟,需要外部提供时钟,因为需要设置外部提供给SD卡的时钟,也就是MMC_CLK

此时刚开始和SD卡通信,soc不清楚SD卡属于哪个版本(高版本和低版本的读写速率不同,高版本的可以工作在低版本的速率下,而低版本的SD卡不能工作在高版本的速率下),所以先设置外部SD卡的时钟为低速率40K时钟,以便和SD卡通信,后面根据读取SD的类型,在设置时钟。

clip_image055

对于Hsmmc_SetClock函数,这个是设置MMC_CLK的时钟。

操作为以下几步:

第一步:关闭时钟

第二步:设置时钟

第三步:开启时钟

clip_image057

对于Hsmmc_ClockOn函数,有两个参数,1表示开启时钟,0表示关闭时钟。

clip_image059

主要是和CLKCON寄存器打交道。该寄存器也有4个,分别对于不同通道的SDCLK设置。

clip_image060

这里用到的是第2位和第3位。第2位控制外部SD卡的时钟是否使能。使能之后,时钟不是马上就稳定的,需要检测第3位,为1说明时钟稳定,为0说明时钟不稳定,需要等待。

clip_image062

 

设置外部SD时钟。主要和CONTROL2CONTROL3寄存器有关系。根据要设置的时钟值,设置CONTROL3。这里主要是设置反馈时钟模式。当外部SD卡时钟较高时,对于时钟要进行反馈,为了时钟的准确,会对时钟进行校准。对于频率比较低的时钟,不需要使用反馈时钟。

clip_image064

clip_image066

         设置反馈模式后,需要开始反馈时钟,就在CONTROL2寄存器中设置。也就是14位和15位要置1,使能反馈时钟。

clip_image068

         时钟源选择SCLK_MMC,也就是48M时钟。

clip_image070

         将最高两位置1

clip_image072

设置外部SD时钟的分频值,以设置外部的时钟。

clip_image074

clip_image076

这里采用一个C语言技巧,来得到分频值。先得到48MH/2^n 最接近设置时钟的n值。然后再将该值处理写入到CLKCON寄存器的[15:8]位,以设置分频值。

并开启内部时钟。

clip_image078

      时钟设置完毕后,检测内部时钟是否稳定,最后使能外部SD时钟。

clip_image080

5)     设置超时时间和速度模式

clip_image082

clip_image084

寄存器设置超时时间,用于数据线超时检测。超时后,会在中断状态寄存器标明。使用的时钟是TMCLK

 

6)     设置控制器寄存器

clip_image085

设置物理特性。如数据模式,命令数据什么边沿输出,DMA使用以及额外的数据位宽扩展等。

clip_image087

程序中将第2位清零,表明主机的命令和数据输出都是在时钟的下降沿变化,因为对于外部SD/MMC卡,命令和数据是上升沿有效,对于socSD/MMC控制器来说,命令和数据就需要在时钟下降沿变化,以满足数据时序的建立/保持时间。

 

7)     清除中断标志位

两个寄存器。

clip_image089

NORINTSTS 普通中断状态寄存器,当对应中断开启后,会将对应状态位会置1,写入1,清除中断标志位。初始化的时候,需要将之都清除。

 

 

clip_image091

ERRINTSTS :错误中断状态寄存器,发生错误,如果错误使能,会将对应位置1。初始化需要置1,清除错误中断状态位。

clip_image093

8)     中断、错误使能

clip_image095

         将所有中断、错误都使能。

7.    发送命令函数

对于发送命令Hsmmc_IssueCommand函数。

clip_image097

需要检测是否可以发命令,这个查看寄存器PRNSTS,最低两位,一个判断数据线,一个判断命令线。发送命令前,需要检查是否能够发命令,也就是看这个寄存器的第0位。

clip_image099

clip_image101

         如果命令还需要数据线参与,那么还需要检查数据线是否可以发送数据。

写入参数,每个命令都是带有参数的。

clip_image103

 

写命令:

clip_image105

     该寄存器CMDREG命令寄存器,往这个寄存器写值,SD控制器会把命令和参数给发送给SD卡。

clip_image106

     [13:8]位是命令。

clip_image108

     后面的位是说明命令的。

clip_image110

clip_image112

     Command type是命令的类型。不同的命令,这个地方要写入不同的值。

clip_image114

     DATAPRNT 数据选择,有的命令需要数据线参与,需要数据线参与的,这一位要置1

clip_image116

     ENCMDIDC: 使能响应的索引检查。响应中有一个索引和目录的索引是一样的,可以通过检查该索引,判断是否有错误。

clip_image118

ENCMDCRC: 检查响应的CRC

clip_image120

RSPTYP: 响应数据的长度。

 

将数据写入到命令寄存器后,SD控制器会将该命令发送出去,并自动读取响应到寄存器CMPRSP中。CMPRSP寄存器有4个。

clip_image122

 寄存器的内容:

clip_image124

     对于不同的响应,值存的地方不一样。

clip_image126

 

 

命令发送完毕后,需要等待命令结束。

clip_image128

对于Hsmmc_WaitForCommandDone函数。

clip_image130

  其实就是读取NORINTSTS寄存器的15位,当传输出现错误后,该位会置1。出现错误后,读取错误中断状态寄存器,得到错误号返回。

clip_image132

         如果命令传输成功后,NORINTSTS寄存器的第0位会置1,表示命令完成。

clip_image134

 

         经过以上的操作,命令发送就结束了。返回0,说明命令发送成功。

8.    SD卡初始化序列

初始化序列根据下图来进行。

clip_image136

发送CMD0,复位SD卡。

clip_image138

发送CMD8,判断是否有响应。

clip_image140

       无响应。会出现超时,于是ERRINTSTS寄存器的最低位会为1,说明没有响应。而发送命令函数,如果没有响应,会将这个ERRINTSTS寄存器的值给返回回来,为1,说明未响应,可能是SD1.0版本,或者是没有卡。

       然后发送ACMD41命令,而发ACMD41命令,其实是两个命令的组合,一个CMD55,一个CMD41,如果有响应,说明是SD1.0卡,没有响应说明识别卡错误。

clip_image142

       对于有响应,发送命令函数会返回0,执行else的程序。

clip_image144

       读取响应,判断卡支持的电压,如果电压不对,返回错误。然后再发送ACMD14命令,读取响应,判断卡的类型。

当判断卡的类型后,需要发送CMD2CMD3。让卡就绪。

clip_image146

发送CMD3,读取RCA的值,SD卡进入stand-by状态。

发送CMD7SD卡进入transfer状态。

最后获取SCR

然后根据SCR的类型,设置外部SD卡的时钟。

clip_image148

 

clip_image150

         设置数据位宽为4

clip_image152

         发送CMD16,设置块长度为512字节。读取SD卡的CSD寄存器,得到卡的一些信息。返回0表示初始化成功。

         初始化完后,SD卡进入transfer状态了。

clip_image154

         初始化不成功的话,返回-1

9.    SD卡操作

SD卡的操作就根据以下的图来进行操作了。

clip_image156

发送CMD3命令后,SD卡进入stand-by状态了。要对SD卡进行读写,要进入transfer状态,发送CMD7命令。所以初始化中,发送完CMD3命令后,再发送CMD7命令,SD卡进入transfer状态,就可以进行读写了。

1)     SDblock

对于Hsmmc_ReadBlock函数

clip_image158

先将中断和错误都清掉。

clip_image160

函数能实现读多块的功能,所以外面有一个while循环,判断多块读是否完成。SD卡一次最多能够读65536块(由SD卡控制器决定),当需要读的块数大于65536后,就要分多次读。

clip_image162

BLKSIZE寄存器,设置块大小,以及DMA数据长度。将块大小设置为512字节。DMA没有使用的话,设置为最大长度。

clip_image164

clip_image166

clip_image168

 

CLKCNT寄存器,设置传输的块数。

clip_image169

clip_image171

在多块数据传输时,这个寄存器每传输完一块,就会减一,减到0,就停止数据传输。

要设置这个值,必须是要没有数据传输的时候设置。在数据传输过程中,读这个寄存器返回非法的数,写这个寄存器无效。这里能传输的最大块数为65535,所以之前的程序需要对传输的块数进行处理。

clip_image173

设置读的地址。对于SDHC卡,地址是块地址。对于V1V2版本,是字节地址,所以需要块 * 512,得到字节地址。

clip_image175

得到下一次读块的地址。

         写入命令参数,对于读SD,参数是读取数据的地址。

 

 

 

clip_image177

         这里,读分成两种,一种是读一块,一种是读多块。

         读一块使用的命令是CMD17,第多块使用的命令是CMD18

 

TRNMOD寄存器,设置传输模式。

clip_image178

clip_image180

clip_image182

       第五位:MUL1SIN0 ,多块操作使能。对于读一块,设置为0。对于读多块,要设置为1。每读取一块数据,BLKCNT寄存器会减一,当减到0的时候,读取结束。

         第四位:  RD1WT0 , 数据传输模式, 1读,0是写。 对于读操作,设置为1.

         第二位: ENACMD12, 数据传输接收后,是否自动发送ACMD12命令。对于多块操作,需要ACMD12命令来停止传输。多块传输中,最后一个块传输后,如果开启这一位,会自动发送ACMD12命令。

         第一位:ENBLKCNT 使能多块计数。使能后,传输一块后,CLKCNT会减一。

         0位:ENDMA 使能DMA

 

         设置好传输模式后,发送对应的命令。

clip_image184

         命令发送完毕后,需要等待命令操作完成。

 

clip_image186

         读取多块数据。

         判断读是否准备好。

clip_image188

         判断NORINTSTS寄存器的第5位。为1,表示读缓冲可以使用。

clip_image190

 

 

clip_image192

         因为参数提供的内存地址是char *型,所以先判断地址是否4字节对齐。然后分成不对齐和对齐处理。

         对于BDATA寄存器,这是一个soc内部的寄存器,当读该寄存器时,SD控制器会自动从SD卡读取4个字节数据放入到这个寄存器中。所以读这个寄存器得到32位数据。

如果内存地址对齐,需要将内存地址强制转化为uint32_t类型,写入一次,地址加4。如果内存地址不对齐,就只能一个字节一个字节的操作。

clip_image194

 

         块数据读取结束后,需要判断传输是否结束。

clip_image196

         判断NORINTSTS寄存器的第1位。为1,表示传输完成。

clip_image198

clip_image200

clip_image202