Cortex-M3的低层编程

上传人:ll****x 文档编号:243017235 上传时间:2024-09-13 格式:PPT 页数:22 大小:222KB
返回 下载 相关 举报
Cortex-M3的低层编程_第1页
第1页 / 共22页
Cortex-M3的低层编程_第2页
第2页 / 共22页
Cortex-M3的低层编程_第3页
第3页 / 共22页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,*,Cortex-M3的低层编程,􀁺 概览,􀁺 汇编与 C 的接口,􀁺 典型的开发流程,􀁺 第一步工作,􀁺 与外界互动,􀁺 使用数据存储器,􀁺 使用互斥访问实现互斥锁操作,􀁺 使用位带实现互斥锁操作,􀁺 使用位段提取与查表跳转,1,概览,在CM3 上编程,既可以使用C 也可以使用汇编。可能还有其它语言的编译器,但是大多数人还是会在C 与汇编的世界里游弋。C 与汇编都有尺短寸长,不能互相取代。使用C 能开发大型程序,而汇编则用于执行特种任务。,2,在使用不同的工具链和芯片时,有大量的用法和用量都随之不同。因此,本书不会深入讲解怎样精通一个具体的工具链,也不会大谈如何把程序烧到板子上。在第19 章和第20章会提到一些入门知识,具体内容还需查阅相关的文献和在线帮助文档。,3,使用汇编,如果工程比较小,使用纯汇编常常是可行的,而且你能随心欲地优化和控制程序。不过,你的开发周期会变长。尤其是当工程变大,需要处理比较复杂的数据结构,以及要管理函数库时,你将发现汇编会使工作量激增。各种地址和间接引用千头万绪;bug 劈头盖脸;甚至好几天都改不完,简直就是自虐。当然,如果你想成为系统开发的大虾,就必须以“我不下地狱谁下地狱”的决心,去勇敢面对,后天下乐而乐。,4,不论如何,时间宝贵。我们应该以C 来实现程序的大框架,而本着好钢用在刀刃上的原则来使用汇编,因为只有在不多的特殊场合是非使用汇编语言不可的,它们是:,􀁺 无法用,C,写成的函数,如操作特殊功能寄存器,以及实施互斥访问。,􀁺 在危急关头执行处理的子程(如,,NMI,服务例程)。,􀁺 存储器极度受限,只有使用汇编才可能把程序或数据挤进去。,􀁺 执行频率非常高的子程,如操作系统的调度程序。,􀁺 与处理器体系结构相关的子程,如上下文切换。,􀁺 对性能要求极高的应用,如防空炮的火控系统。,5,使用C,用C写的程序可以移植,并且操作复杂数据结构时远远比汇编方便。但因为C是一种通用语言至少是低等高级语言,它并不指定如何初始化具体的处理器(用于在main执行前准备好执行环境)。在解决这个问题时,不同的工具链都有自己的一套,因此最聪明的办法就是看一看工具链附带的示例程序。如果使用RealView开发套件(RVDS)或者KEIL 的RealView微控制器开发套件(RVMDK),则编译器和汇编器是ARM提供的,而且它们中都附带了很多示例。如果使用了GNU的工具链,则第19章以CodeSourcery GNU工具链为例,给出一个简单的示例(其它示例可以网上找)。,6,尽管在使用了C后,大大加速了开发,但是底层的系统控制往往还需要汇编代码。很多编译器都允许你直接在C代码中插汇编,称为“内联汇编”;另外还允许你写独立的汇编模块,与编译后的C模块一起连接。以往,使用内联汇编的作法比较多,但是在ARM编译器中,不支持对Thumb2指令的内联汇编。取而代之的,是从RealView C编译器的3.0版开始,新增了所谓“嵌入式汇编”的功能,它支持Thumb2指令。它让你可以在C程序中插入使用汇编语言编写的函数,,7,例如:,_asm,void SetFaultMask(unsigned int new_value),/在这里使用汇编代码实现本函数,MSR FAULTMASK, new_value / 把new_value写入FAULTMASK中,BX LR / 返回主程序(不可省略),RealView C 编译器对嵌入式汇编的详细论述,在RVCT 3.0 Compiler and Library Guide(Ref6)中给出。,8,在CM3 中,嵌入式汇编还是比较需要的,因为常常会有访问特殊功能寄存器的时候。比如,在设置堆栈时,就要使用MRS/MSR 指令。对于其它不能由编译器产生的指令,比如WFI/WFE、互斥访问、存储器隔离等指令,也必须用汇编显式给出。,9,在以前的ARM 处理器中,因为支持ARM/Thumb 双重状态,往往需要所谓的“interworking”,且不同的源文件可能需要编译成不同状态下的代码。在CM3 中不再有此需求,因为只使用了Thumb 状态,从而工程管理清爽多了。,10,当使用C 开发程序时,推荐你开启CM3 的双字对齐管理机制(在NVIC 配置与控制寄存器中,把STKALIGN 置位),代码形如:,#define NVIC_CCR (volatile unsigned long *)(0xE000ED14),*NVIC_CCR *NVIC_CCR | 0x200; /设置STKALIGN位,这是用于确保系统能严格遵守AAPCS 过程调用标准,个中细节请参阅第12 章。,11,汇编与C 的接口,在很多情况下,都需要让C 程序模块与汇编程序模块互相交互,它们包括:,在,C,代码中使用了嵌入式汇编(或者是在,GNU,工具下,使用了内联汇编),C,程序呼叫了汇编程序,这些汇编程序是在独立的汇编源文件中实现的,汇编程序调用了,C,程序,在这些情况下,必须知晓参数是如何传递的,以及值是如何返回的,才能在主调函数与子程序之间协同工作。这些交互的机制在,ARM,中有明确的规定,由文档,ARM Architecture Procedure Call,Standard(AAPCS, Ref5),给出。,12,不过,在大多数场合下的情况都比较简单:当主调函数需要传递参数(实参)时,它们使用R0R3。其中R0传递第一个,R1传递第2个在返回时,把返回值写到R0中。在子程序中,可以随心所欲地使用R0R3,以及R12(回顾第9章,想想为什么会PUSH它们)。但若使用R4R11,则必须在使用之前先PUSH它们,使用后POP回来。,13,可见,汇编程序使用R0R3, R12时会很舒服。但是如果换个立场汇编要呼叫C函数,则考虑问题的方式就有所不同:必须意识到子程序可以随心所欲地改写R0R3, R12,却决不会改变R4R11。因此,如果在调用后还需要使用R0R3,R12,则在调用之前,必须先PUSH,从C函数返回后再POP它们,对R4R11则不用操心。在本章的示例程序中,绝大多数只是调用汇编子程序,它们只影响少量寄存器,或者会在返回前恢复寄存器的内容,所以往往没有严格遵守AAPCS。这主要是为了突出其它重点,简化程序,请读者不要钻牛角尖。,14,典型的开发流程,在开发基于CM3的应用程序时,常常有多种源程序和库,有些是自己写的,有些是别人已经写好的(尤其是底层的软件)。上述这些开发工具,在代码生成的流程都差不离。对于最基本的应用,也至少需要C编译器,连接器以及二进制文件处理工具。如果使用的是ARM的工具,如RVDS或RealView 编译器工具(RVCT),则它们的流程如图10.1所示。其中的“分散加载脚本”是可选的,但是当存储器映射变得比较复杂时,则需要它。,15,图10.1 使用ARM工具链时的典型开发流程,在上述基本工具之外,RVDS还提供了大量的其它实用程序,比如一个集成开发环境(IDE)以及调试器。欲知详情,可登录ARM网站(),16,第一步工作,本章为提供了若干汇编写的例子,在实际应用中,这些程序都会用C写。但是以汇编的方式呈现,有助于让读者更深更好地理解CM3的工作内幕,以便在以后用C开发时心里更有底。这里给的程序都用ARM的汇编器(armasm)来汇编,其它工具可能对语法格式有些不同的要求。而且实际上,开发工具几乎都会把启动工作为你做好,让你根本不用去想还有启动代码的事(不过,这也妨碍了我们学习得更深入)。,17,下面,就隆重请出本书第一个完整的示例程序(请参考向量表来阅读),STACK_TOP EQU 0x20002000 ; SP初始值,常数,AREA |Header Code|, CODE,DCD STACK_TOP ; 栈顶(MSP的),DCD Start ; 复位向量,ENTRY ; 指示程序从这里开始执行,Start ; 主程序开始,; 初始化寄存器,MOV r0, #10; 加载循环变量的初值,MOV r1, #0 ; 初始化运算结果的值,; 计算 10+9+8+.+1,loop,ADD r1, r0 ; R1 += R0,SUBS r0, #1 ; R0自减,并且根据结果更新标志(有”S”后缀),BNE loop ; if (R0!=0) goto loop;,; 现在,运算结果在R1中,deadloop,B deadloop ; 工作完成后,进入无穷循环,END ; 标记文件结束,18,这个例子非常简单,它只初始化了SP以及PC,以及初始化了需要使用的寄存器,然后就执行连加循环中。,使用ARM工具来汇编该程序,命令为:,$ armasm -cpu cortex-m3 -o test1.o test1.s,命令行中的“o”指示后面的是输出文件名也就是test1.o,它也就是目标文件。,19,接下来,我们就要使用连接器,连接各目标文件(本例中只有一个)并创建出一个可执行的映像(ELF),命令为:,$ armlink -rw_base 0x20000000 -ro_base 0x0 -map -o test1.elf test1.o,这里,“ro_base 0x0”的意思是说,把只读区(也就是程序ROM)的起始地址设为0;而“rw_base 0x20000000”则指定读写区(数据存储器)从0x20000000开始(在本例中,我们没有定义任何RAM数据)。“map”选项则要求连接器给出存储器分配映射表,通过它,可以查看编译后的映像中内存的布局。,20,最后,我们要生成二进制烧写文件,命令行为:,$ fromelf -bin -output test1.bin test1.elf,如果想要看看生成的映像是否确实是我们想要的,还可以像这样对它做反汇编:,$ fromelf -c -output test1.list test1.elf,(其实基本上很少会做上步译者注),如果一切都好,就可以把ELF映像或者二进制代码烧写到器件中了,也可使用模拟器来测试。,21,与外界互动,22,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!