您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > Cortex-M3汇编实践
CORTEX-M3汇编语言实践编程基于STM32F103系列MCU2015-1-9三两二锅头duck8815@126.comCortex-M3汇编语言实践编程-1-写在前面:接触Cortex-M3已经有一段时间了,大大小小也做了几个项目,可以说对这个系列的片子有了一定的了解。相对于8位单片机来说CM3给我的感觉实在是强了太多,其中比较明显的感觉是存储上的扩充,这让我在编程的时候不必为了节省几十个字节的内存而大费周章。还记得当初用ATmega16写一个项目的时候,申请了一个比较大的缓冲区之后要好多个模块共用,搞得程序结构非常乱而且还容易出错,当然这还只是一个小惊喜。更大的优势在于CM3先进高效的中断机制以及它丰富的外围接口和强大的片内功能,这些让我在开发的过程中深切的体会到CM3相对于8位单片机的优越性。而相对于高端的ARM芯片(ARM7、ARM9等)来讲CM3又以它精巧灵活的特性让我深深的喜欢上了这个系列的芯片,尤其是新的指令集给人感觉耳目一新,让原来繁杂的芯片初始化工作最终浓缩到数十行汇编代码中,CM3以它的精简和易用再一次吸引了我。经过一段时间的学习和使用,个人觉得如果想把一款芯片用的得心应手一些必要的理论知识还是值得花时间去学习和研究的,所以在工作之余就有了这个文档。本文主要从汇编语言的角度去阐述和学习Cortex-M3的体系结构以及基本工作原理,实现对一些片内功能的配置与应用同时还包括一些简单的外设应用。本文重点不在于深究汇编指令码,而是通过使用汇编语言让读者从计算机的角度出发去思考问题,了解计算机的工作原理和步骤,所以汇编指令码的细节内容在这里则不会深入讨论。声明:本文内容完全属于个人学习总结以及个人的理解和看法,在学习过程中借鉴过很多资料包括来源于网络的资料,如果文中内容让您感觉不适请联系作者删除。由于作者水平有限文中难免出现错误,如遇到错误烦请您不吝指正,并欢迎您与作者进行交流沟通duck8815@126.com。作者默认您对CM3有一定的了解,并且具备基于CM3芯片的C语言开发经验。文中使用的芯片是STM32F103ZE,软件开发环境用的是***(因为涉及到版权问题本来考虑在Linux平台下进行编写代码但是考虑到大家可能很少有人用Linux开发程序,所以选了和大家一样的开发环境)。下面作者将从一个空的汇编工程展开本文。Cortex-M3汇编语言实践编程-2-1第一个汇编工程我们创建工程的时候IDE会提示我们是否导入启动文件,而这个启动文件就是用汇编语言编写的,在这里简单说一下汇编工程的创建步骤:新建一个工程创建工程的步骤和平时创建工程一样,之余工作目录之类的东西相信各位自己也都有自己的习惯这里就不再赘述。Figure1-1新建工程工程名字自己随便写一个就行Figure1-2工程名字选择对应芯片,在出现是否创建启动文件时选择不创建。Figure1-3Cortex-M3汇编语言实践编程-3-配置工程修改工程目录以及配置目标文件输出位置,保证工程目录文件便于管理。Figure1-4创建工程目录单击途中1号位置单击2号位选择obj目录4好位置选中创建HEX文件Figure1-5配置目标文件输出位置Cortex-M3汇编语言实践编程-4-按照图中序号顺序完成后续配置修改部分工程信息,1、2两处改成自己对应的工程名与组名Figure1-6修改工程信息Cortex-M3汇编语言实践编程-5-新建一个文本文件,并保存为汇编源程序文件Figure1-7新建文件Figure1-8保存文件将保存好的文件添加到工程,添加完毕效果如下:Figure1-9添加到工程Cortex-M3汇编语言实践编程-6-编写程序Figure1-10第一段汇编程序对于上面的这段程序需要详细的解释一下:1.正文第1行以分号(;)开始,在ARM汇编里表示单行注释,ARM汇编不支持多行注释。2.第三行代码的内容在ARM汇编中被称之为伪代码,这行代码的意思是定义一个段[section],段是汇编语言组织代码的基本单位,功能与C语言中的函数类似,代码写在段的外面也允许,但是会出一些问题。这一行代码中AREA伪指令表示声明一个段,RESET是段的名字,在当前平台上RESET段也是系统默认的入口,所以在代码中有且只有一个RESET段。CODE表示短的属性,代表当前段为代码段,和CODE功能类似的还有DATA、STACK、HEAP等分别表示数据段、栈和堆。READONLY是当前段的访问属性表示只读,还有READWRITE表示可读可写。3.第4行代码只有一个单词ENTRY,表示程序入口,即CPU会从ENTRY标记的这一行代码处开始执行程序,类似与C语言中的main函数,但是与C语言不同的事ARM汇编允许一个程序有多个入口,但是用户需要指定一个入口作为主Cortex-M3汇编语言实践编程-7-入口。关于入口的定义你还可以在MDK参考手册上找到如下解释:Figure1-11ENTRY官方解释4.第6行代码“STARTPROC”与第12行代码“ENDP”通常成对出现,表示定义一个子程序,其中START是子程序名或者叫做标号,在ARM汇编当中代表当前子程序的入口地址,相当于C语言中的函数名的作用。同时大家应该注意到这个START的位置是顶格写的,这是因为在ARM汇编中规定:标号必须要顶格写,而指令、伪指令、伪操作等指令码(或者称为关键字例如MOV、ADD等属于指令、LDR、ADR等属于伪指令、DCD、IF/ENDIF等属于伪操作)在书写的时候需要有前导空格,一般我们用一个或者多个TAB代替。例如我们把第8行内容变成如下形式:Cortex-M3汇编语言实践编程-8-编译程序我们会发现如下错误:事实上编译器是把第8行指令的MOV当成标号来处理,而把R0当成的指令操作码,因为无论是指令、伪指令、还是伪操作中都不包含R0这条指令码,所以编译器会报出上述错误。同理如果把第6行的START加上前导空格也会报出类似的错误,在这里就不重复展示了。5.第7行EXPORTSTART是一条链接属性声明语句,表示START这个子程序(确切的说是这个标号或叫标识符)在其他汇编语言文件中也可以被调用,但是如果其他文件中想调用START还需要将这个标号进行导入,导入的方法是”IMPORTSTART“,EXPORT与IMPORT是一对操作符,用EXPORT声明的标号只有通过IMPORT导入以后才能正常使用。6.最后14行END表示当前汇编语言源文件的结束,ARM汇编编译器在编译期对预处理过的汇编语言源文件进行逐行扫描,当遇到END关键字的时候表示当前文件扫描结束,编译器将不会处理写在END之后的任何内容。经过上面的介绍我们得出一些结论,这些结论是关于编写一个ARM汇编程序的必须因素,它们是:1.一个汇编语言程序至少要有一个代码段,否则芯片将不知道执行什么内容。2.一个汇编语言程序至少要有一个入口,否则芯片将不知道该从什么地方开始执行程序。3.一个汇编语言源文件应该以END进行标记结束。4.在当前IDE环境下系统默认的段名字叫RESET,这里没有明确说RESET段必须是代码段,所以也可以是其他属性的段。Cortex-M3汇编语言实践编程-9-编译、调试程序接下来我们把刚刚写好的程序进行编译,我们会发现这里有个警告:Figure1-12第一个程序编译警告双击这个警告会跳出如下内容:Figure1-13警告对应内容自习查看我们会发现这个以.sct结尾的文件实际是编译器在编译期生成的一个中间文件,警告内容说无法匹配*(InRoot$$Sections)这个段,实际上这个段就是编译器在编译期给C语言中的main函数定义的一个别名,因为我们没有写.C文件更没有写main函数所以编译器自然就不能匹配到main函数了,这个问题属于编译器的原因造成的,即编译器在编译程序的时候需要有main函数,否则将会报出警告。处理的办法是在工程当中添加一个C语言源文件并写入一个空的main函数。Cortex-M3汇编语言实践编程-10-Figure1-14将上述写好的文件保存并添加到工程后编译:Figure1-15这个时候又变成了另外一个警告,意思是有多个程序入口点被定义,但是没有指定一个主入口,原因是main函数本身也是一个程序的默认入口与我们子汇编文件中写的ENTRY意思是一样的,所以我们需要指定一个主入口或者只保留一个入口就可以了,因为程序中不需要很多入口所以只保留main删除ENTRY。Figure1-16Cortex-M3汇编语言实践编程-11-修改后再次编译就没有错误了,但是只有这几行代码芯片还是无法正常工作的,所以暂时还不能使用设备,那我们只好借助仿真器来调试一下看一看程序的结果,首先配置调试目标,需要去掉Runtomain这个选项,让程序从汇编代码开始执行:Figure1-17调试配置点击调试选项则会出现以下情况,看看反汇编器以及寄存器的值,完全不知道程序执行到哪里了。Figure1-18Cortex-M3汇编语言实践编程-12-点击复位之后可以看到以下界面,鼠标选中一行代码,反汇编器会自动跳到对应的位置。Figure1-19首先观察2号标记,也就是PC寄存器的值是0x0102F04E,同时注意我们在程序第7行的位置已经添加了断点,断点处代码对应的地址应该是0X08000000,图中3号所标记的地址,但是这个PC的地址很明显说明是程序跑飞了,也就是说程序根本没有按照我们预想的顺序去执行。再观察3和4说明在地址0x8000000处存放的正好是我们编写的第一行代码”MOVR0,#1“,而这条汇编指令对应的二进制机器码是0xF04F0001。实际上一般来讲系统代码都应该是从0x00地址处开始的这里为什么是0x08000000呢?那是因为这里的地址(0x08000000)是硬件的物理地址,而那个0x00地址只是逻辑地址,二者之间是有一个映射关系的,IDE在这里已经帮我们把映射之后的地址显示出来了,所以我们在这里看到的实际的物理地址(0x08000000)而不是逻辑地址(0x00000000)。这一点也可以通过下图来证明Cortex-M3汇编语言实践编程-13-Figure1-20图中的配置选项里分别给出了内存中只读存储区(READONLY,经常用来存放代码或者常量)与读写存储区(READWRITE,用于存放数据、变量等)的起始地址与大小,这个地址是系统默认给出的我们一般不会做修改。我们的代码段的访问熟属性是READONLY,那第一行代码的地址自然是从0X08000000处开始。如果我们再观察一下CM3的存储空间分配则不难发现0X08000000恰好属于代码段,而0X20000000恰好是SRAM的起始地址。Figure1-21Cortex-M3汇编语言实践编程-14-到这里我们仍然没有解决一个问题,那就是为什么程序会跑飞了呢?CM3的启动过程如果想彻底解决程序跑飞的问题我们就需要好好的研究一下CM3在启动的时候都做了哪些事情。一般来讲芯片启动后都是从0x00000000地址处开始执行,然后直接进入系统的RESET异常处理,在RESET处理中可能做一些堆栈初始化、寄存器复位等工作,处理完毕之后最终跳转到C语言编写的main函数当中执行C语言程序。CM3也不例外,同样是从0x00000000地址处开始执行程序,但是它和其他的芯片有一点差别,那就是Cortex-M3放在0x00000000地址处的并不是RESET的入口地址而是其他的东西,是什么呢?请看下表(表格出自《Cortex-M3权威指南》英文版第40页):Figure1-22Cortex-M3向量表通过观察上表我们不难发现,CM3的向量表0x00地址处存放的并不是RESET程序的入口而是系统主堆栈的入口地址,而0x04地址处存放的才是真正的RESET程序入口地址。Cortex-M3汇编语言实践编程-15-原来CM3启动时虽然是从0x00000000地址处开始但是并没有直接进入RESET程序,而是先把存放在0x00000000地址处的数据赋值给主堆栈指针(也就是M
本文标题:Cortex-M3汇编实践
链接地址:https://www.777doc.com/doc-5295715 .html