搜索
bottom↓
回复: 331

可能还有很多同志仍然对ARM的启动过程的认识比较模糊,下面我将做简要的介绍【恢复】

[复制链接]

出0入0汤圆

发表于 2008-11-29 11:29:04 | 显示全部楼层 |阅读模式
(想要弄懂这个问题,一定要坚持看完并做实际的演示才行,如有不明白之处,请在后面跟帖提问,我会尽快回复)

    基于ARM的芯片多数为复杂的片上系统,这种复杂系统里的多数硬件模块都是可配置的,需要由软件来设置其需要的工作状态。因此在用户的应用程序之前,需要由专门的一段代码来完成对系统的初始化。由于这类代码直接面对处理器内核和硬件控制器进行编程,一般都是用汇编语言。一般通用的内容包括: 

 中断向量表 

 初始化存储器系统 

 初始化堆栈 

 初始化有特殊要求的断口,设备 

 初始化用户程序执行环境 

 改变处理器模式 

 呼叫主应用程序 

 中断向量表 

 ARM要求中断向量表必须放置在从0地址开始,连续8X4字节的空间内。 

 每当一个中断发生以后,ARM处理器便强制把PC指针置为向量表中对应中断类型的地址值。因为每个中断只占据向量表中1个字的存储空间,只能放置一条ARM指令,使程序跳转到存储器的其他地方,再执行中断处理。 

 中断向量表的程序实现通常如下表示: 

 AREA Boot ,CODE, READONLY 

 ENTRY 

 B  ResetHandler 

 B  UndefHandler 

 B  SWIHandler 

 B  PreAbortHandler 

 B  DataAbortHandler 

 B  IRQHandler 

 B  FIQHandler 

 其中关键字ENTRY是指定编译器保留这段代码,因为编译器可能会认为这是一段亢余代码而加以优化。链接的时候要确保这段代码被链接在0地址处,并且作为整个程序的入口。 

 初始化存储器系统 

 存储器类型和时序配置 

 通常Flash和SRAM同属于静态存储器类型,可以合用同一个存储器端口;而DRAM因为有动态刷新和地址线复用等特性,通常配有专用的存储器端口。 

 存储器端口的接口时序优化是非常重要的,这会影响到整个系统的性能。因为一般系统运行的速度瓶颈都存在于存储器访问,所以存储器访问时序应尽可能的快;而同时又要考虑到由此带来的稳定性问题。 

 存储器地址分布 

 一种典型的情况是启动ROM的地址重映射。 

 初始化堆栈 

 因为ARM有7种执行状态,每一种状态的堆栈指针寄存器(SP)都是独立的。因此,对程序中需要用到的每一种模式都要给SP定义一个堆栈地址。方法是改变状态寄存器内的状态位,使处理器切换到不同的状态,让后给SP赋值。注意:不要切换到User模式进行User模式的堆栈设置,因为进入User模式后就不能再操作CPSR回到别的模式了,可能会对接下去的程序执行造成影响。 

 这是一段堆栈初始化的代码示例,其中只定义了三种模式的SP指针: 

 MRS  R0,CPSR 

 BIC  R0,R0,#MODEMASK 安全起见,屏蔽模式位以外的其他位 

 ORR  R1,R0,#IRQMODE 

 MSR  CPSR_cxfs,R1 

 LDR  SP,=UndefStack 

 

 ORR  R1,R0,#FIQMODE 

 MSR  CPSR_cxsf,R1 

 LDR  SP,=FIQStack 

 

 ORR  R1,R0,#SVCMODE 

 MSR  CPSR_cxsf,R1 

 LDR  SP,=SVCStack  

初始化有特殊要求的端口,设备 

 初始化应用程序执行环境 。一个ARM映像文件由RO,RW和ZI三个段组成,其中RO为代码段,RW是已初始化的全局变量,ZI是未初始化的全局变量。 映像一开始总是存储在ROM/Flash里面的,其RO部分即可以在ROM/Flash里面执行,也可以转移到速度更快的RAM中执行;而RW和ZI这两部分是必须转移到可写的RAM里去。所谓应用程序执行环境的初始化,就是完成必要的从ROM到RAM的数据传输和内容清零。 

 下面是在ADS下,一种常用存储器模型的直接实现: 

编译器使用下列符号来记录各段的起始和结束地址: 

|Image$$RO$$Base| :RO段起始地址 

|Image$$RO$$Limit| :RO段结束地址加1 

|Image$$RW$$Base| :RW段起始地址 

|Image$$RW$$Limit| :ZI段结束地址加1 

|Image$$ZI$$Base| :ZI段起始地址 

|Image$$ZI$$Limit| :ZI段结束地址加1 

这些标号的值是根据链接器中设置的中ro-base和rw-base的设置来计算的。 

初始化用户执行环境主要是把RO、RW、ZI三段拷贝到指定的位置。 

 LDR  r0,=|Image$$RO$$Limit| 得到RW数据源的起始地址 

 LDR  r1,=|Image$$RW$$Base| RW区在RAM里的执行区起始地址 

 LDR  r2,=|Image$$ZI$$Base| ZI区在RAM里面的起始地址 

 CMP  r0,r1         比较它们是否相等 

    BEQ  %F1 

 0   CMP  r1,r3 

    LDRCC r2,[r0],#4

