S5PV210裸机之SD卡

主流的外存设备介绍

内存和外存的区别:

一般是把这种RAM(random access memory,随机访问存储器,特点是任意字节读写,掉电丢失)叫内存,把ROM(read only memory,只读存储器,类似于Flash SD卡之类的,用来存储东西,掉电不丢失,不能随机地址访问,只能以块为单位来访问)叫外存

软盘、硬盘、光盘、CD、磁带

(1)存储原理大部分为磁存储,缺点是读写速度、可靠性等。优点是技术成熟、价格便宜。广泛使用在桌面电脑中,在嵌入式设备中几乎无使用。

(2)现代存储的发展方向是Flash存储,闪存技术是利用电学原理来存储1和0,从而制成存储设备。所以闪存设备没有物理运动(硬盘中的磁头),所以读写速度可以很快,且无物理损耗。

纯粹的Flash:NandFlash、NorFlash

(1)这些是最早出现的、最原始的 Flash 颗粒组成芯片。也就是说 NandFlash、NorFlash 芯片中只是对存储单元做了最基本的读写接口,然后要求外部的 SoC 来提供 Flash 读写的控制器以和 Flash 进行读写时序。

(2)缺陷:1、读写接口时序比较复杂。2、内部无坏块处理机制,需要 SoC 自己来管理 Flash 的坏块;3、各家厂家的 Flash 接口不一致,甚至同一个厂家的不同型号、系列的 Flash 接口都不一致,这就造成产品升级时很麻烦。

(3)NandFlash 分 MLC 和 SLC 两种。SLC 技术比较早,可靠性高,缺点是容量做不大(或者说容量大了太贵,一般 SLC Nand 都是 512MB 以下);MLC 技术比较新,不成熟,可靠性差,优点是容量可以做很大很便宜,现在基本都在发展MLC 技术。

SD卡、MMC卡、MicroSD、TF卡 
(1)这些卡其实内部就是Flash存储颗粒,比直接的 Nand 芯片多了统一的外部封装和接口。 
(2)卡都有统一的标准,譬如SD卡都是遵照 SD 规范来发布的。这些规范规定了 SD 卡的读写速度、读写接口时序、读写命令集、卡大小尺寸、引脚个数及定义。这样做的好处就是不同厂家的 SD 卡可以通用。

iNand、MoviNand、eSSD

(1)电子产品如手机、相机等,前些年趋势是用SD卡/TF卡等扩展存储容量;但是近年来的趋势是直接内置大容量Flash芯片而不是外部扩展卡。

(2)外部扩展卡时间长了卡槽可能会接触不良导致不可靠。

(3)现在主流的发展方向是使用 iNand、MoviNand、eSSD(还有别的一些名字)来做电子产品的存储芯片。这些东西的本质还是 NandFlash,内部由 Nand 的存储颗粒构成,再集成了块设备管理单元,综合了 SD 卡为代表的各种卡的优势和原始的 NandFlash 芯片的优势。

(4)优势:1、向 SD 卡学习,有统一的接口标准(包括引脚定义、物理封装、接口时序)。2、向原始的 Nand 学习,以芯片的方式来发布而不是以卡的方式;3、内部内置了 Flash 管理模块,提供了诸如坏块管理等功能,让 Nand 的管理容易了起来。

SSD(固态硬盘)

SD卡的特点和背景知识

SD卡和MMC卡的关系

(1)MMC 标准比 SD 标准早,SD 标准兼容 MMC 标准。

(2)MMC 卡可以被 SD读卡器读写,而 SD卡 不可以被 MMC读卡器 读写。

SD卡和Nand、Nor等Flash芯片差异

(1) SD卡/MMC卡 等卡类有统一的接口标准,而 Nand 芯片没有统一的标准(各家产品会有差异)

SD卡与MicroSD的区别

(1)体积大小区别而已,传输与原理完全相同。

SD卡与TF卡的区别

(1)外观上,SD卡大而TF卡小;用途上,SD卡用于数码相机等而TF卡广泛用于手机、GPS等;

(2)时间上,SD卡1999年推出,TF卡于2004年推出;SD卡由日本松下、东芝与美国SanDisk共同推出,而TF卡由Motorola与SanDisk共同推出。

(3)SD卡有写保护而TF卡没有,TF卡可以通过卡套转成SD卡使用。

SD卡的编程接口

SD卡的物理接口

(1)SD卡由9个针脚与外界进行物理连接,这9个脚中有2个地,1个电源,6个信号线。

SD协议与SPI协议

