历史上的今天
返回首页

历史上的今天

今天是:2024年11月12日(星期二)

正在发生

2019年11月12日 | ARM2440的启动模式

2019-11-12 来源:51hei

研究arm也有2个月了,现在才感觉理解了arm在Nand flash模式下的启动过程,现在来这里记录下来以表达我无比喜悦的心情。闲话少说,趁着还没有忘记学习过程中的感受,直接进入正题。

大家都知道,arm在Nand flash启动模式下启动时系统会将Nand flash中的前4KB代码拷贝到SRAM(也就是Steppingstone中),由SRAM配置中断向量表和完成Nand flash访问的必要初始化,然后将Nand flash中的全部程序代码拷贝到SDRAM中,最后由SRAM跳转到SDRAM,然后程序就正常执行了,这一过程看上去很简单,但是真正理解这一过程还是不简单的,尽管这样,还是想告诉大家仔细理解还是比较容易理解这个过程的。如果您是ADS用户,你省去了很多麻烦,但我不确定你省去的这些麻烦是否值得,这里介绍的是一种麻烦的方式,linux下的led程序。


代码Head.s

  • .extern main

  • .text

  • .global _start

  • _start:

  •     b reset


  • reset:

  •     ldr sp,=4096

  •     bl disable_watch_dog

  •     bl clock_init

  •     bl memsetup

  •     bl copy_steppingstone_to_sdram

  •     ldr pc,=on_sdram


  • on_sdram:

  •     msr cpsr_c,#0xdf

  •     ldr sp,=0x34000000

  •     ldr lr,=halt_loop

  •     ldr pc,=Main


  • halt_loop:

  •     b halt_loop



我认为,最需要理解的就是这段代码了。先简单的解释下这段代码。


(1)由于arm执行reset之后pc会被清零,也就是reset中断的中断入口地址,因此,第一条指令就是b reset,跳转到reset中断处理函数。


(2)由于这里硬件配置都是C语言来完成的,而且我们的初始代码比较小,完全不会超出4KB,因此可以在SRAM使用堆栈,故将SP设置为4096,以提供C运行环境


(3)接下来的3个bl分别完成了关闭看门够定时器,配置时钟信号和存储器配置的工作,第四个bl是将SRAM的4KB空间内的代码拷贝到了SDRAM中。


(4)接下来的ldr句将pc赋值为on_sdram的地址,实现了从SRAM到SDRAM的跳转(下面会讲为什么)


(5)on_sdram中切换到了了系统模式然后分配了系统模式堆栈,将链接寄存器设置为halt_loop然后就跳转到了SDRAM中的Main


上面的解释只是大体上说明了代码的意思,但是初学者总会有个疑问就是为什么ldr pc,=on_sdram就实现了从SRAM到SDRAM的跳转呢?我被这个问题困扰了很长时间,到今天才想明白了这个问题,问题的关键就是相对跳转和绝对跳转的问题。为了说明这个问题我先解释一下bl指令跟ldr指令在执行过程中的区别。


B指令是相对跳转指令,B 指令是最简单的跳转指令。一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间),同样的,BL、BX都是相对跳转。


LDR伪指令是将第二操作直接赋值给第一操作数,当执行ldr pc,=Main时是将Main的绝对地址赋值给了PC。


好了,知道这两个指令的区别之后我们来看代码是如何实现的从SRAM到SDRAM的跳转,首先需要指出,2440的开发板有SRAM和SDRAM,SRAM是从地址0x00000000开始的4KB内存空间,SDRAM是从0x30000000开始的64M空间。


无论用ADS编译还是用arm-linux-gcc编译都会将代码链接到0x30000000以后(也就是SDRAM中),ADS用户可以通过查看ADS的工程配置,其中有项配置是RO起始地址是0x30000000,linux用户在链接时需要用-T指定代码的其实地址为0x30000000。


根据编译原理,在链接阶段程序中函数的地址就已经确定了,也就是说函数的实际地址都在0x30000000之后,而程序的入口函数也就是这里的_start的地址就是0x300000000,其他函数都会大于这个数。