STRCC r2,[r1],#4 

    BCC  %B0 

 1   LDR  r1,=|Image$$ZI$$Limit| 

    MOV  r2,#0 

 2   CMP  r3,r1 

    STRCC r2,[r3],#4 

    BCC  %B2 

直接从启动代码跳转到应用程序的主函数入口,当然主函数名字可以由用户随便定义。 

 在ARM ADS环境中,还另外提供了一套系统级的呼叫机制。 

 IMPORT __main 

 

 B   __main 

 __main()是编译系统提供的一个函数,负责完成库函数的初始化和初始化应用程序执行环境,最后自动跳转到main()函数。

ARM启动ourdev_521416.doc(文件大小:38K) (原文件名:ARM 启动.doc) 





本贴被 d6821_021362 编辑过,最后修改时间:2008-11-29,13:21:35.

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2008-11-29 11:53:07 | 显示全部楼层
非常感谢~~

出0入0汤圆

发表于 2008-11-29 13:12:54 | 显示全部楼层
比较复杂!

出0入0汤圆

发表于 2008-11-29 13:35:54 | 显示全部楼层
总结得非常详细,赞!

出0入0汤圆

发表于 2008-11-29 13:36:48 | 显示全部楼层
看完,感谢楼主~~

出0入0汤圆

发表于 2008-11-29 14:26:17 | 显示全部楼层
学习了! 

出0入0汤圆

发表于 2008-11-29 14:32:25 | 显示全部楼层
谢谢楼主.........

出0入0汤圆

发表于 2008-11-29 14:33:51 | 显示全部楼层
学习

出0入0汤圆

发表于 2008-11-29 19:29:00 | 显示全部楼层
thank you

出0入0汤圆

发表于 2008-11-29 20:09:35 | 显示全部楼层
我补充一点我认识的:



image 在装入前只有 RO 和 RW, ZI 初始不占用空间, 只是一个占位符,

image 执行的时候, 装入到 RAM, 生成了 ZI.



这是我困惑比较长的一个问题,

后来看了 CSAPP 后, 才明白的 :)



可能有理解错误的地方, 请大家指正.

出0入0汤圆

发表于 2008-11-29 22:17:13 | 显示全部楼层
我也补充一点

因为ZI是无初始化数据的。对ZI区通常只是清零。对于C程序,这个工作在CRT代码中完成,映像只需给出ZI区的地址范围



要注意的是,ARM的Cortex-M3的低阶初始化程序虽然大体也完成相同的工作,但是CM3在向量表结构、处理器模式和中断系统上是大相径庭的



另外,在基于CM3单片机中,往往从ROM执行比从RAM执行快。主要是因为基于CM3的单片机,Flash与SRAM读写速度通常差不多,但却是有不同的总线访问ROM区和RAM区。在ROM中取指的同时可以访问RAM,于是加快了执行。

出0入0汤圆

发表于 2008-11-29 23:16:18 | 显示全部楼层
好像是哪本书上的……

感谢楼主提出这个主题,刚接触ARM,启动文件确实是我们菜鸟最困扰的问题



看完后有两点不明白的:

1、初始化应用程序执行环境 。一个ARM映像文件由RO,RW和ZI三个段组成,……(以下略)

不明白的是RO,RW和ZI都是ADS环境下的写法吧,如果我用IAR的话,这一部分可以跳过去吗?看着好抽象……

2、都说remap,书上说remap就是把RAM或片外存储器映射为0x0,那到底是怎么映射的呢?而且要把ROM中的内容复制到RAM,这又是怎么搞得呢?要写代码还是ARM相关寄存器设置的?



谢谢大家!

出0入0汤圆

发表于 2008-11-29 23:18:25 | 显示全部楼层
好,顶了再看

出0入0汤圆

发表于 2008-11-30 00:53:59 | 显示全部楼层
不错

出0入0汤圆

发表于 2008-11-30 12:57:29 | 显示全部楼层
非常谢谢!!

出0入0汤圆

发表于 2008-11-30 13:06:24 | 显示全部楼层
谢谢!!

出0入0汤圆

发表于 2008-11-30 14:36:03 | 显示全部楼层
To 12楼

RO段, RW段, ZI段最好不要太教条主义地去理解,不同工具叫法有区别,比如GCC的就管ZI叫.bss,RO叫.text,应重点理解它们的地位和类型。IAR中可能也有不同的名字,但它的帮助应该会讲到。只不过,网上基于ARM官方工具的教程更丰富(偶也不懂IAR)

基于ARM的单片机通常有“存储器控制器”,它负责把ARM产生的地址映射到不同类型的存储器中。要完成remap工作,就要在程序中手工编程它的寄存器,使它把RAM的地址认定为0.一般单片机的零地址对应Flash。

