ARM 的分散加载.docx
《ARM 的分散加载.docx》由会员分享,可在线阅读,更多相关《ARM 的分散加载.docx(9页珍藏版)》请在冰豆网上搜索。
ARM的分散加载
对于刚学习ARM的人来说,如果分析它的启动代码,往往不明白下面几个变量的含义:
|Image$$RO$$Limit|、|Image$$RW$$Base|、|Image$$ZI$$Base|。
首先申明我使用的调试软件为ADS1.2,当我们把程序编写好以后,就要进行编译和链接了,在ADS1.2中选择MAKE按钮,会出现一个ErrorsandWarnings的对话框,在该栏中显示编译和链接的结果,如果没有错误,在文件的最后应该能看到Imagecomponentsizes,后面紧跟的依次是Code,ROData,RWData,ZIData,Debug各个项目的字节数,最后会有他们的一个统计数据:
本文引用地址:
Code163632,ROData20939,RWData53,ZIData17028
TatalROsize(Code+ROData)184571(180.25kB)
TatalRWsize(RWData+ZIData)17081(16.68kB)
TatalROMsize(Code+ROData+RWData)184624(180.30kB)
后面的字节数是根据用户不同的程序而来的,下面就以上面的数据为例来介绍那几个变量的计算。
在ADS的DebugSettings中有一栏是Linker/ARMLinker,在output选项中有一个RObase选项,下面应该有一个地址,我这里是0x0c100000,后面的RWbase地址是0x0c200000,然后在Options选项中有Imageentrypoint,是一个初始程序的入口地址,我这里是0x0c100000。
有了上面这些信息我们就可以完全知道这几个变量是怎么来的了:
|Image$$RO$$Base|=Imageentrypoint=0x0c100000;表示程序代码存放的起始地址
|Image$$RO$$Limit|=程序代码起始地址+代码长度+1=0x0c100000+TatalROsize+1
=0x0c100000+184571+1=0x0c100000+0x2D0FB+1
=0x0c12d0fc
|Image$$RW$$Base|=0x0c200000;由RWbase地址指定
|Image$$RW$$Limit|=|Image$$RW$$Base|+RWData53=0x0c200000+0x37(4的倍数,0到55,共56个单元)
=0x0c200037
|Image$$ZI$$Base|=|Image$$RW$$Limit|+1=0x0c200038
|Image$$ZI$$Limit|=|Image$$ZI$$Base|+ZIData17028
=0x0c200038+0x4284
=0x0c2042bc
也可以由此计算:
|Image$$ZI$$Limit|=|Image$$RW$$Base|+TatalRWsize(RWData+ZIData)17081
=0x0c200000+0x42b9+3(要满足4的倍数)
=0x0c2042bc
原文地址
简单应用时可以不写.scf文件。
而在"Output"页中选择"Simple".然后填写"ROBase"和"RWBase"的起始地址。
在"LayOut"页中,填写Object/Symble:
Startup.o,Section:
Start.编写启动文件:
Startup.s.
在"Option"页里的"ImageEntryPoint"填入起始地址。
--------------------------------------------------------------------------------
Scatter-LoadDescriptionFile的结构:
".scf"文件中的"+RW"对应".s"源文件中的"READWRITE".
".scf"文件中的"+ZI"对应".s"源文件中的"NOINIT".
".scf"文件中的"+RO"对应".s"源文件中的"READONLY".
在".s"源文件中有:
AREAarea_nameCODE/DATA,READONLY/NOINIT/READWRITE
END
".scf"的例子
内容 注解
ROM_LOAD0x80000000
{ ;NameofLoadRegion,StartAddressforLoadRegionandMaximumsizeofLoadRegion(省略了)
ROM_EXEC0x800000000x20000
{;片外存储区,从0x80000000开始,最多0x20000字节。
Startup.o(Vector,+First);Startup模块的Vector段放在最前面。
注1
*(+RO);其他所有模块中的所有代码和只读的数据放在这里。
}
IRAM0x400000000x00004000
{;片内RAM区,从0x40000000开始,最多0x4000字节
Startup.o(MyStacks,+first);指定Startup.o中MyStacks放在最前面。
Startup.o(+RW,+ZI);Startup.o中的其他+RW/+ZI段。
注1
os_cpu_a.o(+RW,+ZI)
}
STACKS0x40004000UNINIT
{;片内16KRAM的顶端,存放不需要被"Clibrary"初始化的段。
Stack.o(+ZI)注2
}
ERAM0x80040000
{
*(+RW,+ZI)
}
HEAP+0UNINIT
{;"+0"表示接着上一段"ERAM"的结尾,继续安排存储区。
Heap.o(+ZI)注3
}
}
下面是在scf文件中引用过的源文件示意:
"Startup.s"
code32
areaVectors,CODE,READONLY
entry
...
end注1:
在"Startup.o"里面会生成名为"Vectors"的段,段的属性为"READONLY"
"Stack.s"
areaStacks,DATA,NOINIT
exportStackUsr
StackUsrSPACE1
end注2:
在"Stack.o"里面会生成名为"Stacks"的段,段的属性为"NOINIT",该属性对应scf文件中的"+ZI".该段不需要初始化或者可以被初始化为"0".
"Heap.s"
areaHeap,DATA,NOINIT
exportbottom_of_heap
bottom_of_heapSPACE1
end注3:
"Heap.o"里面名为"Heap"的段。
在Scatter文件中最好每一个Region都加一个Maximum参数,这样当编译时如果实际使用的空间大于MaximumSize,会有Error:
16220E:
Excutionregionxxxsize(xxxbytes)exceedslimit(xxbytes)。
如果地址有重复,会有Error:
16221E:
Excutionregionxxxoverlapswithexcutionregionxxx。
前一个Region的首地址+Maximum>后一个Region的首地址时不一定有Error。
只有当一分配的内存出现覆盖时才会有Error。
Region的"UNINIT"之类的参数要放在"Maximumsize"参数之前。
在一个Region中,RAM的分配不是按照罗列的顺序来的。
要想让汇编中使用的变量有固定的位置,可以把所有汇编文件产生的".o"放在同一个Region中。
如:
IRAM10x40000000
{
startup.o(+RW,+ZI)
ASMSourceCode1.o(+RW,+ZI)
ASMSourceCode2.o(+RW,+ZI)
}
IRAM2+0
{
CSourceCode1.o(+RW,+ZI)
CSourceCode2.o(+RW,+ZI)
}
这样,所有汇编中定义的变量地址就相对集中了。
如果只有一个汇编文件如startup.s,也可以这样:
IRAM0x400020000x1000
{
startup.o(Mystack,+first)
*(+RW,+ZI)
}
用一个"+first"强行将startup.s中的Mystack放在0x40002000位置。
在"Edit->DebugRelSettings...->ARMLinker"中选中"Imagemap"。
编译后在Error&Warnings窗口会显示出详细的内存分配情况。
如果在"Listfilename"中指定一个输出文件名,该祥单会直接存在制定文件中以供多次研究。
--------------------------------------------------------------------------------
关于JTAG接口:
P1.20/TRACESYNC应该加上拉电阻以禁止TRACE功能。
PINSEL2一定要在程序开始时初始化一下。
LPC2210
JTAG
注
1,2/VDD3.3V
P1.31/nTRST,input3/nTRST,outputEasyJTAG中有上拉电阻。
P1.28/TDI,input5/TDI,outputEasyJTAG中有上拉电阻。
P1.30/TMS,input7/TMS,outputEasyJTAG中有上拉电阻。
P1.29/TCK,input/output9/TCK,input/outputEasyJTAG中有上拉电阻。
P1.26/RTCK,input11/RTCK,outputP1.26外接下拉电阻。
P1.26有内部上拉电阻,故测量时该引脚会呈现高电平。
但是在复位时,它的上拉电阻不起作用,只有外部的下拉电阻起作用,P1.26=0V,所以上电后PINSEL2的D3~D0会是0x04(B0100),JTAG有效。
若将P1.26接到3.3V再复位,此时PINSEL2的D3~D0将会是0x00,JTAG无效。
P1.27/TDO,output13/TDO,inputEasyJTAG中有上拉电阻。
nRESET,input15/nRST,outputEasyJTAG中有上拉电阻。
4,6,8,10,12,14,16,18,20/GND
17,19/NC
G18控制板采用LPC2114,每次运行Axd都不会正确调入程序。
原因如下:
有一次是因为已经有一个Axd在运行了,打开第二个Axd,当然不会正确调入程序。
还有一次是重新编译了一下,就好了。
以上两次都不奇怪,奇怪的是下面几次:
在"ConfigTarget->Config->EasyJTagSetup"随便点两下"HaltMode"中的选项,然后一路点击"OK",会出现"ReloadthelastImage?
",点击"Yes"。
有时会有正确的程序被调入,但有时候不成功。
要检验是不是已经成功