(1) SD卡与SRAM/DDR/SROM 之类的东西的不同:SRAM/DDR/SROM 之类的存储芯片是总线式的,只要连接上初始化好之后就可以由 SoC 直接以地址方式来访问;但是 SD 卡不能直接通过接口给地址来访问,它的访问需要按照一定的接口协议(时序)来访问。

(2) SD 卡虽然只有一种物理接口,但是却支持两种读写协议:SD 协议和 SPI 协议。

SPI协议特点(低速、接口操作时序简单、适合单片机)

(1)SPI 协议是单片机中广泛使用的一种通信协议,并不是为 SD卡 专门发明的。

(2)SPI 协议相对 SD 协议来说速度比较低。

(3)SD 卡支持 SPI 协议,就是为了单片机方便使用。

SD 协议特点(高速、接口时序复杂,适合有 SDIO 接口的 SoC )

(1)SD 协议 是专门用来和 SD卡 通信的。

(2)SD 协议 要求 SoC 中有 SD 控制器,运行在高速率下,要求 SoC 的主频不能太低。

S5PV210 的 SD/MMC 控制器

(1)数据手册 Section8.7,为 SD/MMC 控制器介绍。

(2) SD 卡内部除了存储单元 Flash 外,还有 SD 卡管理模块,我们 SoC 和 SD 卡通信时,通过 9 针引脚以 SD 协议/ SPI 协议向 SD 卡管理模块发送命令、时钟、数据等信息,然后从 SD 卡返回信息给 SoC 来交互。工作时每一个任务(譬如初始化 SD 卡、譬如读一个块、譬如写、譬如擦除····)都需要一定的时序来完成(所谓时序就是先向 SD 卡发送 xx 命令,SD卡 回 xx 消息,然后再向 SD卡 发送xx命令····)

S5PV210 的 SD卡 启动详解

SoC 为何要支持 SD卡 启动

(1)一个普遍性的原则就是:SoC 支持的启动方式越多,将来使用时就越方便,用户的可选择性就越大,SoC 的适用面就越广。

(2)SD卡 有一些好处:譬如可以在不借用专用烧录工具(类似Jlink)的情况下对SD卡 进行刷机,然后刷机后的 SD卡 插入卡槽,SoC 既可启动;譬如可以用 SD卡 启动进行量产刷机(量产卡)。像我们 X210 开发板,板子贴片好的时候,内部iNand 是空的,此时直接启动无启动;板子出厂前官方刷机时是把事先做好的量产卡插入SD卡卡槽,然后打到 iNand 方式启动;因为此时 iNand 是空的所以第一启动失败,会转而第二启动,就从外部 SD2 通道的 SD卡 启动了。启动后会执行刷机操作对 iNand 进行刷机,刷机完成后自动重启(这回重启时iNand中已经有 image 了,所以可以启动了)。刷机完成后 SD 量产卡拔掉,烧机 48 小时,无死机即可装箱待发货。

SD卡启动的难点在哪里(SRAM、DDR、SDCard)

(1) SRAM、DDR 都是总线式访问的,SRAM 不需初始化既可直接使用而 DDR 需要初始化后才能使用,但是总之 CPU 可以直接和 SRAM/DRAM 打交道;而SD卡 需要时序访问,CPU 不能直接和 SD卡 打交道;NorFlash 读取时可以总线式访问,所以 Norflash 启动非常简单,可以直接启动,但是 SD/NandFlash 不行。

(2)以前只有 Norflash 可以作为启动介质,台式机笔记本的 BIOS 就是 Norflash 做的。后来三星在 2440 中使用了 SteppingStone 的技术,让 Nandflash 也可以作为启动介质。SteppingStone(翻译为启动基石)技术就是在 SoC 内部内置4KB的SRAM,然后开机时 SoC 根据 OMpin 判断用户设置的启动方式,如果是NandFlash 启动,则 SoC 的启动部分的硬件直接从外部 NandFlash 中读取开头的4KB 到 内部 SRAM 作为启动内容。

(3)启动基石技术进一步发展,在 6410 芯片中得到完善,在 210 芯片时已经完全成熟。210 中有 96KB 的 SRAM,并且有一段 iROM 代码作为 BL0,BL0 再去启动 BL1( 210 中的 BL0 做的事情在 2440 中也有,只不过那时候是硬件自动完成的,而且体系没有 210 中这么详细)。

S5PV210的启动过程回顾

(1)210 启动首先执行内部的 iROM(也就是BL0),BL0 会判断 OMpin 来决定从哪个设备启动,如果启动设备是 SD卡,则 BL0 会从 SD卡 读取前 16KB(不一定是 16,反正 16 是工作的)到 SRAM 中去启动执行(这部分就是 BL1,这就是steppingstone 技术)