代码搬移工作,不管用C还是用汇编写程序,通常也是手工完成的。代码搬移要建立在对不同段的位置有精确的设置基础上,尤其是对于用C语言写的程序,指导CRT代码正确地初始化RW和ZI段到期望的RAM地址,也使烧写工具正确地把RO段烧到flash中。如果没有定好位,就可能发生把RO段搬移到RAM中后,却把RW、ZI段给覆盖了的情况使程序崩溃。

通常是先remap,再代码搬移,然后视情况跳转到零重新执行。代码的搬移不一定都是把RO区的内容一成不变地搬移。





本贴被 bluelucky 编辑过,最后修改时间:2008-11-30,14:39:07.

出0入0汤圆

发表于 2008-11-30 14:39:58 | 显示全部楼层
;初始化C程序运行环境,然后进入C程序代码

        IMPORT      |Image$$RO$$Limit|           

        IMPORT      |Image$$RW$$Base|

        IMPORT      |Image$$ZI$$Base|

        IMPORT      |Image$$ZI$$Limit|

        IMPORT      Main                            ;声明C程序中的Main函数

        

        

        AREA        Start,CODE,READONLY

        ENTRY

        CODE32

RESET   LDR         SP,=0x40003F00

        LDR         R0,=|Image$$RO$$Limit|      ;RO段结束地址加1 ,表示RO区末地址后面的地址,即RW数据源的起始地址,应该是RW的加载地址

        LDR         R1,=|Image$$RW$$Base|      ;RW区在RAM里的执行区起始地址,也就是编译器选项RW_Base指定的地址,应该是RW运行地址

        LDR         R3,=|Image$$ZI$$Base|      ;ZI区在RAM里面的起始地址

        

        CMP         R0,R1

        BEQ         LOOP1                           ;R0与R1相等就跳转            

LOOP0   CMP         R1,R3                           ;R1小于R3 

        LDRCC       R2,[R0],#4                          

        STRCC       R2,[R1],#4

        BCC         LOOP0

; COPY ROM TORAM       

        

LOOP1   LDR         R1,=|Image$$ZI$$Limit|

        MOV         R2,#0

LOOP2   CMP         R3,R1

        STRCC       R2,[R3],#4                      ;

        BCC         LOOP2                           ;R3小于0,跳转到LOOP2

  ; ZI清零      

        B           Main

        END

;一个arm由RO,RW,ZI三个断组成 其中RO为代码段,RW是已经初始化的全局变量,ZI是未初始化的全局变量(对于GNU工具 对应的概念是TEXT ,DATA,BSS)bootloader 

;bootloader要将RW段复制到ram中并将ZI段清零 编译器使用下列段来记录各段的起始和结束地址 



; |Image$$RO$$Base| ; RO段起始地址 2

; |Image$$RO$$Limit| ; RO段结束地址加1 ,表示RO区末地址后面的地址,即RW数据源的起始地址

; |Image$$RW$$Base| ; RW段起始地址 

; |Image$$RW$$Limit| ; RW段结束地址加1 

; |Image$$ZI$$Base| ; ZI段起始地址 

; |Image$$ZI$$Limit| ; ZI段结束地址加1



;IMPORT |Image$$RO$$Limit| ; End of ROM code (=start of ROM data) 

;IMPORT |Image$$RW$$Base| ; Base of RAM to initialise 

;IMPORT |Image$$ZI$$Base| ; Base and limit of area 

;IMPORT |Image$$ZI$$Limit| ; to zero initialise 

;IMPORT Main ; The main entry of mon program 

;大总结!!!!!!!!!!!!!映像一开始总是存储在ROM/Flash里面的,其RO部分既可以在ROM/Flash里面执行,也可以转移到速度更快的RAM中执行;而RW和ZI这两部分是必须转移到可写的RAM里去。所谓应用程序执行环境的初始化,就是完成必要的从ROM到RAM的数据传输和内容清零。

;R0是RW区的load address

;R1是RW区的execution address

;当两者相等时就不用拷贝

;不相等时,程序先把ROM里|Image$$RO$$Limt|开始的RW初始数据拷贝到RAM里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Image$$ZI$$Limit|





这个启动程序,是为下面C语言程序做准备的,其实这个程序很有意义,为以后自己写C程序建立了环境

#define     uint8       unsigned char

#define     uint32      unsigned int

#define     N           100

uint32      sum;

//计算1加到N N是大于0的数

void Main(void)

{

uint32 i;

sum=0;

  for(i=0;i<N;i++)

  {

   sum+=i;

  }

while(1);

}



非常感谢网上的朋友写的日志,看了你们的日志我才慢慢弄懂是启动是怎么会事情





----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



刚刚接触这方面.上面一段是在网上COPY的,看了很久,也没有明白倒底是怎么回事.我有以下几个问题想问一下,在此先谢谢了.



1:    IMPORT      |Image$$RO$$Limit|           

        IMPORT      |Image$$RW$$Base|

        IMPORT      |Image$$ZI$$Base|

        IMPORT      |Image$$ZI$$Limit|

这个里面的IMPORT      |Image$$RO$$Limit|  是编译器的固定写法吗?哪儿有这方面的资料?