但是由于arm上电后系统会将Nand flash的前4KB代码拷贝到SRAM中,也就是_start函数开始的4KB指令将被拷贝到SRAM中执行,根据上例,在0x00000000处执行的指令就是“b reset”,由于b是相对跳转,是在当前pc值的基础上加减某个数而跳转到将要执行的代码处,因此,pc加减该数之后将到达reset函数的位置,故reset函数不能写到4KB之外的空间中,否则arm的启动将会失败,同样的,接下来的几个bl都是执行的相对跳转,所以都相对当前pc进行的跳转,由于Nand flash总共只有64M的空间,所以相对跳转是不可能会跳转到SDRAM的,因为跳转到SDRAM至少要发生0x30000000的跳转,而这个相对位移远远大于64M。

而ldr pc,=Main是将Main函数的实际地址赋值给pc,而Main的实际地址是在0x30000000之后,这样,就从SRAM跳转到了SDRAM。


由于这个过程设计到了硬件格局和编译原理,所以对一般人来讲,理解起来确实比较困难,而且受本人水平限制,很多地方只能说是只可意会不可言传,如果误导了大家请大家谅解。当然如果看到这里还不能理解arm的启动过程可以联系QQ630905224来讨论这个问题。下面是相关的其他代码,我附在这里,2440addr.h没有贴出,由于我也是使用arm自带示例程序中的代码,而且代码有四千多行,多数地址是没有用到的,如果有人需要就联系我的QQ吧。其他的代码如下


代码Init.s

  • #include "2440addr.h"


  • void disable_watch_dog(void);

  • void clock_init(void);

  • void memsetup(void);

  • void copy_steppingstone_to_sdram(void);

  • void inituart(void);


  • void disable_watch_dog(void)

  • {

  •     rWTCON = 0;

  • }


  • void clock_init(void)

  • {

  •     rCLKDIVN  = 0x03;


  •     /*

  •      *如果HDIVN非0,CPU的总线模式应该从

  •      *“fast bus mode”变为“asynchronous

  •      *bus mode”

  •      */

  •     __asm__(

  •             "mrc    p15, 0, r1, c1, c0, 0n"

  •             "orr    r1, r1, #0xc0000000n"

  •             "mcr    p15, 0, r1, c1, c0, 0n"

  •            );


  •     rMPLLCON = (92<<12)|(1<<4)|(2);

  •     //rMPLLCON =  ((0x5c<<12)|(0x01<<4)|(0x02));

  • }


  • void memsetup(void)

  • {

  •     volatile unsigned long *p = (volatile unsigned long *)0x48000000;


  •     /* 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值

  •      * 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到

  •      * SDRAM之前就可以在steppingstone中运行

  •      */

  •     /* 存储控制器13个寄存器的值 */

  •     p[0] = 0x22011110;     //BWSCON

  •     p[1] = 0x00000700;     //BANKCON0

  •     p[2] = 0x00000700;     //BANKCON1

  •     p[3] = 0x00000700;     //BANKCON2

  •     p[4] = 0x00000700;     //BANKCON3

  •     p[5] = 0x00000700;     //BANKCON4

  •     p[6] = 0x00000700;     //BANKCON5

  •     p[7] = 0x00018005;     //BANKCON6

  •     p[8] = 0x00018005;     //BANKCON7


  •     /* REFRESH,

  •      * HCLK=12MHz:  0x008C07A3,

  •      * HCLK=100MHz: 0x008C04F4

  •      */

  •     p[9]  = 0x008C04F4;

  •     p[10] = 0x000000B1;     //BANKSIZE

  •     p[11] = 0x00000030;     //MRSRB6

  •     p[12] = 0x00000030;     //MRSRB7

  • }


  • void copy_steppingstone_to_sdram(void)

  • {

  •     unsigned int *pdwSrc  = (unsigned int *)0;

  •     unsigned int *pdwDest = (unsigned int *)0x30000000;


  •     while (pdwSrc < (unsigned int *)4096)

  •     {

  •         *pdwDest = *pdwSrc;

  •         pdwDest++;

  •         pdwSrc++;

  •     }

  • }


=======================================================================

一般而言,一个程序包括只读的代码段和可读写的数据段。在ARM的集成开发环境中,只读的代码段和常量被称作RO段(ReadOnly);可读写的全局变量和静态变量被称作RW段(ReadWrite);RW段中要被初始化为零的变量被称为ZI段(ZeroInit)。对于嵌入式系统而言,程序映象都是存储在Flash存储器等一些非易失性器件中的,而在运行时,程序中的RW段必须重新装载到可读写的RAM中。这就涉及到程序的加载时域和运行时域。简单来说,程序的加载时域就是指程序烧入Flash中的状态,运行时域是指程序执行时的状态。对于比较简单的情况,可以在ADS集成开发环境的ARM LINKER选项中指定RO BASE和RW BASE,告知连接器RO和RW的连接基地址。对于复杂情况,如RO段被分成几部分并映射到存储空间的多个地方时,需要创建一个称为“分布装载描述文件”的文本文件,通知连接器把程序的某一部分连接在存储器的某个地址空间。需要指出的是,分布装载描述文件中的定义要按照系统重定向后的存储器分布情况进行。在引导程序完成初始化的任务后,应该把主程序转移到RAM中去运行,以加快系统的运行速度。


