概要:

本文介绍了DM368 NAND Flash启动的原理,并且以DM368  IPNC参考设计软件为例,介绍软件是如何配合硬件实现启动的.

芯片上电后是如何启动实现应用功能的?这是许多工程师在看到处理器运行的时候,通常都会问的一个问题.下面我们就以德州仪器的多媒体处理芯片TMS320DM368为例,介绍它的NAND Flash启动原理以及实现.

1. NAND Flash启动原理

德州仪器的多媒体处理芯片TMS320DM368可以实现1080P30 h264的编码,已经广泛的使用在了网络摄像机的应用中.DM368可以支持NOR Flash, NAND Flash, UART, SD Card启动等多种启动方式.对于NAND启动,DM365支持的特性如下:

  1. 不支持一次性全部固件下载启动.相反的,需要使用从NAND flash把第二级启动代码(UBL)复制到ARM的内存(AIM),将控制转交给用户定义的UBL.
  2. 支持最大4KB页大小的NAND.
  3. 支持特殊数字标志的错误检测,在加载UBL的时候会尝试最多24次.例如在NAND的第1个block没有找到特殊数字标志,会到下一个block继续查找,一直到查找到第24个block.
  4. 支持30KB大小的UBL(DM365有32KB的内存,其中2KB用作了RBL的堆栈,剩下的空间可以放UBL)
  5. 用户可以选择在RBL执行的时候是否需要支持DMA,I-cache(例如,加载UBL的时候)
  6. 使用并且需要4位硬件ECC(支持每512字节需要ECC位数小于或等于4位的NAND Flash).
  7. 支持需要片选信号在Tr读时间为低电平的NAND Flash.

在网络网络摄像机的应用中为了节约成本,有一些用户使用了NAND Flash启动方式.图1就是从上电到Linux启动的一个概要的流程图.首先RBL(ROM boot loader)从NAND上读取UBL(user boot loader)并且复制到ARM的内存里面.UBL运行在ARM的内存里,初始化系统,例如初始化DDR.然后UBL从NAND Flash里面读取U-Boot的内容并且复制到DDR里运行.DDR里面运行的U-Boot又从NAND Flash里面读取Linux内核代码,并且复制到DDR上,然后启动内核.这样DM365的系统就从上电到完成Linux内核启动,然后就可以运行相应的应用程序了.

      图1 NAND Flash启动流程

下面我们会一步一步的介绍从上电到Linux启动是如何实现的.

首先我们需要提到的一个概念是RBL,也就是ROM Boot Loader (ROM启动代码).在DM368芯片上有一块ROM的区域(地址从0x00008000到 0x0000 BFFF),这块区域就是存放RBL代码的地方.ROM上的代码是在芯片出厂前就烧写好的,用户是不能修改的.在DM368上,除了AEMIF (Nor Flash)启动,其他的启动方式都需要运行RBL.

无论是上电复位,热复位,还是看门狗复位,在复位信号由低到高的时候,DM368芯片会检测BTSEL[2:0]引脚(启动选择引脚).只要检测到电平不是001,也就是不是AEMIF (NOR Flash)启动,ARM程序就会从ARM的ROM的地址0x00008000地址开始执行.

RBL首先会读取BOOTCFG寄存器里面的BTSEL信息,如果发现BTSEL的状态是000,就会得知配置的是NAND Flash启动,NAND启动模式开始执行.注意:为了保证NAND启动正常运行,需要保证在复位的时候DEEPSLEEPZ/GIO0引脚拉高.在确认启动是NAND后,首先RBL会初始化最高2KB的内存为堆栈并且关闭所以中断.然后RBL会读取NAND的ID信息,然后在RBL的代码里面的NAND ID 列表,从而得知更详细的NAND Flash的信息,例如页(page)大小等,对EMIF做好相应的配置.DM368支持启动的NAND的ID信息可以在参考文档1(ARM子系统用户手册)里面找到.硬件选型时,请务必选择在NAND ID列表里面支持的NAND芯片.

接下来,RBL会在NAND Flash的第1块的第0个页开始查找UBL的描述符.如果没有找一个合法的UBL的特殊数字标志,RBL会继续到下一个块的第0个页查找描述符,最多第24个块.RBL会到多个块里面查找描述符是根据NAND Flash本身容易与坏块的特点而设计的.24块应该足以避免NAND Flash坏块的影响.