2:";bootloader要将RW段复制到ram中并将ZI段清零 编译器使用下列段来记录各段的起始和结束地址 "

   刚开始是把编译好的代码下载并存储到ROM/Flash中.ARM芯片上电启动时,都靠bootloader把相应在代码copy到指定的地方.是不是只要提供几个地址参数,bootloader就可以自动的每次将代码copy到指定的地方.觉得这里很神奇.也不知道,我的理解是不是正确的?





3:

;R0是RW区的load address

;R1是RW区的execution address

;当两者相等时就不用拷贝

;不相等时,程序先把ROM里|Image$$RO$$Limt|开始的RW初始数据拷贝到RAM里面|Image$$RW$$Base|开始的地址,当RAM这边的目标地址到达|Image$$ZI$$Base|后就表示RW区的结束和ZI区的开始,接下去就对这片ZI区进行清零操作,直到遇到结束地址|Image$$ZI$$Limit|



load address 与execution address最根本的区别是什么?这儿很模糊.当两者相等时,也是load address与execution address的地址是一们的,这两个地址是一样的,是不是说明RW段,ZI段就是同一个段.既然是同一个段,那么为什么又要分load address与execution address呢?





谢谢了...

出0入0汤圆

发表于 2008-11-30 15:08:53 | 显示全部楼层
1.这是ARM官方工具约定的写法。在ADS或RealView的帮助中应该有(推荐从http://infocenter.arm.com/help/index.jsp中下载RealView的官方中文版)

2. RW与ZI的初始化其实一点都不神秘。对于RW,只是把一段数据装填到一个指定的地方,因此只需在RO中给出待装填的内容(全局变量与静态变量初值)以及要装填的地址就可以了(跟发货没大区别)。ZI就更简单了,只是要清洗一段内存,于是只给出地址范围就可以了。

3. 无需太抠它的字眼。寄存器R0指向存储在RO区中的,待装填到RW地址范围的数据。RO区还包含了我们的程序代码,而这些待装填物通常放到代码的后面。装填物的结束地址后面,就是定义ZI位置与长度数据的起始地址。load address就是指在RO区待装填内容的存储地址。execution address就是在2中提到的需要装填目的地的地址——也就是在RAM中,真正的RW段起始地址。编译连接工具已经把我们程序中对变量名的引用,解析成对RW区中存储该变量的地址的引用。

RW段与ZI段不是同一段。load address与execution address与ZI段无关

出0入0汤圆

发表于 2008-11-30 16:44:19 | 显示全部楼层
非常感谢!!

出0入0汤圆

发表于 2008-11-30 16:46:10 | 显示全部楼层
good !!

tks !!

出0入0汤圆

发表于 2008-11-30 18:18:18 | 显示全部楼层
非常感谢bluelucky网友,还不是很懂,感觉要先看看ARM的汇编语句才好理解这些例程里的启动代码。接着看书……

出0入0汤圆

发表于 2008-12-1 01:36:34 | 显示全部楼层
谢谢鼓励^_^

如果学习基础指令和汇编语言,推荐一本《从51到ARM》的书,赵星寒,刘涛 编著

比《ARM体系结构与编程》好懂,也更体贴

出0入0汤圆

发表于 2008-12-1 08:26:06 | 显示全部楼层
mark,有时间细读

出0入0汤圆

发表于 2008-12-1 08:51:00 | 显示全部楼层
从51到ARM不错,不过看完最好再看ARM体系结构与编程。

很多东西多啃几遍书就很明白了

出0入0汤圆

发表于 2008-12-1 10:18:18 | 显示全部楼层
谢谢,不错,如果能详解下CM3的启动过程,相信很多人感兴趣

本贴被 hkap 编辑过,最后修改时间:2008-12-01,10:20:25.

出0入0汤圆

发表于 2008-12-1 10:37:45 | 显示全部楼层
额,CM3的也差不多,CM3也是ARM额

出0入0汤圆

发表于 2008-12-1 11:00:08 | 显示全部楼层
学习

出0入0汤圆

发表于 2008-12-1 12:19:41 | 显示全部楼层
to 26楼:

《Cortex-M3权威指南》中讲到了CM3的复位工序,可以去看

出0入0汤圆

发表于 2008-12-1 13:00:34 | 显示全部楼层
请问,启动代码.S文件里最后的堆栈空间设置怎么理解?一般怎么去根据自己思路设定堆栈大小?

; User Initial Stack & Heap

                AREA    |.text|, CODE, READONLY



                IMPORT  __use_two_region_memory

                EXPORT  __user_initial_stackheap

__user_initial_stackheap



                LDR     R0, =  Heap_Mem

                LDR     R1, =(Stack_Mem + USR_Stack_Size)

                LDR     R2, = (Heap_Mem +      Heap_Size)

                LDR     R3, = Stack_Mem

                BX      LR

出0入0汤圆

发表于 2008-12-1 13:09:17 | 显示全部楼层
mark!

出0入4汤圆

发表于 2008-12-1 18:53:55 | 显示全部楼层
复杂!

出0入0汤圆

发表于 2008-12-2 09:38:28 | 显示全部楼层
 谢谢 bluelucky 



还有个问题



一般中断向量表的程序实现通常如下表示:  

 AREA Boot ,CODE, READONLY  

 ENTRY  

 B  ResetHandler  

 B  UndefHandler  

 B  SWIHandler  

 B  PreAbortHandler  

 B  DataAbortHandler  

 B  IRQHandler  

 B  FIQHandler  



但ARM的中断很多;一旦发生中断后,是不是跳到上面的中断向量表去 ?上面的中断向量表是怎么区分这么多的中断源,比如外部中断1和外部中断13发生后,程序是怎么走的?



谢谢了

出0入0汤圆

发表于 2008-12-2 10:06:48 | 显示全部楼层
一般的非CM3 ARM单片机,是先跳到IRQHandler,由IRQHandler再去读取中断控制器的寄存器,来分析具体是什么中断源,因此实际上是2级分发,这实时性不好。因此,有些ARM单片机硬件实现向量中断:全程监视ARM核的取指过程,一旦侦测到取指目的地是0x18的,就在硬件上自动分析应该该响应哪个具体的中断,并且自动生成一条跳转到该ISR首地址的B指令(4字节的数据)送给ARM核,于是就会直接跳往该ISR,而原先写在0x18处的指令则被架空了

在CM3中就清爽多了。CM3在0地址处存储一张向量表,并且直接支持240个中断。内建的中断控制器会识别出中断号,并且从向量表中直接取出该中断的ISR地址,从而跳到ISR中

出0入0汤圆

发表于 2008-12-2 11:17:26 | 显示全部楼层
好强悍的贴啊

出0入0汤圆

发表于 2008-12-2 11:38:00 | 显示全部楼层
jh 

出0入0汤圆

发表于 2008-12-2 12:57:52 | 显示全部楼层
再次谢谢 bluelucky 的耐心详细的指导

接着问

在CM3启动代码中

*******************************************************************************

; Fill-up the Vector Table entries with the exceptions ISR address

;*******************************************************************************

                 AREA    RESET, DATA, READONLY

                 EXPORT  __Vectors

                      

__Vectors        DCD  __initial_sp              ; Top of Stack

                 DCD  Reset_Handler

                 DCD  NMIException

                 DCD  HardFaultException

                 DCD  MemManageException

                 DCD  BusFaultException

                 DCD  UsageFaultException

                 DCD  0                 ; Reserved

                 DCD  0                 ; Reserved

                 DCD  0                 ; Reserved

                 DCD  0                 ; Reserved

                 DCD  SVCHandler

                 DCD  DebugMonitor

                 DCD  0                 ; Reserved

                 DCD  PendSVC

                 DCD  SysTickHandler

                 DCD  WWDG_IRQHandler

                 DCD  PVD_IRQHandler

                 DCD  TAMPER_IRQHandler

                 DCD  RTC_IRQHandler

                 DCD  FLASH_IRQHandler

                 DCD  RCC_IRQHandler

                 DCD  EXTI0_IRQHandler

                 DCD  EXTI1_IRQHandler

                 DCD  EXTI2_IRQHandler

                 DCD  EXTI3_IRQHandler

                 DCD  EXTI4_IRQHandler

                 DCD  DMAChannel1_IRQHandler

                 DCD  DMAChannel2_IRQHandler

                 DCD  DMAChannel3_IRQHandler

                 DCD  DMAChannel4_IRQHandler

                 DCD  DMAChannel5_IRQHandler

                 DCD  DMAChannel6_IRQHandler

                 DCD  DMAChannel7_IRQHandler

                 DCD  ADC_IRQHandler

                 DCD  USB_HP_CAN_TX_IRQHandler

                 DCD  USB_LP_CAN_RX0_IRQHandler

                 DCD  CAN_RX1_IRQHandler

                 DCD  CAN_SCE_IRQHandler

                 DCD  EXTI9_5_IRQHandler

                 DCD  TIM1_BRK_IRQHandler

                 DCD  TIM1_UP_IRQHandler

                 DCD  TIM1_TRG_COM_IRQHandler

                 DCD  TIM1_CC_IRQHandler

                 DCD  TIM2_IRQHandler

                 DCD  TIM3_IRQHandler

                 DCD  TIM4_IRQHandler

                 DCD  I2C1_EV_IRQHandler

                 DCD  I2C1_ER_IRQHandler

                 DCD  I2C2_EV_IRQHandler

                 DCD  I2C2_ER_IRQHandler

                 DCD  SPI1_IRQHandler

                 DCD  SPI2_IRQHandler

                 DCD  USART1_IRQHandler

                 DCD  USART2_IRQHandler

                 DCD  USART3_IRQHandler

                 DCD  EXTI15_10_IRQHandler

                 DCD  RTCAlarm_IRQHandler

                 DCD  USBWakeUp_IRQHandler 



这个是必需要按照中断的优先顺序写的吗?这个表还有没有其他的作用的?

出0入0汤圆

发表于 2008-12-2 13:05:58 | 显示全部楼层
这贴要顶一下

出0入0汤圆

发表于 2008-12-2 14:52:25 | 显示全部楼层
下一个MDK评估版打开一个例程就能看到怎么配置了

出0入8汤圆

发表于 2008-12-2 15:26:59 | 显示全部楼层
我发个在开源杂志上看到的有用的文章(也可以下载开源杂志原pdf格式看,这个在第11期中:



 (原文件名:C_Documents and Settings_Administrator_桌面_opensource11_2008111.jpg) 





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008112.jpg)&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008112.jpg)&nbsp;</a>