什么是arm的映像文件,arm映像文件其实就是可执行文件,包括bin或hex两种格式,可以直接烧到rom里执行。在axd调试过程中,我们调试的是axf文件,其实这也是一种映像文件,它只是在bin文件中加了一个文件头和一些调试信息。映像文件一般由域组成,域最多由三个输出段组成(RO,RW,ZI)组成,输出段又由输入段组成。所谓域,指的就是整个bin映像文件所处在的区域,它又分为加载域和运行域。加载域就是映像文件被静态存放的工作区域,一般来说flash里的 整个bin文件所在的地址空间就是加载域,当然在程序一般都不会放在 flash里执行,一般都会搬到sdram里运行工作,它们在被搬到sdram里工作所处的地址空间就是运行域。


我们输入的代码,一般有代码部分和数据部分,这就是所谓的输入段,经过编译后就变成了bin文件中ro段和rw段,还有所谓的zi段,这就是输出段。对于加载域中的输出段,一般来说ro段后面紧跟着rw段,rw段后面紧跟着zi段。在运行域中这些输出段并不连续,但rw和zi一定是连着的。zi段和rw段中的数据其实可以是rw属性。


      Image

RO


Base| |Image

RO
Limit| |Image

RW


Base| |Image

ZI


Base| |Image

ZI


Limit|这几个变量是编译器通知的,我们在 makefile文件中可以看到它们的值。它们指示了在运行域中各个输出段所处的地址空间。| Image

RO


Base| 就是ro段在运行域中的起始地址,|Image

RO


Limit| 是ro段在运行域中的截止地址。其它依次类推。我们可以在linker的output中指定,在 simple模式中,ro base对应的就是| Image

RO
Base|,rw base 对应的是|Image

RW


Base|,由于rw和zi相连,|Image

ZI


Base| 就等于|Image

ZI


limit| .其它的值都是编译器自动计算出来的。


下面是2410启动代码的搬运部分,我给出注释
            BaseOfROM DCD |Image

RO


Base|
            TopOfROM DCD |Image

RO


Limit|
            BaseOfBSS DCD |Image

RW


Base|
            BaseOfZero DCD |Image

ZI


Base|
            EndOfBSS DCD |Image

ZI


Limit|
            adr r0, ResetEntry;    ResetEntry是复位运行时域的起始地址,在boot nand中一般是0
            ldr r2, BaseOfROM;
            cmp r0, r2
            ldreq r0, TopOfROM;TopOfROM=0x30001de0,代码段地址的结束
            beq InitRam 
            ldr r3, TopOfROM
            ;part 1,通过比较,将ro搬到sdram里,搬到的目的地址从 | Image

RO


Base| 开始,到|Image

RO


Limit|结束
            
            0 
            ldmia r0!, {r4-r7}
            stmia r2!, {r4-r7}
            cmp r2, r3
            bcc %B0;
            
            ;part 2,搬rw段到sdram,目的地址从|Image

RW


Base| 开始,到|Image

ZI


Base|结束
            sub r2, r2, r3;r2=0
            sub r0, r0, r2    
            InitRam ;carry rw to baseofBSS
            ldr r2, BaseOfBSS ;TopOfROM=0x30001de0,baseofrw
            ldr r3, BaseOfZero ;BaseOfZero=0x30001de0
            0
            cmp r2, r3
            ldrcc r1, [r0], #4
            strcc r1, [r2], #4
            bcc %B0 
            ;part 3,将sdram zi初始化为0,地址从|Image

ZI


Base|到|Image

ZI


Limit|
            mov r0, #0;init 0
            ldr r3, EndOfBSS;EndOfBSS=30001e40
            1 
            cmp r2, r3
            strcc r0, [r2], #4
            bcc %B1



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

一 概述

