1. 概述
本文档描述AT91SAM9260 NORFLASH系统启动的设计方案;
AT91SAM9260 支持多种boot策略,具体取决于系统reset时BMS的状态,当BMS=0时系统从连接到CS0上的外部静态非易失性存储器boot。
Norflash接口和SRAM类似,并且数据读取操作简单,CPU的SMC(静态存储控制器)可以直接读取。理论上可以用来存放boot及应用代码。
2. 官方支持的boot方案
ATMEL支持的比较成熟的boot方案是DATAFLASH或NANDFLASH启动,为了实现DATAFLASH和NANDFLASH启动,首先在CPU在内部ROM中固化了boot program,当BMS=1时,CPU从内部ROM boot。
该boot program主要实现了2个功能,
1. 系统初始化
RESET后进入系统初始化阶段:
1. FIQ Initialization
2. Stack setup for ARM supervisor mode
3. External Clock Detection
4. Switch Master Clock on Main Oscillator
5. C variable initialization
6. Main oscillator frequency detection if no external clock detected
7. PLL setup:
2. 1级bootloader的功能,
初始化完成后进入Bootloader阶段:
8. Initialization of the DBGU serial port (115200 bauds, 8, N, 1) only if OSCSEL = 1
9. Enable the user reset
10. Jump to DataFlash Boot sequence through NPCS0. If DataFlash Boot succeeds, perform a remap and jump to 0x0.
11. Jump to DataFlash Boot sequence through NPCS1. If DataFlash Boot succeeds, perform a remap and jump to 0x0.
12. Jump to NAND Flash Boot sequence. If NAND Flash Boot succeeds, perform a
remap and jump to 0x0.
13. Activation of the Instruction Cache
14. Jump to SAM-BA Boot sequence
15. Disable the WatchDog
16. Initialization of the USB Device Port
除此之外,ATMEL在PC端还提供了SAM-BA应用程序实现对DataFlash以及Nandflash的烧写功能。
图2.1 SAM-BA应用程序界面
3. Norflash boot实现方案
不论是片内的boot program还是上位机SAM-BA工具都不提供对Norflash的支持,可见ATMEL官方对于 Norflash boot 方案没有任何技术支持,也就是说如果采用Norflash boot 方案的话,必须自己实现所有片内和片外(上位机)的工作。
这是一个比较繁琐和复杂的工作。
3.1 片外烧写工具
首先,要实现Norflash boot势必在系统reset之前norflash中要有boot代码,这就意味着必须可以从片外对norflash进行编程,而ATEML官方提供的片外编程工具不支持Norflash编程,所以只能选择第三方的flash编程工具。
这里推荐的是SEGGER提供的工具Jlink+JFlash,Jlink是一种USB JETG仿真器,功能强大,支持大多数编译器,包括ADS、IAR、以及KEIL的MDK。而JFlash是基于该仿真器的Flash编程软件。
JFlash的功能很强,使用方法也比较简单,首先在projectfile文件夹下打开预存的工程文件比如AT91SAM9260_CFI_1x16.jflash。该工程文件中有针对不同厂家不同型号系统所预先设置好的工程参数,包括CPU初始化参数以及FLASH的相关参数等,这些参数都是可编辑的,具体在Option菜单中的Project setting中设置,一般采用预设值不用做任何改动。
将Jlink与目标板连接以后,就可以对flash进行操作了,包括erase、program等。这里要注意的是打开2进制文件时软件会提示用户输入该文件的起始地址,该起始地址必须和flash在目标CPU的内存映射空间上的地址一致。
图 3.1 JFlash界面
3.2 连接器配置
有了JFlash工具解决了Norflash的片外编程问题,接下来就是如何编写boot program的问题了。
首先必须先选择编译器。
这里推荐使用IAR,因为ATMEL官方提供的代码都是IAR写的。KEIL的MDK也不错,不过就不能直接使用官方的代码了。
为什么跟编译器有关呢,这里涉及到一个链接的问题,我们知道最终代码在目标系统的存放地址是由linker决定的,而具体某个存储器对应的地址段一般是确定的,所以要想将代码存放到指定的存储器上必须对linker进行配置,而linker的配置是通过编写link command file来实现的,不同编译器的link command file有所不同,所以必须先确定编译器。
配置Link command file可能不是一件容易的事,这需要对编译器原理以及ARM体系结构甚至C语言原理都要有一定的理解。此外还必须了解目标CPU的具体内存空间映射情况。
3.2.1 AT91SAM9260的内存空间分配情况:
首先看片内存储资源:
·32K ROM 用于存放Boot program
·2x4K的高速SRAM 一般用于存放中断向量表,以及2级bootloader
片内的存储资源很宝贵,并且它们都可以进行地址重映射。所谓的地址重映射指的是同一快存储器可以被映射到不同的地址空间上。
比如32K ROM所在地址是0x100000到0x108000,当BMS=1时,它又被映射到0x0地址,此时访问地址空间0x0~0x8000与0x100000~0x108000的效果是一样的。
具体参考Datasheet: AT91SAM9260 Memory Mapping
另一块可以被重映射的地址区域就是CS0所在的0x10000000~0x10100000地址段,该地址段就是norflash所在的地址段,当BMS=0 系统Reset时该地址段被映射到0x0处,而reset后CPU将从地址0x0开始取指,也就实现了从Norflash boot。
所以,必须将boot代码指定存放在这一地址段才行。
仅仅有代码程序是无法执行的,还需要RAM来存放变量和临时数据,C语言的话还需要堆和栈的支持,而片内的RAM只有8K,所以必须要有片外的SDRAM支持。
SDRAM被分配在CS1的20000000~2FFFFFFF地址段,和Norflash不同的是,必须通过配置SDRAM控制器CPU才能操作SDRAM,也就是说系统reset后是不能直接访问SDRAM。理论上SDRAM控制器的初始化代码必须用汇编来写,除非将CSTACK指定到内部SRAM上,具体见下一节。
事实上SDRAM控制器实现了所有对SDRAM的操作,包括读和写,但是必须对其进行配置,默认配置是无法访问SDRAM的。而Norflash可以不需要配置就可以通过静态存储控制器SMC对其进行读操作了,但是SMC默认的配置只能访问16位的外部静态存储器,并且只能以慢速时钟访问,要想以最佳速度对特定的norflash进行操作,仍然需要对SMC进行配置。此外即使配置了SMC也还是仅仅能进行读操作而已,如果想对Norflash进行擦除或者写操作,则还必须编写特定的驱动程序。
3.2.2 ARM体系结构相关及中断向量表
ARM定义了1组CPU模式,包括用户模式、系统模式、中断模式等,每个CPU模式对应一组特定CPU寄存器,这些CPU寄存器有的是各模式所共用的而有的是模式所特有的,也就是说只有在特定模式下才可见,SP寄存器是被编译器用来存放堆栈指针的CPU寄存器,在ARM架构定义中不同的CPU模式有自己特有的SP寄存器。
而C语言编译器是依赖SP寄存器来实现对堆栈的操作的,函数调用等C的语义就是依赖堆栈实现的,也就是说在使用C语言语义之前必须先对堆栈进行初始化。
所谓的堆栈初始化就是告诉编译器堆栈的起始地址在哪里,堆栈的尺寸等,而堆栈的起始地址就是存放在SP寄存器中的,因为ARM有多个CPU模式,每个模式有自己的SP寄存器,所以必须对每个SP指针都进行初始化。
不仅仅是对各个SP指针进行初始化工作,还需要为各个模式下的堆栈分配空间,很显然这些空间都只能分配在RAM上,可供选择的只有片内的SRAM和片外的SDRAM。
前面说到SDRAM控制器的初始化代码只能用汇编写就是这个道理,因为C代码需要堆栈的支持,而堆栈需要SDRAM的支持,SDRAM控制器初始化之前CPU又不能访问SDRAM,所以不能使用C语言来编写SDRAM控制器初始化的代码,只有当SDRAM控制器初始化完成以后C代码才有可能被正常执行。
中断向量表一般只有几行多至几十行代码,但是保证程序得以正常运行非常重要的部分,其主要的功能是实现系统中断,而包括操作系统在内很多软件功能都是利用中断来实现的。
理论上程序代码可以被存放在系统地址空间允许访问的任何地方,中断向量表特殊的地方就在于它必须被放在地址0x0开始的地方,换句话来说如果你将中断向量表写入某个存储器内,那么该存储器必须是或者必须可以被映射到地址0x0处。
这也解释了为什么某些存储器可以被重映射的原因。可以这么理解:可以被重映射的存储器就是可能会存放中断向量表代码的存储器。
所以,可以被选择存放中断向量表的对象只有2个:一个是片内的SRAM,另一个就是Norflash,至于片内的ROM,虽然它也可以被重映射到0x0地址,但是它是不可写的。
3.2.3 Link command file
了解了代码、堆栈以及中断向量表分别应该被放在哪里之后,接下来还需要了解如何告诉连接器按照我们的设想来连接编译好的代码。
这个工作是由link command file实现的。
IAR的连接器是通过module和Sector来分解和组织整个工程的,一个C源文件就是一个module,这是由C编译器自动定义的,所以对C程序员来说不用关心Module的概念;但是一个汇编源文件可以定义多个module,至少是一个。
Sector是比Module更小的区域,一个Module可以有多个Sector。Sector也是linker支持的最小的划分单位,也就是说在一个sector中的代码或者数据总是会被linker放在连续的地址段中,如果你想要将2段代码分别放在不同的地址段中的话,那么至少你要定义2个sector;
Sector定义好之后,接下来就是要为将该sector分配地址空间,同样,2个sector分配的地址空间不可以有重叠。
利用-Z指令可以为一个Sector分配地址段,比如:
-Z(CODE)CODE=10000000-10FFFFFF
就是将名为CODE的sector分配到10000000-10FFFFFF地址段中,如前所述该地址段是映射到Norflash上的。
对于堆栈也可以用同样的方法为他们分配地址空间,先将堆栈定义成SECTOR,然后利用-Z指令指定堆栈的物理地址,如:
-Z(DATA)CSTACK+1000=200000-200fff
该指令将CSTACK分配到了内部SRAM所在的地址空间。这样,当程序需要使用CSTACK时就会去访问SRAM了。
而中断向量表必须被分配到0x0地址段,也就是0x10000000地址:
-Z(CODE)INTVEC=10000000-1000003F
3.3 boot program编写
编译器设置好之后就可以将boot及应用程序按照设计好的方案正确的编译和连接了,接下来的工作就是如何编写boot program了。
因为boot program是将要烧写到flash中运行的,而现有的工具,包括Jlink都不支持片外Flash的debug功能,也就是说烧入flash中的程序必须准确无误,尤其是boot program,否则程序的行为是未知的。
这里的一个方法是先在SDRAM中对即将烧入FLASH中运行的程序进行仿真调试,验证无误后再烧入FLASH运行。
要说明的是实际上在SDRAM下运行的程序和在FLASH中运行的程序是有差异的,差异就在初始化阶段,在SDRAM仿真环境下运行很多初始化工作是不需要做的,比如CPU时钟初始化、SDRAM控制器的配置等,原因是仿真器会自动执行这些初始化工作,但是在实际FLASH环境下运行情况就不一样了,所有的初始化工作 都必须由程序自己完成。
所以要想验证程序最终是否能够正常工作,就必须完整的实现整个系统初始化过程,包括CPU时钟,SMC,SDRAM控制器初始化等,因为boot阶段是不能使用堆栈的,所以这些初始化代码都必须要用汇编代码来实现。
当这些初始化工作完成以后,接下来的程序的执行在SDRAM仿真环境和在实 际FLASH环境下运行就没有区别了。
这里说明一个IAR编译器的功能,就是跟大多数编译器一样,IAR提供多工程配置的功能,也就是说一个工程可以有多个配置,类似于VC的debug和release 概念,debug下的配置用于SDRAM仿真调试,而release配置用于最终烧写到FLASH 运行的程序。这样每次更换运行环境时就不需要修改编译
注:转载自http://blog.csdn.net/vincent_lon/archive/2009/03/07/3966161.aspx