&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008113.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008114.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008115.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008116.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008117.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource11_2008118.jpg)&nbsp;

下面是MMU和cache(在第8期中):



&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080801.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080802.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080803.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080804.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080805.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080806.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080807.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080808.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080809.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080810.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080811.jpg)&nbsp;





&nbsp;(原文件名:C_Documents&nbsp;and&nbsp;Settings_Administrator_桌面_opensource8_20080812.jpg)&nbsp;

本贴被 kebaojun305 编辑过,最后修改时间:2008-12-02,15:39:18.

出0入0汤圆

发表于 2008-12-2 16:31:57 | 显示全部楼层
强帖

出0入0汤圆

发表于 2008-12-26 10:42:39 | 显示全部楼层
mark

出0入0汤圆

发表于 2008-12-26 11:36:43 | 显示全部楼层
记号

出0入0汤圆

发表于 2008-12-26 17:22:41 | 显示全部楼层
很好,学习了,但是还是不大明白其中的奥妙

出330入0汤圆

发表于 2008-12-26 19:30:58 | 显示全部楼层
很抽象,留到以后再看

出0入0汤圆

发表于 2009-1-1 13:10:21 | 显示全部楼层
很好,学习了!





45楼的杂志下载地址&nbsp;http://oss.linuxpk.com

