这次我们来聊聊CMSIS。之前在Kile环境下创建STM32工程的时候,对有些文件的加入总不是很了解,书上或网上建立工程的教程对于这些文件的加入也是一笔带过,或者直接不说。对于类似名叫core_cm3.h,system_stm32f4xx.c的文件的作用感到比较困惑。在阅读了《ARM Cortex-m3与Conrtex-m4权威指南》之后,对CMSIS才有了一个比较清楚的了解,也知道为什么工程中需要加入这些文件了。
以下内容节选自《ARM Cortex-m3与Conrtex-m4权威指南》第三版,Joseph Yiu著,清华大学出版社出版。根据这些描述我将创建一个典型的STM32F4的工程,以便更好的来理解我们对CMSIS的阐述。如果你想深入了解Cortex-m3或Cortex-m4而不是停留在简单的函数调用的话,我非常建议阅读本书,它会很好的解答你在学习过程中遇到的很多问题。
1.CMSIS简介
CMSIS由ARM开发,它使得微控制器和软件供应商可以使用一致的软件结构来开发Cortex微控制器的软件,许多Cortex-M微控制器的软件产品都是符合CMSIS的。
由于当前庞大的生态系统,对软件结构进行某种形式的标准化已经非常必要,这样可以确保多种开发工具和不同软件解决方案的兼容性。同时,嵌入式系统也变得越来越复杂,开发和软件测试的工作量也显著增加了。为了减少开发时间并且降低产品中存在缺陷的风险,软件重用已经越来越普遍。另外,嵌入式系统的复杂度也增加了对第三方软件解决方案的依赖。例如,一个嵌入式软件工程可能会涉及各方面的软件部件:
·内部开发者开发的软件
·重用的其他项目的软件
·微控制器供应商的设备驱动库
·嵌入式OS
·通信协议栈等其他的第三方软件产品
在这种情况下,各种软件产品间的配合已经非常关键。由于所有这些原因,ARM同各家微控制器供应商、工具供应商和软件解决方案提供商一道开发了CMSIS——一个涵盖了大多数Cortex-M处理器和Cortex-M微控制器产品的软件框架。CMSIS项目仍在不断更新。
CMSIS项目有CMSIS-Core、CMSIS-DSP、CMSIS-SVD、CMSIS-RTOS、CMSIS-DAP。我们最能直观感受到的就是CMSIS-Core。这些项目所做的工作都是对Contex-M芯片的使用进行一个标准化。下面我们来看看CMSIS-Core进行了哪些标准化。
2.CMSIS-Core所做的标准化
(1)处理器外设的标准化定义。
这里注意区分处理器外设和微控制器的外设的区别,微控制器就像STM32,处理器就像STM32中的Cortex-M,我们知道处理器也是有自己的私房外设的,其中包括嵌套向量中断控制器(NVIC)中的寄存器、处理器中的系统节拍定时器(SysTick)、可选的存储器保护单元(MPU)、系统控制块(SCB)中的多个可编程寄存器以及一些和调试特性相关的软件可编程寄存器。注意:有些Cortex-M4中的寄存器在Cortex-M3中是不可用的,类似地,Cortex-M3和Cortex-M4中的一些寄存器在Cortex-M0中也是不可用的。
(2)访问处理器特性的标准化函数。
其中包括使用NVIC进行中断控制的多个函数以及访问处理器中特殊寄存器的函数。若需要的话,也可以直接访问寄存器,而使用这些函数(有时也被称作应用编程接口,或者叫API)进行编程有助于提高软件可移植性。实际上,你可以回忆在core_cm4.h中看到的很多“奇怪”的函数,这里的函数指的就是他们。你可以放心的使用他们而不必担心这些代码在其他cortex系列的处理上无法运行,当然前提是代码得符合CMSIS标准。
(3)操作特殊指令的标准化函数。
Cortex-M处理器支持几个用于特殊目的的指令(例如,等待中断WFI,用于进入休眠模式),这些指令无法用普通的IEC/ISOC语言生成。CMSIS实现了一组函数,C程序代码可以利用这些函数实现特殊指令。若没有这些函数,用户必须得使用工具链相关的解决方案,如内在函数或内联汇编,才能将特殊指令插入应用程序中,这样会降低软件的可重用性,而且为了避免出现错误,可能还需要对工具链的深入了解。CMSIS为这些特性提供了一种标准的API,这样应用程序开发者就可以轻松使用了。它们也存在于类似core_cm4.h的文件中。
(4)系统异常处理的标准化命名。
多个系统异常类型在Cortex-M处理器的架构中有所体现,通过赋予这些系统异常处理标准化的命名,开发适用于多种Cortex-M产品的软件也就更加容易。这对嵌入式OS开发者尤其重要,因为嵌入式OS需要使用一些系统异常。
(5)系统初始化的标准函数。
对于多数具有丰富特性的现代微控制器产品,在应用程序开始前都需要配置时钟电路和电源管理寄存器。在符合CMSIS的设备驱动库中,这些配置过程由Systemlnit()实现。很显然,该函数的实际实现是设备相关的,而且可能需要适应多种工程需求。不过,由于有了标准的函数名、函数的标准使用方式以及函数的标准位置,设计者就能很容易地开始使用Cortex-M微控制器。
(6)描述时钟频率的标准化的变量。
这个看起来必要性不是很大,不过有时应用程序代码需要知道系统当前运行的时钟频率。例如,在设置UART波特率分频器或初始化嵌人式OS使用的SysTick定时器时可能需要这种信息。CMSIS-Core中定义了一个软件变量SystemCoreClock(用于CMSIS的1.3或者更新的版本,之前的版本为SystemFreq)。
另外,CMSIS-Core还提供了设备驱动库的通用平台。每个设备驱动库看起来都是一样的,这样初学者使用设备就更加容易,而且软件开发人员也可以很轻松地开发出用于多种Cortex-M微控制器产品的软件。
3.CMSIS-Core的组织结构
CMSIS文件被集成在微控制器供应商提供的设备驱动库软件包中,设备驱动库中的有些文件是ARM准备的,对于各家微控制器供应商都是一样的,其他文件则取决于供应商/设备。一般来说,可以将CMSIS定义为以下几层:
1、内核外设访问层。名称定义、地址定义以及访问内核寄存器和内核外设的辅助函数,这是处理器相关的,由ARM提供。
2、设备外设访问层。名称定义、外设寄存器的地址定义以及包括中断分配、异常向量定义等的系统设计,这是设备相关的(注意:同一家供应商的多个设备可能会使用同一组文件)。
3、外设访问函数。访问外设的驱动代码,这是供应商相关的,而且是可选的。在开发应用程序时,可以选择使用微控制器供应商提供的外设驱动代码,或者有必要,也可以直接访问外设。
对于外设访问还提出了另外一层:中间件访问层。该层在当前的CMSIS版本中不存在,现在的设想为,开发一组用于访问UART、SPI以及以太网等常见外设的API。若该层存在,中间件开发人员可以基于该层开发自己的应用程序,这样软件在设备间移植也就更加容易。各层角 {MOD}如下图所示
注意在有些情况下,设备驱动库中可能会包含用于微控制器供应商设计的NVIC的函数(例如可能大部分人都使用过的misc.c文件中的函数),它们是供应商定义的。CMSIS的目标为提供一个共同的起点,微控制器供应商也可以根据自己的意愿添加其他的函数。不过若软件需要在另外一个微控制器产品上重用,就需要移植。
4、如何使用CMSIS-Core
CMSIS文件位于微控制器供应商提供的设备驱动软件包中,因此,在使用微控制器供应商提供的设备驱动库时,就已经在使用CMSIS了。
一般来说,需要做到以下几点。
(1)将源文件添加到工程中,其中包括:
·设备相关,工具链相关的启动代码,C或汇编。
·设备相关的设备初始化代码(如system_stm32f1xx.c)。
·用于外设访问功能的其他供应商相关的源文件,这是可选的(如GPIO,USART等外设的.c文件)。
·对于CMSIS-Core库的CMSIS2.00或者之前版本,为了访问内核寄存器,可能还需要将一个处理器相关的C程序文件(如core_cm3.c)添加到工程中,从CMSIS-Core版本2.10开始就不再需要了(只需要添加core_cm3.h即可)。
(2)将头文件添加到搜索路径中,其中包括:
·用于外设寄存器定义和中断分配定义的设备相关的头文件(如stm32f1xx.h)。
·用于设备初始化代码的设备相关的头文件(如system_stm32f1xx.h)。
·多个处理器相关的头文件(如core_cm3.h、core_cm4.h,它们对于所有的微控制器供应商都是相同的)。
·其他可选的用于外设访问的供应商相关的头文件(如GPIO,USART等外设的.h文件)。
·有些情况下,开发组件中可能会包含一些预安装的CMSIS支持文件。
有些情况下,在创建一个新的工程时,集成开发环境(IDE)会自动设置启动代码,要不然,还需要手动将设备驱动库中的启动代码(如startup_stm32f401xx.s)添加到工程中。处理器的启动流程需要启动代码,它包括中断处理所需的异常向量表定义。
具体如下图所示:
下面我将利用我下载得到的STM32F4xx_DSP_StdPeriph_Lib_V1.8.0标准库根据上面第4条如何使用CMSIS-Core的说明来构建一个基于标准库的STM32F4开发环境。在STM32F4xx_DSP_StdPeriph_Lib_V1.8.0LibrariesCMSIS目录下有一个叫index的html文件,对其中的CMSIS文件作用做了说明:
从中我们可以看出我们要使用的CMSIS-Core文件在Include文件夹中。我们可以看到这里还有CMSIS-DSP项目,日后如果要用微控制器进行DSP之类的,可以来使用这其中的文件,可以看到它甚至还为ARMCC和GCC开发工具做好了相应的库,如GCC就是一个集成的.a文件,非常方便,也比较高效,那么下面就开始动手吧。
1、首先在桌面新建一个文件夹stm32f4_TestProject。
2、打开并在其中建立一个名叫CMSIS的文件夹,专门存放我们的CMSIS文件;建立MDK文件夹,用来存放工程文件;建立USER文件夹,用来存放应用代码;建立StdPeriph_Lib文件夹,用来存放外设标准库函数。
3、在CMSIS中建立Include目录,加入core_cm4.h、core_cmSimd.h、core_cmInstr.h、core_cmFunc.h、stm32f4xx.h、stm32f4xx.h。继续在CMSIS目录中加入启动文件startup_stm32f401xx.s。加入system_stm32f4xx.c文件
4、在StdPeriph_Lib目录中视需要加入标准外设启动库函数,在USER目录添加自己的工程文件,和一个stm32f4xx_conf.h控制引入的头文件即可。
5、打开kile5,新建工程,设备选择STM32F4RE,而后添加文件到工程,添加头文件路径就不再说了。
6,添加宏定义 USE_STDPERIPH_DRIVER,STM32F40XX
7,编译运行, 0 Error(s), 0 Warning(s).
实际上可以看到,这就是按照上图的工程结构来进行搭建的,只有对每一个文件的加入理解了,才能更好的组织工程代码,使我们的工作更有条理。