Scatter file (分散加载描述文件)用于armlink的输入参数,他指定映像文件内部各区域的download与运行时位置。Armlink将会根据scatter file生成一些区域相关的符号,他们是全局的供用户建立运行时环境时使用。(注意:当使用了scatter file 时将不会生成以下符号 Image

RW


Base, Image

RW
Limit, Image

RO


Base, Image

RO


Limit, Image

ZI


Base, and Image

ZI


Limit)



二 什么时候使用scatter file

当然首要的条件是你在利用ADS进行项目开发,下面我们看看更具体的一些情况。


1 存在复杂的地址映射:例如代码和数据需要分开放在在多个区域。
2 存在多种存储器类型:例如包含 Flash,ROM,SDRAM,快速SRAM。我们根据代码与数据的特性把他们放在不同的存储器中,比如中断处理部分放在快速SRAM内部来提高响应速度,而把不常用到的代码放到速度比较慢的Flash内。
3 函数的地址固定定位:可以利用Scatter file实现把某个函数放在固定地址,而不管其应用程序是否已经改变或重新编译。
4 利用符号确定堆与堆栈:
5 内存映射的IO:采用scatter file可以实现把某个数据段放在精确的地指处。
因此对于嵌入式系统来说scatter file是必不可少的,因为嵌入式系统采用了ROM,RAM,和内存映射的IO。

推荐阅读

史海拾趣

客益(Guestgood)公司的发展小趣事

机顶盒,全称为数字视频变换盒(Set Top Box,简称STB),是现代家庭娱乐中不可或缺的重要设备。它作为连接电视机与外部信号源的桥梁,主要功能在于接收数字电视信号,并将其转换成适合在电视机上播放的格式。机顶盒不仅能接收来自有线电缆、卫星天线、宽带网络及地面广播的信号,还具备强大的媒体处理能力和交互功能,极大地丰富了用户的观看体验。

从技术层面看,机顶盒经历了从模拟到数字的飞跃式发展。早期的机顶盒主要用于有线电视网络的信号解扰,而现代机顶盒则支持高清、甚至4K超高清视频内容的播放,为用户带来更为细腻的画面和震撼的音效。此外,机顶盒还集成了网络交互功能,用户可以通过机顶盒连接到互联网,享受在线购物、观看网络视频、玩游戏等多元化服务,使电视机从单向接收信息的设备转变为智能互动终端。

随着科技的进步,机顶盒的功能和应用场景也在不断扩展。例如,一些先进的机顶盒支持智能语音控制,用户可以通过语音指令搜索节目、调整设置,极大地提升了使用的便捷性。同时,机顶盒还具备存储功能,用户可以将喜欢的媒体文件存储在机顶盒中,随时通过电视屏幕进行观看,享受个性化的娱乐体验。

综上所述,机顶盒作为家庭娱乐的重要组成部分,不仅承载着传输和显示数字视频信号的基本功能,还通过不断的技术创新和应用拓展,为用户提供了更加丰富、便捷、智能的观影体验。随着技术的不断进步和市场的不断扩大,机顶盒将继续在家庭娱乐领域发挥重要作用。

Electrolube公司的发展小趣事

在电子行业中,电池管理系统(BMS)的可靠性和耐用性一直是制造商关注的焦点。Electrolube公司凭借其在材料科学领域的深厚积累,成功推出了一款名为UVCL的新型UV固化涂层。这款涂层以其独特的特性迅速在市场中脱颖而出。

UVCL涂层采用先进的UV固化技术,能够在几秒钟内完成固化过程,大大提高了生产效率。同时,它还具有高效的湿气引发的二次固化机制,确保即使在阴影区域也能实现完全固化。这一特性对于BMS等复杂电子电路的保护至关重要。

为了将UVCL涂层推向市场,Electrolube公司的研发团队与客户紧密合作,克服了客户内部没有UV固化设施的难题。他们与信誉良好的供应商合作,提供了完整的解决方案,并成功为客户提供了原型样品单元进行现场测试。测试结果显示,UVCL涂层能够为电子电路提供最高水平的保护,且操作过程简单、应用速度快。

UVCL涂层的成功推出不仅提升了Electrolube公司在电子材料领域的地位,也为公司赢得了众多客户的信赖和好评。

Elpac公司的发展小趣事

在电子产品同质化日益严重的今天,Elpac公司始终坚持品质至上的原则。公司严格把控产品质量,从原材料采购到生产流程再到售后服务,每一个环节都力求做到最好。正是这种对品质的执着追求,让Elpac公司的产品在市场上脱颖而出。许多客户在体验过Elpac公司的产品后,都对其赞不绝口,成为了公司的忠实用户。