出0入0汤圆

发表于 2009-1-1 14:45:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-1-4 15:51:31 | 显示全部楼层
还是没有人讲讲RO的搬运过程啊?

出330入0汤圆

发表于 2009-1-4 15:53:03 | 显示全部楼层
我真是可惜啊,现在没有搞ARM,否则可以跟上进度了。

出200入0汤圆

发表于 2009-1-4 21:14:05 | 显示全部楼层
MARK~~

出0入0汤圆

发表于 2009-1-4 22:27:01 | 显示全部楼层
基本上弄明白,之前做过MSP430自升级也做过一个小的引导程序,不过ARM的好像更加复杂了!

出0入0汤圆

发表于 2009-1-13 10:50:15 | 显示全部楼层
mark.学习了

出0入0汤圆

发表于 2009-1-13 12:02:37 | 显示全部楼层
学习了

出0入0汤圆

发表于 2009-1-14 16:14:34 | 显示全部楼层
记号,记号,记号

出0入0汤圆

发表于 2009-1-15 21:32:29 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-1-15 22:19:17 | 显示全部楼层
经典呀。。。

出0入0汤圆

发表于 2009-1-16 08:50:20 | 显示全部楼层
搬运RO段其实也跟memcpy()函数做的工作差不多。只是在搬运后,可能要为RO段中的代码设置新的启动配置信息

另外,只有位置无关代码才是可搬运的。位置无关代码只允许使用相对寻址方式,&nbsp;通常是相对于PC。如果代码中含有加载立即数并跳转到立即数的地址上去,就要十分小心了,这样的代码几乎都是不可搬运的。

本贴被 bluelucky 编辑过,最后修改时间:2009-01-16,08:51:54.

出0入0汤圆

发表于 2009-1-16 11:34:57 | 显示全部楼层
讲到点子上去了

出0入0汤圆

发表于 2009-1-16 16:06:55 | 显示全部楼层
非常有价值的帖子,想不顶都做不到

出0入0汤圆

发表于 2009-1-16 19:31:22 | 显示全部楼层
最大的困惑是ARM运行在不同存储器时的地址安排,就是配置文件中的段放置。我的理解是:片内RAM时,把ROM和RAM地址都指向片内RAM,相当于将RO、RW、ZI都放置在片内RAM中;而在片外norflash运行的话,将ROm设置为flash地址,RAM为片内RAM或片外SRAM,并将RO段放在ROM区即flash中,将RW、ZI放置在RAM中,初始化过程中,ARM还将自动把RW段拷贝到RAM中,但是norflash的地址怎么写?是原来的0x10000000,还是0x0?至于,将片外flash中的代码拷贝到片内或片外的SRAM内运行的话,RO、RW段的地址到底怎么安排就更迷惑了。



还有关于remap,我一直不理解什么是remap,从片外启动时,片外norflash地址为0x0,这算不算从0x10000000到0x0的remap呢?



请大侠指教,谢谢?

出0入0汤圆

发表于 2009-1-16 20:25:34 | 显示全部楼层
学习了

出0入0汤圆

发表于 2009-1-19 23:12:05 | 显示全部楼层
楼主写得东西我在书上看到了,基本上一模一样,

不知楼主是不是那本书的作者,那是一本清华出的,南京一个大学几位老师写的

出0入0汤圆

发表于 2009-1-20 01:27:48 | 显示全部楼层
标记!