如RBL在某块里面找到了合法的UBL描述符,这个块号(block number)就会写到ARM内存最后的32位(0x7FFC~0x8000)用于调试时候使用,然后UBL描述符的具体内容将被读取并且处理.UBL描述符告诉RBL关于下载和将控制权交给UBL所需要的信息,具体见表1.

      表1 NAND UBL描述符

一旦用户需要的启动设置配置好,RBL就会从0x0020第地址开始把UBL搬移到ARM内存.在从NAND读取UBL的过程中中,RBL会使用4位的硬件ECC对NAND Flash上的数据进行检错和纠错.如果因为其他原因读失败,复制会立即停止,RBL会在下个块里面继续寻找特殊数字标志.

对于UBL的描述符有几点注意事项:

  1. 入口地址必须在0x0020到0x781C之间
  2. 存放UBL的页必须是连续的页,可以分布在多个块内,总共大小必须小于30KB.
  3. UBL的起始块号(block number)可以是和存放UBL描述符的块号一样.
  4. 如果UBL的起始块号是和存放UBL描述符的块号一样, 那UBL的起始页数一定不可以和UBL描述符存放的页数一样.

但RBL根据UBL描述符里提供的UBL大小信息将UBL全部成功复制到ARM内存后,RBL会跳到UBL起始地址,这样芯片的控制权就交给了UBL,UBL开始在ARM内存里运行了.

也许你会问,既然RBL可以把NAND Flash上的内容复制到ARM内存里运行,为什么我们不直接把U-Boot复制到内存运行?原因是ARM内存太小.一般的U-Boot都是大于100KB,而DM365上可以用于启动的内存只有30KB.也许你又要问了,那为什么不把U-Boot直接复制到DDR上运行,DDR有足够大的空间?这个原因是,芯片上电后并无法知道用户在DM365的DDR2接口上接的DDR信息,RBL也就无法初始化DDR,在RBL运行的阶段DDR是不可用的.这也是为什么UBL里面初始化DDR是它的一项重要任务.

当NAND启动失败的时候,RBL会继续尝试MMC/SD启动方式.如果你系统使用NAND启动,但NAND上的内容损坏了,如果你的板子上有SD卡接口,也可以改变启动方式,那你可以用SD卡先把系统启动起来,然后重新烧写NAND Flash上的内容.这可以作为产品失效后在客户侧的一个补救方法.

2. NAND Flash启动的软件配合实现

现在我们知道了DM368 NAND Flash启动的原理,下面我们来看看软件是如何根据并配合硬件的要求实现启动的.在DM368 IPNC的软件包里面有一个工具的目录,里面有预先编译好的烧写NAND的CCS的可执行文件, UBL的二进制文件以及相关源码.

2.1 UBL描述符的实现

刚才在介绍NAND Flash启动原理的时候,我们提到了RBL需要到NAND Flash上面搜索特殊数字标志.这个特殊数字标志就是由烧写NAND的CCS的工程写到Flash上的.在flash_utils_dm36x_1.0.0\flash_utils_dm36x\DM36x\CCS\NANDWriter\src\nandwriter.c里面的LOCAL_writeHeaderAndData()函数就是用来写描述符的.

   // Setup header to be written
  headerPtr = (Uint32 *) gNandTx;
  headerPtr[] = nandBoot->magicNum; //Magic Number
  headerPtr[] = nandBoot->entryPoint; //Entry Point
  headerPtr[] = nandBoot->numPage; //Number of Pages
#if defined(IPNC_DM365) || defined(IPNC_DM368)
  headerPtr[] = blockNum+; //Starting Block Number
  headerPtr[] = ; //Starting Page Number - always start data in
  page (this header goes in page )

对比表1,你可看到headerPtr[3]的内容是用来存放UBL代码的起始块号.这里+3的意思就是UBL是存放在UBL描述符所放块号后面的第三块里面.headerPtr[4] = 0表示是从第0页开始存放.当然这个值用户是可以修改的.只要你烧写UBL代码的位置和描述符里面的起始块/页数一致就可以了.

在IPNC的代码里面UBL的描述符是会从NAND Flash的第1个块开始写,如果块是好的,就放在第1块的第0页.如果第1块是坏的,就会把UBL的描述符写入到下一个块的第0页.IPNC的代码里面没有将UBL描述符可能有的块号从1到24块(这是RBL搜索的范围),它只是从第1块到第3块.如果UBL描述符放在第1块,那如果第4块是好的话,UBL的代码就从第4块的第0页开始放.

 #elif defined(IPNC_DM368)
// Defines which NAND blocks the RBL will search in for a UBL image
#define DEVICE_NAND_RBL_SEARCH_START_BLOCK (1)
#define DEVICE_NAND_RBL_SEARCH_END_BLOCK (3)