Echelon_Corporation公司的发展小趣事

作为一家技术驱动的公司,Echelon始终注重技术创新和产品研发的投入。公司拥有一支专业的研发团队,致力于开发更加先进、更加可靠的产品和技术。同时,Echelon还积极与全球范围内的科研机构、高校等合作,共同推动技术创新和产业升级。这些努力使得Echelon在电子行业始终保持领先地位。

Embedded Planet公司的发展小趣事

Embedded Planet公司深知人才是企业发展的核心驱动力。因此,公司一直致力于培养和吸引优秀人才,建立了一支高效、专业的团队。公司为员工提供丰富的培训和发展机会,鼓励员工不断学习和创新。同时,公司还注重团队建设和文化塑造,营造了一个积极向上、团结协作的工作氛围。这些努力使得Embedded Planet公司成为了一个充满活力和创造力的企业。

ABB Group公司的发展小趣事

作为一家负责任的企业,Embedded Planet公司一直将绿色环保理念融入产品设计和生产过程中。公司积极采用环保材料和技术,努力降低产品对环境的负面影响。同时,公司还倡导员工参与环保活动,共同为地球的可持续发展贡献力量。这些环保实践不仅提升了公司的社会形象,也为公司赢得了更多客户的信任和支持。

问答坊 | AI 解惑

[转贴]开关电源的分类及应用

1 引言   随着电力电子技术的告诉发展,电力电子设备与人们的工作、生活的关系日益密切,而电子设备都离不开可靠的电源,进入80年代计算机电源全面实现了开关电源化,率先完成计算机的电源换代,进入90年代开关电源相继进入各种电子、电器设备 ...…

查看全部问答>

论坛改版倒计时---欢迎大家的讨论!

号外号外,潜水的用户请快快浮出水面.eeworld论坛要改版啦!近期会新增加一个聚合页面.目前正在紧张内测中.先截个图给大家看看。新页面集中了大家可能会比较关注的发贴排行、本周热点、最新评论、会员空间等列表模块。大家有什么意见?请指正!不 ...…

查看全部问答>

嵌入式的迷茫阶段

各位好,我是计算机专业,想打算学习嵌入式的,但是我发现在嵌入式课程的学习中有很多芯片,很多的电路图,我以前学过接口,但是感觉现在的知识和以前学的有很大的差别,甚至是根本就没有听说过,现在学习起来感觉很迷茫,不知道嵌入式是否对于像我 ...…

查看全部问答>

散射 OR 辐射的概念,你弄懂了么?

之前也看到论坛里有就关于”二极管是有源无源的讨论”, 这里也抛个概念出来,希望大家可以说说。 辐射与散射到底有何区别?又有什么联系?…

查看全部问答>

wince平台中的SQLIT问题

我是一个嵌入式开发的新手,目前想用VS2005(C#)做一个SQLite应用程序,在WINCE平台上运行,是不是只下载一个 System.Data.Sqlite 安装之后,在C#里面添加引用就可以了?谁能给我说一下开发的详细的步骤啊?…

查看全部问答>

关于数字地与模拟地

我看别人设计的电路里面,数字地和模拟地之间用电感连接起来! 我想问问这个电感的大小是怎样选择的! 谢谢…

查看全部问答>

LM1117系列有没有能够提供负压的?

LM1117系列有没有能够提供负压的? 请教几个问题:1,1117系列是否属于LDO? 2,LM1117系列有没有能够提供负压的?对于LDO了解不多 3,对于LDO了解不多,是不是象有LM317和LM337那样的分类形式分别提供正负电压的?或是通用的?…

查看全部问答>

电源面试问题若干(来自我测试一下)

转自:http://forum.powersystems.eet-cn.com/BLOG_ARTICLE_6743.HTM?click_from=8800073982,9523571682,2011-03-04,PSCOL,FORUM_ALERT&click_from==etsd 1.一般情况下,同功率的开关电源与线性电源相比,_____。 A, 体积大,效率高   ...…

查看全部问答>

关于直流电压隔离采样

现在要对0-25V的直流电压进行隔离采样,精度要求1%,由于霍尔电压传感器的价格 较高,希望能换其他的隔离采样方式!   本来用线性光耦HCNR201大概能实现,但是这个光耦前后级各需一个运放,这样前后 运放就必须各自接不同的电源和地才行 ...…

查看全部问答>