出0入0汤圆

发表于 2009-4-23 18:37:50 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-23 20:36:59 | 显示全部楼层
看大家讨论的比较热烈,说一些也许有人还没有注意到的东西,供讨论。
这里主要针对ARM9以及以前的体系结构。Cortex-M系列的,我正在看手册,修改的东西太多了,暂不讨论。

·中断向量表
中断向量表,通常大家看到的是从0地址开始。但是:通过设置CP15,中断向量可以是FFFF0000开始,32Bytes。
这个在有MMU的系统上很重要:通过这个映射,就把0地址腾空了。这样,任何读写空指针都会导致Abort模式异常。对于没有操作系统的程序调试,依然很有意义。

·关键字Entry
特别注意,Entry只是指明程序入口,这个是elf文件中,有一个字段说明程序起始地址。
如果代码中只有一个Entry的话,那么elf的入口就是这个entry。否则,就需要在连接器指定入口地址,这个入口就不一定非要是Entry,任何一个Export的标号都是可以的。
Entry,把elf/axf转换为bin之后,入口在什么地方。BIN只是把elf根据给定的内存模型,转换成为的纯数据文件。

·初始化顺序
一般考虑:外部总线时序 -> PLL和时钟等 -> SDRAM -> MMU -> 初始化堆栈。
很多裸奔或者小OS的,往往会忽略MMU的。
堆栈初始化注意,切记要8Byte对齐。否则在新的编译器上,运行的时候会出问题。

·对于段起始和边界
Image$$RO$$Base 类似这样的描述,是Linker提供的,用于段定位的东西。
如果初始化了C运行库,建议运行库来干,不要用户自己来操作。
特别需要注意,如果用了Scatter[分散加载],并且使用了复杂的Scatter结构,那么,Image这样的符号是不一定会存在的。那时候,最好用C运行库初始化,否则就要查Linker手册,确认每个Exec Section用的是什么符号。

·对11楼bluelucky的补充
ZI区域不一定清零。
首先是Scatter有多个ZI区域,这时候,Image$$ZI那个就不存在了。因为没办法定义。此时C运行库初始化依然能正常,因为它用的是ZI$$Table这个数据区。
然后在Exec属性里,如果有UNINIT,这样的ZI区是不会被初始化的。

Cortex-M3的速度,还是要看具体的RAM/ROM如何挂在Core的总线上。TCM还是AHB,是否经过仲裁还是如何,等等。

·对于RO,RW,ZI
如果开了MMU的话,可以针对不同的操作属性进行不同的映射。比如RO的数据可以写保护,等等。


·对于Load/Exec Region
这是RealView编译器系统定义的。
Load Region是Image被加载到的地址区域。Exec Region是最终程序运行/使用的时候的地址区域。
必须有一个Load == Exec的地址,这个是主区,复制代码等等的操作都要在这里才行。想下也是这样。

·To 48# RO的搬运
分两类,一类是代码/只读变量(const),Code,Load/Exec地址不一致的情况,需要把数据从Image的指定位置,移动到Exec的指定位置。
一类是RW数据,这个前边说过了。

·To 57# bluelucky
RO代码的搬运操作和代码的位置无关特性没有关系。
我认为,RVCT之所以这么设计,是为了这样的情况:
- 用户用了MMU,程序运行的时候,加载地址很分散,比如0x90000000是操作系统内核;0xA0000000是Driver的库。
- 用户只有一个Flash,用来装载原始的BIN文件。
这样,BIN到实际内存肯定不是1:1的映射,这样会死人,因此需要搬运。Image是Linker生成的,因此,即便位置相关的代码,也是可以编译,并且被压缩到一起的,只不过,搬运目的地错了,不能运行而已。

位置无关代码可以随便搬运,RO不一定能随便搬运,这就是区别。

出0入0汤圆

发表于 2009-4-23 21:35:49 | 显示全部楼层
dr2001 牛人啊,谢谢,有些还没看懂,留个记号。

好奇做什么工作的,ARM公司的?

出0入0汤圆

发表于 2009-4-23 22:11:56 | 显示全部楼层
不是ARM的,本职和这些关系不是很大,随便研究研究而以。

其实,一切在文档里密密麻麻的写的很清楚,关键在于,是不是愿意一页一页去爬文档。

出0入0汤圆

发表于 2009-4-23 22:58:17 | 显示全部楼层
其实,一切在文档里密密麻麻的写的很清楚,关键在于,是不是愿意一页一页去爬文档。

————————————————————————

是啊,可惜大部分人都像我一样,都期望别人告诉下一步具体怎么做,而不是自己琢磨,看到密密麻麻的英文文档就头大了

出0入0汤圆

发表于 2009-4-23 22:59:31 | 显示全部楼层
学习了

出0入0汤圆

发表于 2009-4-24 15:40:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-4-24 17:07:25 | 显示全部楼层
支持一个

出0入0汤圆

发表于 2009-5-14 21:21:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-5-17 01:34:15 | 显示全部楼层
凶狠~~

出0入0汤圆

发表于 2009-5-23 09:24:56 | 显示全部楼层
记号,以后再看

