编译和链接
在大多数情况下,一个项目包含多个单独编译的文件。经过编译过程后,每个源文件都会有一个相应的目标文件。
为了生成最终的可执行映像,需要一个单独的链接过程。
在链接阶段之后,IDE还可以以其他文件格式生成程序映像,以便将映像编程到设备。
Flash编程
几乎所有的Cortex-M微控制器使用内存来存储程序。
创建程序映像后,我们需要将程序下载到微控制器的闪存中。
要做到这一点,需要一个调试适配器。
实际的Flash编程过程可能相当复杂,但这些通常由IDE完全处理,只需要单击鼠标即可执行整个编程过程。如果愿意,也可以将应用程序下载到SRAM并从那里执行它们。
执行程序和调试
编译后的程序下载到微控制器后,您可以运行程序,看看它是否工作。
可以使用IDE中的调试环境来停止处理器(通常称为halt)并检查系统状态以确保其正常工作。
如果不能正常工作,可以使用各种调试特性(如单步调试)详细检查程序操作。所有这些都需要一个调试适配器来连接IDE和被测试的微控制器。
如果发现了软件缺陷,那么可以编程程序代码,重新编译项目,将代码下载到微控制器,然后再次测试。
如果使用的是开源工具链,则可能没有IDE,并且可能需要脚本或使用Makefile来处理编译和链接过程。
根据使用的微控制器产品,可以使用第三方工具将编译后的程序映像下载到微控制器中的闪存中。
在编译程序的执行过程中,您可以通过各种I/O机制(如UART接口或LCD模块)输出信息来检查程序的执行状态和结果。本书中的一些示例将展示如何实现其中一些方法。
编译嵌入式程序的过程取决于使用的开发工具。
首先,我们假设您正在使用C编程语言开发项目。这是微控制器软件开发中最常用的编程语言。我们的项目可能还包含一些汇编语言文件;例如,微控制器供应商提供的启动代码。
不同的开发工具有不同的方式来指定微控制器系统中程序和数据存储器的布局。
在ARM工具链中,可以使用一种称为分散加载文件,或者在Keil MDK-ARM,分散加载文件可以由mVision开发环境自动生成。
对于其他一些ARM工具链,您也可以使用命令行选项来指定ROM和RAM的位置。
在基于GNU工具链中,内存规范由链接脚本处理。这些脚本通常包含在商业GCC工具链的安装中。
但是,一些GCC用户必须自己创建这些文件。
在使用GNU gcc工具链时,通常一次编译整个应用程序,而不是将编译和链接阶段分开。
如果需要,gcc编译会自动调用链接器和汇编器。
这种安排确保将所需参数和库的详细信息正确地传递给链接器。使用链接器作为一个单独的步骤可能容易出错,因此大多数gcc工具供应商不建议使用。
外设是内存映射的,这意味着寄存器可以从系统内存映射中访问。为了在C程序中访问这些外设寄存器,我们可以使用指针。
通常,外设在使用之前需要一个初始化过程。这可能包括以下步骤:
所有这些初始化步骤都是通过在各个外设块中编程外设寄存器来完成的。如前所述,外设寄存器是内存映射的,因此可以使用指针访问。例如,你可以定义一个通用输入输出(GPIO)寄存器,它是由一些指针组成的。
__IO在CMSIS标准头文件中定义。它意味着一个易失性数据项(例如,外围寄存器),它可以被软件读或写。
除了__IO之外,外设寄存器也可以定义为__I(只读)和__O(只写)。
“uint32_t”(无符号32位整数)是C99中支持的数据类型。这确保了数据大小是32位的,独立于处理器架构,这可以帮助软件更具可移植性。要使用此数据类型,项目需要包含标准数据类型头(注意:如果您使用的是符合cmsis的设备头文件,则已在设备头文件中为您完成了此操作)。
ARM有庞大的生态系统,软件基础设施工作方式的某种形式的标准化就变得必要,以确保软件与各种开发工具以及不同软件解决方案之间的兼容性。
为了减少开发时间以及降低产品中存在缺陷的风险,软件重用变得越来越普遍。此外,嵌入式系统的复杂性也增加了第三方软件解决方案的使用。例如,嵌入式软件项目可能涉及来自许多不同来源的软件组件。
在这种情况下,各种软件组件的互操作性变得至关重要。由于所有这些原因,ARM与各种微控制器供应商、工具供应商和软件解决方案提供商合作开发CMSIS,这是一个涵盖大多数Cortex-M处理器和Cortex-M微控制器产品的软件框架。
CMSIS的目标包括:
CMSIS是一个不断发展的项目。它最初是作为一种Cortex-M微控制器建立设备驱动程序库一致性的方法。
从软件开发的角度来看,CMSIS-Core标准化了许多方面:
处理器外设的标准化定义——这些包括在嵌套向量中断控制器中的寄存器,处理器中的系统滴答定时器,可选的内存保护单元,系统控制块中的各种可编程寄存器,以及与调试功能相关的一些软件可编程寄存器。
访问处理器特性的标准化访问函数。这些函数包括使用NVIC进行中断控制的各种函数,以及访问处理器中特殊寄存器的函数。如果需要,仍然可以直接访问寄存器,但是对于一般编程来说,使用访问函数可以帮助软件可移植性。
大多数现代功能丰富的微控制器产品在应用程序开始之前需要一些时钟电路和电源管理寄存器的配置。
在符合CMSIS的设备驱动程序库中,这些配置步骤放在一个名为“SystemInit()”的函数中。
显然,此功能的实际实现是特定于设备的,可能需要针对各种项目需求进行调整。
然而,有一个标准化的功能名称,使它更容易设计人员挑选和开始使用一个新的Cortex-M微控制器设备。
CMSIS文件被集成到来自微控制器供应商的设备驱动程序库包中。
设备驱动程序库中的一些文件是由ARM编写的?并且在各种微控制器供应商中是通用的。其它文件是特定于供应商/设备的。一般来说,我们可以将CMSIS定义为多个层次:
另外还有一个用于外设访问的附加层:中间件访问层e。该层在当前版本的CMSIS中不存在。其思想是开发一组api,用于连接通用外设,如UART、SPI和以太网。如果存在这一层,中间件开发人员就可以基于这一层开发他们的应用程序,从而允许软件在设备之间轻松移植。
CMSIS文件包含在微控制器供应商提供的设备驱动程序包中。
因此,当您使用由微控制器供应商提供的符合CMSIS的设备驱动程序库时,已经在使用CMSIS。
通常,需要执行以下操作,向项目添加源文件,这包括:
在项目的搜索路径中添加头文件。这包括:
在某些情况下,当您创建新项目时,集成开发环境(IDE)会自动为您设置启动代码。否则,您只需要手动将设备驱动程序库中的启动代码添加到项目中。启动代码是处理器启动序列所必需的,它还包括中断处理所需的异常向量表定义。