ARM嵌入式软件开发课件_第1页
ARM嵌入式软件开发课件_第2页
ARM嵌入式软件开发课件_第3页
ARM嵌入式软件开发课件_第4页
ARM嵌入式软件开发课件_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

嵌入式软件开发嵌入式开发过程“PC软件”独立的嵌入式应用当程序员开始开发一个基于ARM应用的时候,你可以使用ARM的ADS编写类似于“HELLOWORLD”的程序,使用ARMulator或者在评估板上来调试,但当你把他移植到独立的嵌入式应用设备中时,下面这些问题就成为我们首要考虑的:

硬件环境中所使用的C库函数

目标板上的存储器资源

应用程序的初始化议程PC软件的构造

定制标准C库函数到目标板定制IMAGE的存储器映射到目标板

复位和初始化

深层次的存储器器映象考虑

编译和调试IMAGEADS默认的存储器映射在默认的情况下,我们链接、定位、运行在0x8000heap被直接放置在数据区的上面堆栈的基地址是通过调试环境从C库函数的StartupCode里读取出来的。ARMulator=>fromconfigurationfile(peripherals.ami)default=0x08000000Multi-ICE=>fromdebuggerinternalvariable$top_of_memorydefault=0x80000RORWZI0x8000链接时确定由调试环境提供Heap(malloc,alloc)StackCLibraryUserCode应用程序启动__maincopycodeanddatazerouninitializeddata__rt_entrysetupapplicationstackandheapinitializelibraryfunctionscalltop-levelconstructors(C++)Exitfromapplicationmain()causesthelinkertopullinlibraryinitializationcode程序入口点Agenda 一个PC软件的构造

定制标准C库函数到目标板定制IMAGE的存储器映射到目标板

复位和初始化

深层次的存储器器映象考虑

编译和调试IMAGE重定向C库函数(2)要重定向C库函数,简单的办法是使用你自己的可执行的semihostingSWIs来代替原来的C库函数,从而来满足你的系统要求

比如说,theprintf()系列函数(sprintf()除外)都会调用fputc().在默认情况下fputc()的执行使用了semihostingSWI.用下面的语句来代替:

externvoidsendchar(char*ch);

intfputc(intch,FILE*f)

{/*e.g.writeacharactertoanLCD*/

chartempch=ch;

sendchar(&tempch);

returnch;

}

可查看在ADSEmbeddedexample目录下的retarget.c,可看到更多的重定向例子

你可以确定有不在连接时使用semihostingSWI的吗?…...消除C库函数中的semihosting为了确保在连接时没有函数使用了semihostingSWIs,你可以在程序中加入下面的句子:#pragmaimport(__use_no_semihosting_swi)

如果在程序中仍然使用了semihosting,编译时将会报错:Error:Symbol__semihosting_swi_guardmultiplydefined修改:

如果使用(check-verboselinkeroutputforoccurrencesofIuse_semihosting_swi),那么连接器将会把那些使用了smeihosting的程序列出来,

然后:提供你自己可运行的功能函数。在ADS1.2编译器和库函数手册,表4-2给出了所有使用了semihosting的C库函数。注意:连接器在用户自己的应用代码中不会出现任何有关semihostingSWI使用的报告。Agenda

一个PC软件的构造

定制标准C库函数到目标板

定制IMAGE的存储器映射到目标板

复位和初始化

深层次的存储器器映象考虑

编译和调试IMAGEExecuteViewRAM0x100000x180000x40000x0000ROMRO分散加载

(简单例子)只读代码和数据保存在ROM中C库函数初始化代码(在__main)将:从ROM拷贝RW数据到RAM在RAM中的ZI数据初始化RAM0x100000x180000x40000x0000ROMLoadViewRORWFillwithzerosZICopyRWExecuteViewRAM0x100000x180000x40000x0000ROMROLOAD_ROM0x00000x4000{}RAM0x100000x180000x40000x0000ROMLoadViewRORWScatter描述文件通配符(*)语法允许简单的对CODE和DATA进行分组EXEC_ROM0x00000x4000{*(+RO)}RAM0x100000x8000{*(+RW,+ZI)}RWZIRORWZIROCODERO-DATARO-CODEAB链接器放置规则在每个可执行区,链接器通过一些基本的规则来放置CODE和DATA基本的排序方法是通过属性来安排的:RO领先于RW,RW领先于ZI有相同的属性时,CODE在DATA之前放置。更多的排序方法决定于:输入的组名按字母排序,