在nandwriter.c里面你还可以看到UBL的入口地址是固定的0x100.

 gNandBoot.entryPoint  = 0x0100;       // This fixed entry point will work with the UBLs

要了解为什么是0x100,你就必须要看一下UBL的源码.在UBL源码的UBL.cmd文件里面,你可以看到下

面的定义,将入口地址放在boot的地方,而boot的运行地址就是 0x100.

 -e boot //指定入口地址为 boot

MEMORY
{
  …
  UBL_I_TEXT (RX) : origin = 0x00000100 length = 0x00004300
  …
  UBL_F_TEXT (R) : origin = 0x020000E0 length = 0x00004300
  ...
}
SECTIONS
{
  …
  .text : load = UBL_F_TEXT, run = UBL_I_TEXT, LOAD_START(FLASHTEXTStart),
  LOAD_SIZE(FLASHTEXTSize)
  {
  *(.boot)
  . = align();
  *(.text)
  . = align();
  }
  ….
}

在 UBL的源码 boot.c里面有强制把启动的最初代码放在了boot的section里面.

 #if defined(__TMS470__)

#pragma CODE_SECTION(boot,".boot");
#endif
void boot(void)
{

}

这样从cmd的配置以及代码指定代码段,UBL的程序就能确保是从0x100的地址开始运行.

2.2 U-Boot启动实现

UBL启动U-Boot的过程,借鉴了RBL启动UBL的原理.烧写描述符也是用同样的LOCAL_writeHeaderAndData()函数.在nandwriter.c里面,我们把U-Boot的代码叫做应用代码(APP).

 // Defines which NAND blocks are valid for writing the APP data
#define DEVICE_NAND_UBL_SEARCH_START_BLOCK (8)
#define DEVICE_NAND_UBL_SEARCH_END_BLOCK (10)

下面是 IPNC启动后串口最初的打印

Valid magicnum, 0xA1ACED66, found in block 0x00000008.
DONE
Jumping to entry point at 0x81080000

我们可以看到UBL是指第8块的地方找到了U-Boot的描述符,这个和DEVICE_NAND_UBL_SEARCH_START_BLOCK的定义是一致的.

2.3 U-Boot更新UBL和U-Boot的原理

IPNC代码支持在U-Boot里面更新UBL或者U-Boot自己.下面是烧写ubl和U-Boot在U-Boot下的命令.

烧写 ubl:
nand write 0x80700000 0x080000 0x08000
烧写 U-Boot:
nand write 0x80700000 0x160000 0x28000

要了解为什么NAND Flash的烧写地址是0x80000和0x160000,这还是需要了解nandwriter.c里面的烧写流程.从前面的内容我们可以得知,nandwriter.c烧写UBL是从1+3=4块开始的,而烧写U-Boot是从8+3=11块.在IPNC上使用的NAND Flash是2K一个页,每个块128KB.所以UBL烧写的地址是128KBx4=0x80000,而烧写U-Boot的地址是 128Kx11=0x160000.

2.4 NAND Flash没有坏块的情况

所以如果在没有NAND Flash坏块的情况下,nandwriter.c会把UBL的描述符烧写在第1块第0页上,把UBL的代码烧写在第4块第0页上,把U-Boot(APP)的描述符烧写在第8块第0页上,把U-Boot的代码烧写在第11块第0页上.这样芯片在上电确认是NAND Flash启动后,RBL在执行的时候就会找到UBL相应的描述符,把UBL加载的ARM内存里运行.而UBL又找到了U-Boot的描述符,把U-Boot加载到DDR上运行.最后U-Boot加载uImage并启动了Linux,完成了从上电到 Linux启动的整个过程.

3. 结束语

每个芯片一般都有多种启动方式,各个芯片的启动方式都有所不同,但又有类似的地方.上面的介绍也可以作为学习其他芯片其他启动方式的一个参考.

本文转自:http://www.deyisupport.com/blog/b/av_tech/archive/2011/08/08/dm368-nand-flash.aspx