(2)BL1执行之后剩下的就是软件的事情了,SoC 就不用再去操心了。

SD卡 启动流程( bin 文件小于 16KB 时和大于 16KB 时)

(1)启动的第一种情况是整个镜像大小小于 16KB。这时候相当于我的整个镜像作为 BL1 被 steppingstone 直接硬件加载执行了而已。

(2)启动的第二种情况就是整个镜像大小大于 16KB。(只要大于 16KB,哪怕是17KB,或者是 700MB 都是一样的)这时候就要把整个镜像分为 2 部分:第一部分 16KB 大小,第二部分是剩下的大小。然后第一部分作为 BL1 启动,负责去初始化 DRAM 并且将第二部分加载到 DRAM 中去执行( uboot 就是这样做的)。

最重要的但是却隐含未讲的东西

(1)问题:iROM 究竟是怎样读取 SD卡/NandFlash 的?

(2)三星在 iROM 中事先内置了一些代码去初始化外部 SD卡/NandFlash,并且内置了读取各种 SD卡/NandFlash 的代码在 iROM 中。BL0 执行时就是通过调用这些 device copy function 来读取外部 SD卡/NandFlash 中的 BL1 的。

SoC支持SD卡启动的秘密(iROM代码)

(1)三星系列 SoC 支持 SD卡/NandFlash 启动,主要是依靠 SteppingStone 技术,具体在 S5PV210 中支持 steppingstone 技术的是内部的 iROM 代码。

再看 iROM application note:block device copy function

扇区和块的概念

(1)早期的块设备就是软盘硬盘这类磁存储设备,这种设备的存储单元不是以字节为单位,而是以扇区为单位。磁存储设备读写的最小单元就是扇区,不能只读取或写部分扇区。这个限制是磁存储设备本身物理方面的原因造成的,也成为了我们编程时必须遵守的规律。

(2)一个扇区有好多个字节(一般是 512 个字节)。早期的磁盘扇区是 512 字节,实际上后来的磁盘扇区可以做的比较大(譬如 1024 字节,譬如 2048 字节,譬如4096 字节),但是因为原来最早是 512 字节,很多的软件(包括操作系统和文件系统)已经默认了 512 这个数字,因此后来的硬件虽然物理上可能支持更大的扇区,但是实际上一般还是兼容 512 字节扇区这种操作方法。

(3)一个扇区可以看成是一个块 block(块的概念就是:不是一个字节,是多个字节组成一个共同的操作单元块),所以就把这一类的设备称为块设备。常见的块设备有:磁存储设备硬盘、软盘、DVD 和 Flash 设备(U盘、SSD、SD卡、NandFlash、Norflash、eMMC、iNand)

(4) linux 里有个 mtd 驱动,就是用来管理这类块设备的。

(5)磁盘和 Flash 以块为单位来读写,就决定了我们启动时 device copy function 只能以整块为单位来读取 SD 卡。

用函数指针方式调用 device copy function

(1)第一种方法:宏定义方式来调用。好处是简单方便,坏处是编译器不能帮我们做参数的静态类型检查。

(2)第二种方法:用函数指针方式来调用。

S5PV210的SD卡启动实战

任务:大于 16KB 的 bin 文件使用 SD卡 启动

(1)总体思路:将我们的代码分为 2 部分:第一部分 BL1 小于等于 16KB,第二部分为任意大小,iROM 代码执行完成后从 SD卡 启动会自动读取 BL1 到 SRAM 中执行;BL1 执行时负责初始化 DDR,然后手动将 BL2 从 SD卡 copy 到 DDR 中正确位置,然后 BL1 远跳转到 BL2 中执行 BL2.

(2)细节1:程序怎么安排?程序整个分为 2 个文件夹 BL1 和 BL2,各自管理各自的项目。

(3)细节2:BL1 中要完成:关看门狗、设置栈、开 iCache、初始化 DDR、从 SD卡复制 BL2 到 DDR 中特定位置,跳转执行 BL2.

(4)细节3:BL1 在 SD卡 中必须从 Block1 开始( Block0 不能用,这个是三星官方规定的),长度为 16KB 内,我们就定为 16KB(也就是 32 个 block );BL1 理论上可以从 33 扇区开始,但是实际上为了安全都会留一些空扇区作为隔离,譬如可以从 45 扇区开始,长度由自己定(实际根据自己的 BL2 大小来分配长度,我们实验时 BL2 非常小,因此我们定义 BL2 长度为 16KB,也就是 32 扇区)。