在ARMLINK命令行中指定的顺序。eg:armlink…

AsectionAfromsectionAfromROOT区

LOAD_ROM0x00000x4000;startaddressandlength

{ EXEC_ROM0x00000x4000;root(load=execaddress){

__main.o(+RO);copyingcode*(Region$$Table);RO/RWaddressestocopy*(ZISection$$Table);ZIaddressestozero }

RAM0x100000x8000

{

*(+RO);AllotherROareas *(+RW,+ZI);programvariables

}

}Mustbeinarootregionoutsiderootregion一个root区是一个可执行区,它的加载地址等于执行地址。Root区要点一个root区是一个可执行区,它的加载地址等于执行地址.每个scatter描述文件必须最少包含一个root区,并且最少要包含下列内容:__main.o–含有拷贝code/data的代码Region$$Table和ZISection$$Table–含有将要拷贝的code/data的地址,他是由链接器产生的,不是一个对象文件。(所以*必须用)

Error:L6202E:SectionRegion$$Tablecannotbeassignedtoanon-rootregion. Error:L6202E:SectionZISection$$Tablecannotbeassignedtoanon-rootregion.注意:如果

*(+RO)被定位在root区,在此之前的将被自动放置Main应用程序的入口点必须放在root区。 Error:L6203E:Entrypoint(0x08000000)lieswithinnon-rootregionEXE_FLASH.Run-time存储器管理SemihostingSupportANSICStack&HeapSetupStack&HeapSetupANSICCLibraryUserCodeDebugAgentTargetHardwareRetarget如何设置stack和heap来满足我们的目标存储器?我们已经通过执行__user_initial_stackheap()把C标准库的运行存储器模式修改到目标平台上。Run-time存储器模式你必须决定在放置stack和heap时所使用的区域是单一的区(one-regionmodel)或是不同的两个区(two-regionmodel)HeapStackStackOneregionmodelTworegionmodelHBSBSBHBHL单一存储器模式是默认方式为了实现多区域模式,你可以使用use_two_region_memory在所有的模式下,软件堆栈检查要许可。编译开关是:-apcs/swst指定堆栈限制(为two-region模式)heapischeckedagainststackpointerHeapheapischeckedagainstheaplimit(SL)__user_initial_stackheap()可以用C或汇编来写,他要返回:Heap基地址在R0,STACK的基地址在R1.Heap的限制地址在R2,STACK的限制地址在R3

EXPORT__user_initial_stackheap__user_initial_stackheap LDRr0,=0x80000;HB LDRr1,=0x88000;SB ;r2notused(HL) ;r3notused(SL) MOVpc,lrHeapStackHeap的限制地址在单一模式是不被使用的。Stack的限制地址只在软件堆栈检查许可的情况下才有效。HB=0x80000SB=0x88000警告!当使用分散加载时你必须执行__user_initial_stackheap()在C库初始化代码内的__user_initial_stackheap()的默认执行是在映像文件的RW/ZI数据段后放置HEAP。使用Image$$RW$$Base/Image$$ZI$$Base

连接符号这些符号对scatterloading是无效的。在ADS1.1和早期版本的软件中:符号被设置为0X0,heap被定位在这!Heap的并发使用,无论是直接(e.g.withmalloc())或间接(byuseofargc/argv)的都可能破坏向量表或其他代码,典型的结果是不可预知的程序在运行时出错了。在ADS1.2:符号没有定义,应用程序不会联接:

Error:L6218E:UndefinedsymbolImage$$ZI$$Limit(referredfromsys_stackheap.o).TheVectorTable

AREAVectors,CODE,READONLY IMPORTReset_Handler

;importotherexceptionhandlers ;…ENTRY B Reset_Handler

B Undefined_Handler

B SWI_Handler

B Prefetch_Handler

B Data_Handler

NOP ;Reservedvector

B IRQ_Handler

;FIQ_Handlerwillfollowdirectly END在使用scatterloading+FIRST时直接定位在0X0(或0xFFFF0000)ENTRY

