首先,分析几种存储:
1>几种存储器
SRAM:SRAM(Static Random Access Memory),即静态随机存取存储器。它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据。SRAM主要用于二级高速缓存(Level2 Cache)。它利用晶体管来存储数据。与DRAM相比,SRAM的速度快,但在相同面积中SRAM的容量要比其他类型的内存小。
部分ARM9的CPU内部都集成有一个SRAM,SRAM是英文Static RAM的缩写,它是一种具有静止存取功能的内存,不需要刷新电路即能保存它内部存储的数据。这样他不需要初始化就能够直接使用。这与我们在外部扩展的大容量的SDRAM是不一样的,外部大容量的SDRAM是需要初始化后才能使用的,这点大家务必要搞清楚。
s3c2410(arm920t),s3c2440(arm920t),at91rm9200(arm920t),at91sam9260(arm926t)上都是这样的。在s3c2440这颗CPU上这个SRAM大小为4KB,datasheet里把它叫做Stepping Stone,江湖人称“起步石”。
SDRAM:同步动态随机存储器,同步是指 Memory工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;动态是指存储阵列需要不断的刷新来保证数据不丢失;随机是指数据不是线性依次存储,而是自由指定地址进行数据读写,用作内存。
NORFLASH:NOR FLASH地址线和数据线分开,来了地址和控制信号,数据就出来。NORFLASH像内存一样是直接挂在系统总线上的,这样有足够多的地址线使得CPU能够寻址到每一个存储单元上去,这也意味着CPU能够直接通过总线访问NORFLASH上存储的内容,同时他还支持XIP(即片上执行,不用将代码搬到内存中,直接在NORFLASH上就能运行)。
NANDFLASH:NANDFLASH它并不是直接挂载系统总线上,而是通过NANDFLASH控制器(这个一般集成在CPU内部)来完成读写操作的。如果我们把NANDFLASH的那种寻址方式叫直接寻址的话(不是汇编里的那个直接寻址,这里指CPU能够直接通过地址线访问存储器的存储单元),那么这里的NANDFLASH就是间接寻址(这里需要NANDFLASH控制器来寻址)。所以我们在使用NANDFLASH之前,一定要初始化NANDFLASH控制器。
2>NOR与NAND的性能区别
NOR的传输效率很高,在1~4MB的小容量时具有很高的成本效益,但是很低的写入和擦除速度大大影响了它的性能。 NAND结构能提供极高的单元密度,可以达到高存储密度,并且写入和擦除的速度也很快。应用NAND的困难在于flash的管理和需要特殊的系统接口。
● NOR的读速度比NAND稍快一些。
● NAND的写入速度比NOR快很多。
● NAND的4ms擦除速度远比NOR的5s快。
● 大多数写入操作需要先进行擦除操作。
● NAND的擦除单元更小,相应的擦除电路更少。
启动过程:
1>从NOR启动
NORFLASH被映射到0x00000000地址(就是nGCS0,这里就不需要片内SRAM来辅助了,所以片内SRAM的起始地址还是0x40000000). 然后CPU从0x00000000开始执行(也就是在NORFLASH中执行)。
2>从NAND启动
CPU会自动从NANDFLASH中读取前4KB的数据放置在片内SRAM里, 同时把这段片内SRAM映射到nGCS0片选的空间(即0x00000000)。CPU是从0x00000000开始执行,也就是NAND FLASH里的前4KB内容。因为NAND FLASH连地址线都没有,不能直接把NAND映射到0x00000000,只好使用片内SRAM做一个载体。通过这个载体把NANDFLASH中大代码复制到RAM(一般是SDRAM)中去执行。
另外,U-Boot有一个Download to SDRAM& Run这个选项,这个选项是把程序下载到SDRAM然后跳转到SDRAM开始执行。所以在做实验的时候,要考虑是要下载到NORFLASH中还是NANDFLASH中还是SDRAM中运行,代码是稍稍有点区别的。比如要下载到SDRAM中程序,它的开始地址是0X30000000,如果程序中有绝对地址跳转,就要考虑更改地址的值到底是多少,当然了,b和bl这样的相对跳转是没有影响的。如果要下载到NORFLASH中,它的开始地址是0X00000000,而且可以直接在NORFLASH中运行。如果是在NANDFLASH中运行,就要考虑程序是不是大于了4K。
我在学习过程中就遇到了一个类似的问题,就是做按键控制LED灯的亮灭的程序。因为我一开始没有意识到这个问题,就在下载的时候直接选择了Download to SDRAM & RUN,怎么都看不到按键控制LED的效果,纠结了好久,还以为是代码写错了(其实如果是下载到SDRAM,确实是写错了),后来突然想到,下载到NANDFLASH试一试,然后果然就好了。最后看到后面的章节才意识到地址的问题,然后修改了跳转到main函数前设置SP的地方,一开始是把SP设置为0,然后修改为0X34000000,然后下载到SDRAM& RUN就正常了。
这个经历让我对地址这个东西有了新的认识,以及编译选项中有一个-Ttext选项,我对于这个按键控制LED的程序修改了这个编译选项,发现没什么影响,因为这个是编译选项,影响的是编译过程,程序中如果知识相对跳转,所以不会有什么影响。但是后面有一个SDRAM的实验,就是跳转到SDRAM中执行的那条指令是绝对地址跳转的,-Ttext后面的选项不同给点话那个地址会发生变化,也就对程序产生了影响。做实验的时候一定不能仅仅是照抄,抄程序是我们学习的第一步,但是后面要转化为自己的东西还是要自动动手去实验的,去改变一些东西进行实验,能够发现更多的问题,因为教程是大众化的,不可能针对所有问题所有人,细节的东西还是需要自己好好的去挖掘。
要分析arm2440的启动流程,先得了解arm2440的硬件配置,在arm2440这款cpu里面没有什么存储的芯片,除了以个4kb的SRAM(静态存储器可以运行程序,但是最重要的一点就是掉电就失掉所有的数据)注意这4kb是cpu自己的不是外设的的。好了现在讲述下启动的流程。(一下是从nand flash 启动)
1、首先机器上电,从外部的nand flash 的0x0000-0x01000也就是前4kb的内容通过硬件的办法来拷贝到我们的cpu内部的4kb的SRAM里面,并且把这个地址映射成起始地址,也就是说把cpu的sp指针指向内部的4kb的SRAM的0x0000地址,开始运行。
备注:(具体的在硬件上怎么拷贝到cpu内部的SRAM里面,下面的这段话也许能解释下)
During reset, Nand flash controller will get information about the connected NAND flash through Pin status
(NCON(Adv flash), GPG13(Page size), GPG14(Address cycle), GPG15(Bus width) – refer to PIN
CONFIGURATION), After power-on or system reset is occurred, the NAND Flash controller load automatically the
4-KBytes boot loader codes. After loading the boot loader codes, the boot loader code in steppingstone is
executed.(2440技术手册)
2.好了现在程序在你的内部4kb的SRAM里面开始运行了,但是这个只有4kb的SRAM空间太小,也许你觉得我写的程序很大起码有M级的,怎么办呢,那你只好外扩一片大点的SRAM,64M怎么样,可以了吧,你要是觉得还是装不下那就256M,但是不管怎么样你现在最重要的问题:怎么把我的程序放到我的外部SRAM里面去啊,于是你就想到为啥我不像在单片机里面的中断一样跳转指令似的,我在我的4kb里面来个复制指令,让我的外部nan flash 的程序全部考到我们的外部SRAM里面去啊,于是这个SRAM作用就体现出了
3.先在有一问题是你的拷贝指令的想法是可以的,但是假设你拷贝到外部的内存中,好了你得把你的sp指针也就是程序指针的地址放到外部的内存的起始地址上,这样子你才能完整的启动你的整个程序。于是你需要将你的地址重新映射下,将外部的内存地址映射成我们程序指针的地址,当然在单片机里面没有什么映射的概念(也许有但很少用),如果是单片机外扩的话,那你只是需要将sp指针的地址指向我们的外部的内存的首地址就可以了
备注:
1、在整个流程如果你是采用Linux来启动的你的系统的话,那么一般就会用到bootloader,那么你可以将你的bootloader放到你的nand flash的首地址。在随后的地址上放你程序,这样子在上电的时候你的bootloader会把你的程序拷贝到你的外部的存储器里面
2、紧跟的问题就来了,bootloader的大小?拷贝的地址从那一段地址到那一段地址?
先考虑第一个问题:大小
如果你的bootloader大于4kb怎么办,简单解决问题方法是,那你就得修改bootloader,当然你也可以修改其大小,使其小于4kb,但是你想要你bootloader的功能很强大,怎么办,那也很简单,那你就在bootloader的小于4kb的地址主要做一下初始化的工作,然后同样把你要的东西全部拷到你的外部内存中。记住在实际的bootloader中比喻:
0x00000000-0x00060000 //u-boot
0x00060000-0x00080000 //启动参数,即saveenv命令,将设置的参数保存的地址。
这里面就分的很详细,程序和启动参数都分得很仔细。
好了第二个问题:拷贝的地址段
如果你的bootloader很小,在cpu的内部sram就可以运行的话,那就拷贝从4kb以后的你的程序就可以了,但是如果大于4kb的话,参考前面的说法,当然你先拷贝你的内核0x00080000-0x00280000 //内核 0x00280000-之后的就是文件系统存放的区域了
4、好了在你的外部内存里面有你的内核和一些启动的bootloader,这个不是很重要,但是你现在就像看看,能不能呢个启动你的linux内核,可以考虑让你程序的地址指针指向的内核的首地址,看是否能启动起来。但是说实在话,很多文章在测试他们的内核是否启动起来的,都把他们下到0x31000000这个起始地址,很是不解。