(5)细节4:DDR 初始化好之后,整个 DDR 都可以使用了,这时在其中选择一段长度足够 BL2 的 DDR 空间即可。我们选 0x23E00000(因为我们BL1中只初始化了 DDR1,地址空间范围是 0x20000000〜0x2FFFFFFF)。

代码划分为 2 部分( BL1和BL2 )

BL1 中的重定位

BL2 远跳转

(1)因为我们 BL1 和 BL2 其实是 2 个独立的程序,链接时也是独立分开链接的,所以不能像以前一样使用 ldr pc, =main 这种方式来通过链接地址实现元跳转到BL2.

(2)我们的解决方案是使用地址进行强制跳转。因为我们知道 BL2 在内存地址0x23E00000 处,所以直接去执行这个地址即可。

烧录启动实验

代码分为2部分启动(上一节讲的)的缺陷

(1)代码分为2部分,这种技术叫分散加载。这种分散加载的方法可以解决问题,但是比较麻烦。

(2)分散加载的缺陷:第一,代码完全分2部分,完全独立,代码编写和组织上麻烦;第二,无法让工程项目兼容 SD卡启动 和 Nand启动、NorFlash启动 等各种启动方式。

uboot中的做法

(1)第二种思路:程序代码仍然包括 BL1 和 BL2 两部分,但是组织形式上不分为 2 部分而是作为一个整体来组织。它的实现方式是:iROM 启动然后从 SD卡 的扇区 1 开始读取 16K 的 BL1 然后去执行 BL1,BL1 负责初始化 DDR,然后从 SD卡 中读取整个程序(BL1+BL2)到 DDR 中,然后从 DDR 中执行(利用 ldr pc, =main 这种方式以远跳转从 SRAM 中运行的 BL1 跳转到 DDR 中运行的BL2)。

再来分析 uboot 的 SD卡 启动细节

(1) uboot 编译好之后有 200 多KB,超出了 16 KB。uboot 的组织方式就是前面1**重点内容**6KB 为 BL1,剩下的部分为 BL2.

(2) uboot 在烧录到 SD卡 的时候,先截取 uboot.bin 的前 16KB(实际脚本截取的是8KB)烧录到 SD卡 的 block1〜bolck32;然后将整个 uboot 烧录到 SD卡 的某个扇区中(譬如 49 扇区)

(3)实际 uboot 从 SD卡 启动时是这样的:iROM 先执行,根据 OMpin 判断出启动设备是 SD卡,然后从 S卡的 block1 开始读取 16KB(8KB)到 SRAM 中执行BL1,BL1 执行时负责初始化 DDR,并且从 SD卡 的 49 扇区开始复制整个 uboot到 DDR 中指定位置(0x23E00000)去备用;然后 BL1 继续执行直到 ldr pc, =main 时 BL1 跳转到 DDR 上的 BL2 中接着执行 uboot 的第二阶段。

总结:uboot 中的这种启动方式比上节讲的分散加载的好处在于:能够兼容各种启动方式。

sd_relocate.c

#define SD_START_BLOCK  45
#define SD_BLOCK_CNT    32
#define DDR_START_ADDR  0x23E00000



typedef unsigned int bool;

// 通道号:0,或者2
// 开始扇区号:45
// 读取扇区个数:32
// 读取后放入内存地址:0x23E00000
// with_init:0
typedef bool(*pCopySDMMC2Mem)(int, unsigned int, unsigned short, unsigned int*, bool);

typedef void (*pBL2Type)(void);


// 从SD卡第45扇区开始,复制32个扇区内容到DDR的0x23E00000,然后跳转到23E00000去执行
void copy_bl2_2_ddr(void)
{
    // 第一步,读取SD卡扇区到DDR中
    pCopySDMMC2Mem p1 = (pCopySDMMC2Mem)(*(unsigned int *)0xD0037F98);
    //pCopySDMMC2Mem p1 = (pCopySDMMC2Mem)0xD0037F98);

    led2();
    delay();
    p1(2, SD_START_BLOCK, SD_BLOCK_CNT, (unsigned int *)DDR_START_ADDR, 0);     // 读取SD卡到DDR中
    led1();
    delay();
    // 第二步,跳转到DDR中的BL2去执行
    pBL2Type p2 = (pBL2Type)DDR_START_ADDR;
    p2();

    led3();
    delay();
}

start.S

.global _start                  // 把_start链接属性改为外部,这样其他文件就可以看见_start了
_start:
//run_on_dram:  
    // 长跳转到led_blink开始第二阶段
    ldr pc, =main               // ldr指令实现长跳转


// 汇编最后的这个死循环不能丢
    b .

猜你喜欢

转载自blog.csdn.net/lushoumin/article/details/82115506