直接告诉链接器这是一个入口点,防止某些段被删除中断向量表初始化步骤CLibraryUserCode__maincopycodeanddatazerouninitializeddata__rt_entryinitializelibraryfunctionscalltop-levelconstructors(C++)Exitfromapplicationmain()tellslinkertolinkinlibraryinitializationcodeImageEntryPoint__user_initial_stackheap()setupstack&heapresethandlerinitializestackpointersconfigureMMU/MPUsetupcache/enableTCM$Sub$$main()enablecaches&interrupts初始化栈的指针;---Amountofmemory(inbytes)allocatedforstacksLen_FIQ_StackEQU256Len_IRQ_StackEQU256…Offset_FIQ_StackEQU0Offset_IRQ_StackEQUOffset_FIQ_Stack+Len_FIQ_Stack…Reset_HandlerLDRr0,stack_base;locatedbyscatterfile;EntereachmodeinturnandsetupthestackpointerMSRCPSR_c,#Mode_FIQ:OR:I_Bit:OR:F_Bit;NointerruptsSUBsp,r0,#Offset_FIQ_StackMSRCPSR_c,#Mode_IRQ:OR:I_Bit:OR:F_Bit;NointerruptsSUBsp,r0,#Offset_IRQ_Stack

…;SystemmodestackissetuplastMSRCPSR_c,#Mode_SYS:OR:I_Bit:OR:F_Bit;NointerruptsSUBsp,r0,#Offset_SYS_Stack;SetupstacklimitifneededLDRr10,stack_limit;locatedbyscatterfile