出0入0汤圆

发表于 2009-5-25 23:06:48 | 显示全部楼层
学习

出0入0汤圆

发表于 2009-5-27 15:02:43 | 显示全部楼层
怎么 mark啊。。。。论坛新手

出0入0汤圆

发表于 2009-6-16 10:59:50 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-6-16 11:46:47 | 显示全部楼层
我的英文也很差,呵呵。
最近也看了一下启动。
对于中断向量,CM3我认为做的很好,采用的是向量方式,而2440不是向量模式,其实2440是一个中断,所以普通中断都进入一个中断里面,在那里面还要好多条代码判断到底是那个中断,然后再通过代码跳转过去,这样实时性就差多了。在CM3中已经不再分什么快速中断和普通中断了,已经没有必要了。不过多了个非屏蔽中断,反正我认为这样更实际一些。
    对于重映射,其实有两种方法,一种是硬件上通过指令来切换的,相当于FLASH和RAM都不在启动的0地址上,只上复位后默认将FLASH映射过去,而当把代码全部(或者部分)复制到RAM里面的时候,再映射过去。这样就相当于把RAM地址落在了0上,其实在原来的位置照样还是可以访问到FLASH和RAM上的。只是为了方便程序高速运行。这个比较简单,当然功能就不是很强了。CM3是用这种方式的。
    对于另外一些带MMU的芯片,其实是通过MMU来改变了地址。其实也是在启动的时候先把FLASH(因为一般这种方式下都用NAND FLASH)内容搬到RAM(或者是SDRAM,当然要先初始化),然后再通过MMU改变一下地址,相当于重映射,把SDRAM开始地址指到0上。因为ARM核访问的时候给出的地址不是直接送到外部地址总线上的,是送给了MMU,所以举例来说,如果发生中断,要向0X18处取指令,此地址发给了MMU,而在MMU会将这个地址改变到SDRAM里面,例如是0X30000018,这样代码根本没感觉有区别,代码好象就是在0X18处取到指令了。当然MMU的功能不只这些,只是与地址相关的功能有这点。
    最近用MDK编写2440的程序,感觉很不方便,所以自己做了几个改进。这样基本就可以在后续工作中简单工作了。当然我也是初学,启动代码肯定还是别人的强。我只是想实现一下裸奔,呵呵。
    修改了MDK的NAND FLASH烧写功能,能够将BOOT代码和自己的程序代码写到NAND FLASH里面,并且不会冲突。
    自己写了启动代码,实现上电的时候初始化一下环境,把自己的工作代码加载到SDRAM里面,同时没有利用MMU,而是直接修改了启动中的中断向量,将所有中断指向用户程序中。
    最后当然就是直接跳到用户程序中运行。至于用户程序怎么操作那就不管了,呵呵。不过在这里用户程序可以不用初始化时钟、SDRAM,可以直接使用了。

出0入0汤圆

发表于 2009-6-16 20:02:42 | 显示全部楼层
armok

出0入0汤圆

发表于 2009-6-20 13:55:58 | 显示全部楼层
问一下mark是什么意思!!

出0入0汤圆

发表于 2009-6-22 14:20:16 | 显示全部楼层
写的很好,Mark。

出0入0汤圆

发表于 2009-7-3 09:37:51 | 显示全部楼层
谢了

出0入4汤圆

发表于 2009-7-3 09:44:34 | 显示全部楼层
标记

出0入0汤圆

发表于 2009-7-9 23:15:27 | 显示全部楼层
先mark...最近在初学ARM9...谢谢楼主的分享!

出0入0汤圆

发表于 2009-7-17 19:32:17 | 显示全部楼层
这么多大图,看得有点窒息。哈哈

出0入0汤圆

发表于 2009-7-18 16:25:21 | 显示全部楼层
记下了

出0入0汤圆

发表于 2009-7-24 20:42:54 | 显示全部楼层
顶下

出0入0汤圆

发表于 2009-7-31 19:23:14 | 显示全部楼层
先mark...最近在初学ARM9...谢谢楼主的分享!

出0入0汤圆

发表于 2009-7-31 23:26:34 | 显示全部楼层
重新记一次

出0入0汤圆

发表于 2009-8-1 08:02:07 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-8-1 10:36:54 | 显示全部楼层
学习中............

出0入0汤圆

发表于 2009-8-1 11:20:08 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-8-5 16:00:42 | 显示全部楼层
哈哈,标记

出0入0汤圆

发表于 2009-8-5 17:42:06 | 显示全部楼层
记号

出0入0汤圆

发表于 2009-8-16 17:59:22 | 显示全部楼层
mark ,谢谢了

出0入0汤圆

发表于 2009-8-20 11:23:10 | 显示全部楼层
mark,很有收获

出0入0汤圆

发表于 2009-8-20 23:30:46 | 显示全部楼层
很不错,谢谢啦

出0入0汤圆

发表于 2009-8-31 03:53:30 | 显示全部楼层
很好的资料

出0入0汤圆

发表于 2009-8-31 10:26:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-8-31 20:22:23 | 显示全部楼层
学习
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 09:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表