DM368 NAND Flash启动的更多相关文章

  1. DM365视频处理流程/DM368 NAND Flash启动揭秘

    出自http://blog.csdn.net/maopig/article/details/7029930 DM365的视频处理涉及到三个相关处理器,分别是视频采集芯片.ARM处理器和视频图像协处理器 ...

  2. nor flash与nand flash启动的简单比较--APPLE的ARM学习笔记一

    2010-10-08 22:26:00 A,nor flash与nand flash的一些区别 1)接口区别: NOR FLASH地址线和数据线分开,来了地址和控制信号,数据就出来. NAND Fla ...

  3. S3C2440从NAND Flash启动和NOR FLASH启动的问题

    1.为什么NAND FLASH不能直接运行程序     NAND FLASH本身是连接到了控制器上而不是系统总线上.CPU运行机制为:CPU启动后是要取指令执行的,如果是SROM.NOR FLASH ...

  4. s3c2440 移值u-boot-2016.03 第2篇 支持Nand flash启动

    1, 要求:在4K 的代码以内,完成 NOR NAND 类型判断,初始化 NAND 复制自身到 SDRAM ,重定向. 2, 在 /arch/arm/cpu/arm920t/ 文件夹里 添加一个 in ...

  5. uboot下 Nand flash 启动 内核与根文件系统

    u-boot版本: u-boot-2010.03_tekkamanninja修改的u-boot 1.将uboot通过j-link烧写到norflash,启动后 saveenv 将参数保存到 nandf ...

  6. nor flash启动与nand flash启动的区别

    1)接口区别:NOR FLASH地址线和数据线分开,来了地址和控制信号,数据就出来.NAND Flash地址线和数据线在一起,需要用程序来控制,才能出数据.通俗的说,就是光给地址不行,要先命令,再给地 ...

  7. 新手学习ARM,对片内ram、SDRAM、NOR FLASH和NAND FLASH启动这几个概念的理解

    片内的ram用来存储启动代码,在2440初始化sdram之前,代码就在片内ram中运行.片内ram装载的是norflash中的内容,即u-boot. uboot放在norflash里,nandflas ...

  8. Nor Flash启动和Nand Flash启动时Stepping stone都在哪?

    当从Norflash启动时,Steppingstone被映射到地址 0x4000 0000 至 0x4000 0FFF: 当从Nandflash启动时,Steppingstone被映射到地址 0x00 ...

  9. S3C2440的内存情况在NAND FLASH或者NOR FLASH启动的情况下

    1,从NANDFLASH启动时,在ARM上电时,ARM会自动把NANDFLASH前4K的内容拷贝到S3C2440内部SRAM中,同时把SRAM的地址映射到0X00000000.ARM上电后会从SRAM ...

随机推荐

  1. 使用OPtional的orElse()问题

    使用OPtional的orElse()问题 项目中有这样一段代码: return Optional.ofNullable(service.A()).orElse(service.B()) 1 功能显而 ...

  2. Java中16进制与字符串之间的相互转换

    笔者前几日在开服过程中需要将字符串转化成为16进制的字符串,在网上找到了一些方法尝试之后,均发现存在一个问题-->字符串转为16进制后再转回来,英文正常,中文出现乱码 经过考虑决定通过以下方式进 ...

  3. tidb 安装试用&&以及安装几个问题解决

    备注:    tidb 听说已经很长时间了,一直无安装部署(主要是不像cockrouchdb 不见那么简单)   1. 环境准备(官方建议使用6台机器) // 我的机器准备(阿里云的,同时大家最好选择 ...

  4. lapis 框架安装试用

    备注:     此次安装使用的是openresty 的openresty-1.11.2.1(openresty-1.11.2.1.tar.gz,最新版本存在cjson 包的问题 )   同时对于lua ...

  5. FastAdmin 前端页面传参笔记

    FastAdmin 前端页面传参笔记 看到 QQ 群里的小伙伴询问如何传参,然后在社区里找到一笔记帖子 1 还要参考在线文档控制器部分2. 引用 Karson 的回复: 如果我们需要自己在控制器中透传 ...

  6. Iterations --codility

    lesson 1:Iterations 1. BinaryGap-----[100%] Find longest sequence of zeros in binary representation ...

  7. curl 无法访问 https 协议

    转自http://blog.mutoo.im/2013/12/curl-could-not-communicate-with-https-sites.html mac升级为10.10以后,homebr ...

  8. 雅虎CSS初始化代码

    body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,b ...

  9. Jenkins的项目管理

    新建Item 使用Jenkins最重要的是能够创建一些工作流,除了部署,还能做很多流程上的事情.同样,一条条项目建起来需要做一定的管理,在Jenkins首页Jenkins->新建可以按自己的需要 ...

  10. python 冒泡排序,二分法

    a = 0 lst = [13,5,1,7,2,6,4,5,6] while a < len(lst): # 控制次数 for i in range(len(lst)-1): if lst[i] ...