局部存储器设置run-time的存储器必须在C库初始化前定义如果你使用的ARM7芯片还有MMU/MPU,它必须设置;ROM/RAM的重新映射必须完成。TCM’s(Tightlycoupledmemory)如果有TCM,典型的必须使能它。请注意:在TCM使能之前,要屏蔽ROM在Cache打开之前要返回。在c库初始化代码运行之后,如果cache被使能,可以避免与cache相关的问题;扩展功能系统初始化代码通常在进入主应用之前运行当然,resethandler不是一个适合使能中断和使能caches地方。在resethandler最后应该放一个C运行库初始化代码EG。IMPORT__main B__main我们可使用$Sub和$Super功能来包装符号externvoid$Super$$main(void);void$Sub$$main(void){cache_enable(); //enablescachesint_enable(); //enablesinterruptssys_to_usr_mode(); //changemode-seenextslide$Super$$main(); //callsoriginalmain()}相关描述可在ADS1.2LinkerandUtilitiesGuide-4.4章查阅到。运行模式考虑主应用程序运行在何种模式是要考虑的重要问题。用户模式(Usermode)是非特权模式(unprivilegedmode)-保护你的系统系统初始化代码只能运行在特权模式(privilegedmode)。需要执行特权操作比如:使能中断。如果你的应用要运行在管理模式,简单的在管理模式下退出你的resethandler就可。如果你想在用户模式下运行你的应用,你需在$Sub$$main()改变为用户模式当然,__user_initial_stackheap()必须有权使用你的应用模式寄存器。解决办法是在系统模式里退出resethandler所有C库初始化代码有权使用用户寄存器,但是仍然可以执行特权操作。Agenda 一个PC软件的构造

裁减标准C库函数到目标板定制IMAGE的存储器映射到目标板

复位和初始化

深层次的存储器器映象考虑

编译和调试IMAGE长跳转VeneersROM_LOAD0x0000{ROM_EXEC0x0000{*(+RO) }RAM0x80000000{farfunc.o(+RO)*(+RW,+ZI)}}/*main.c*/

intmain(void)

{

farfunc();

}/*farfunc.c*/

voidfarfunc(void);

{

:

}代码段可被远距离分开放置(比BL的跳转范围还远)链接器可自动增加长跳转Veneers,远距离的函数可被成功调用。0x00000000

blVen$AA$L$$farfunc : :Ven$AA$L$$farfunc

ldrpc,[pc,#-4]

dcd0x80000000 : :0x80000000

: movpc,lr存储器映射寄存器你可以使用scatterloading来放置外设寄存器的存储器映射在文件中定义它e.g.timer_reg.c struct{ volatileunsignedreg1;/*timercontrol*/ volatileunsignedreg2;/*timervalue*/ }timer_reg;

在存储器映射的请求地址上增加另外的可执行区来放置他们:

LOAD_FLASH0x240000000x04000000 { : TIMER0x40000000UNINIT { timer_reg.o(+ZI) } : }

UNINIT

显示在ZI段没有被初始化为0。Stack和Heap区(1)你也可以在SCATTER文件中放置stack和heap在汇编原文件里定义stack和heap区

比如.stackheap.s这个空间直接保留一个为0的存储器块 AREAstack,DATA,NOINIT SPACE0x3000;Reservestackspace

AREAheap,DATA,NOINIT SPACE0x3000;Reserveheapspace ENDStack和Heap区(2)增加一个可执行区来定位这个区域LOAD_FLASH0X240000000x04000000{ : STACK0x1000UNINIT;length=0x3000 {stackheap.o(stack);stack=0x4000to0x1000 } HEAP0x15000UNINIT;length=0x3000 {stackheap.o(heap);heap=0x15000to0x18000 } }Heap的基地址起始为0x15000.Stack的最大地址为0x4000.Stack和Heap区(3)链接器将产生一个为每个可执行区的基地址和限制地址的符号指针在你的代码中引入这些符号 IMPORT ||Image$$STACK$$ZI$$Base|| IMPORT||Image$$STACK$$ZI$$Limit|| IMPORT||Image$$HEAP$$ZI$$Base|| IMPORT||Image$$HEAP$$ZI$$Limit|| stack_base DCD||Image$$STACK$$ZI$$Limit|| stack_limit DCD||Image$$STACK$$ZI$$Base|| heap_base DCD||Image$$HEAP$$ZI$$Base|| heap_limit DCD||Image$$HEAP$$ZI$$Limit||使用DCD指令为这些段命名__user_initial_stackheap()在resethandler,这个stack指针(r13)和stack限制值(r10)通常设置了,他们分别通过R1和R3作为参数传递给__user_initial_stackheap

IMPORT__use_two_region_memory EXPORT__user_initial_stackheap__user_initial_stackheap LDRr0,heap_base ;SBvaluesetupinresethandler LDRr2,heap_limit ;SLvaluesetupinresethandler MOVpc,lrStackHeap这个__user_initial_stackheap()例子实现了两个存储器区域模式。

必须引用

__use_two_region_memory,在这HEAP被检查,它是HEAP的限制值,而不是STACK指针存储器映射例子16bitRAM0x100000x180000x40000x0000Fast32bitRAMVectorTableStackExceptionHandlersRW&ZIHeapFlash0x240000000x28000000ResetHandlerROPeripherals0x40000000外设控制寄存器的地址映射直接在FLASH运行的代码大小16位RAM被用来保存数据和HEAP区一些紧急的代码和数据可放在快速的RAM区SCATTER文件例子::16bitRAM0x10000{*(+RW,+ZI)}HEAP0x15000UNINIT{stackheap.o(heap)}

TIMER0x40000000UNINIT{timer_reg.o(+ZI)}}FLASH0x240000000x04000000{FLASH0x240000000x04000000{init.o(Init,+First)*(+RO)}32bitRAM0x0000{vectors.o(Vect,+First)handlers.o(+RO)}STACK0x1000UNINIT{stackheap.o(stack)} :这个scatter文件执行上页所显示的存储器映射。Agenda 一个PC软件的构造

裁减标准C库函数到目标板定制IMAGE的存储器映射到目标板

复位和初始化

深层次的存储器器映象考虑

编译和调试IMAGE不使用段的消除和程序的入口点在默认的情况下,链接器将从最终的image文件中删除一些从不使用的代码段,或从未使用的数据段。要查看哪些段被删除了,在链接时用:

‘-infounused’.为了确保不删除重要的段(比如:中断向量表):使用汇编指令entry标示所有的入口点(c库有一个入口点:__main()),使用‘-entry’选择其中一个入口点作为image的入口,否则,链接器将给警告:

Imagedoesnothaveanentrypoint.(Notspecifiedor

notsetduetomultiplechoices)在生成ROMmableimage使推荐使用下面的链接命令:

armlinkobj1.oobj2.o-scatterscatter.scf

-infounused-entry0x0-oprog.axf

输出选项链接器产生ELF/DWARF2格式的映像文件,选择适当的调试器下载调试为把elf映像文件转为‘ROMmable’格式使用

fromelf,例如.:

fromelfimage.axf-bin-o

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论