STM32函数固件库
1、 STM32 固件库与 CMSIS 标准讲解
所谓STM32 固件库就是函数的集合,那么对这些函数有什么要求呢?这里就涉及到一个 CMSIS 标准的基础知识,这部分知识可以从《Cortex-M3 权威指南》中了解到,我们这里只是对权威指南的讲解做个概括性的介绍。经常有人问到 STM32 和 ARM 以及 ARM7是什么关系这样的问题,其实 ARM 是一个做芯片标准的公司,它负责的是芯片内核的架构设计,而 TI, ST 这样的公司,他们并不做标准,他们是芯片公司,他们是根据 ARM 公司提供的芯片内核标准设计自己的芯片。所以,任何一个做 Cortex-M3 芯片,他们的内核结构都是一样的,不同的是他们的存储器容量, 片上外设, IO 以及其他模块的区别。所以你会发现,不同公司设计的 Cortex-M3 芯片他们的端口数量,串口数量,控制方法这些都是有区别的, 这些资源他们可以根据自己的需求理念来设计。同一家公司设计的多种 Cortex-m3 内核芯片的片上外设也会有很大的区别,比如 STM32F103RBT 和 STM32F103ZET,他们的片上外设就有很大的区别。我们可以通过《Cortex-M3 权威指南》中的一个图来了解一下:

从上图可以看出,芯片虽然是芯片公司设计,但是内核却要服从 ARM 公司提出的 Cortex-M3内核标准了,理所当然,芯片公司每卖出一片芯片,需要向 ARM 公司交一定的专利费。
既然大家都使用的是 Cortex-M3 核,也就是说,本质上大家都是一样的,这样 ARM 公司为了能让不同的芯片公司生产的 Cortex-M3 芯片能在软件上基本兼容,和芯片生产商共同提出了一套标准 CMSIS 标准(Cortex Microcontroller Software Interface Standard) ,翻译过来是“ARM Cortex™ 微控制器软件接口标准”。 ST 官方库就是根据这套标准设计的。
  因为基于 Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异,这些差异却导致软件在同内核,不同外设的芯片上移植困难。为了解决不同的芯片厂商生产的 Cortex 微控制器软件 的兼容性问题, ARM 与芯片厂商建立了 CMSIS 标准(CortexMicroController Software Interface Standard)。
  所谓 CMSIS 标准,实际是新建了一个软件抽象层, 具体见见图 10-1。

CMSIS 分为 3 个基本功能层:
  1) 核内外设访问层: ARM 公司提供的访问,定义处理器内部寄存器地址以及功能函数。
  2) 中间件访问层:定义访问中间件的通用 API,也是 ARM 公司提供。
  3) 外设访问层:提供了片上的核外外设的地址和中断定义,主要由芯片生产商提供。
从图中可以看出, CMSIS 层在整个系统中是处于中间层,向下负责与内核和各个外设直接打交道,向上提供实时操作系统用户程序调用的函数接口。如果没有 CMSIS 标准,那么各个芯片公司就会设计自己喜欢的风格的库函数,而 CMSIS 标准就是要强制规定,芯片生产公司设计的库函数必须按照 CMSIS 这套规范来设计。
可见 CMSIS 层位于硬件层与操作系统或用户层之间,提供了与芯片生产商无关的硬件抽象层,可以为接口外设、实时操作系统提供简单的处理器软件接口,屏蔽了硬件差异,这对软件的移植是有极大的好处的。 STM32 的库,就是按照 CMSIS 标准建立的。
其实不用这么讲这么复杂的,一个简单的例子,我们在使用 STM32 芯片的时候首先要进行系统初始化, CMSIS 规范就规定, 系统初始化函数名字必须为 SystemInit,所以各个芯片公司写自己的库函数的时候就必须用 SystemInit 对系统进行初始化。 CMSIS 还对各个外设驱动文件的文件名字规范化,以及函数名字规范化等等一系列规定。上一节讲的函数GPIO_ResetBits 这个函数名字也是不能随便定义的,是要遵循 CMSIS 规范的。
2、STM32 官方库包介绍
STM32库是由 ST公司针对 STM32提供的函数接口,即 API(Application Program Interface),开发者可调用这些函数接口来配置STM32的寄存器,使开发人员得以脱离最底层的寄存器操作,有开发快速,易于阅读,维护成本低等优点。当我们调用库的 API的时候可以不用挖空心思去了解库底层的寄存器操作,就像当年我们学习 C语言的候,用 prinft()函数时只是学习它的使用格式,并没有去研究它的源码实现,如非必要,可以说是老死不相往来。实际上,库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为用户提供配置寄存器的接口。库开发方式与直接配置寄存器方式的区别。

  为什么采用库来开发
  对于 STM32,因为外设资源丰富,带来的必然是寄存器的数量和复杂度的增加,这时直接配置寄存器方式的缺陷就突显出来了:
  (1)、开发速度慢
  (2)、程序可读性差
  这两个缺陷直接影响了开发效率,程序维护成本,交流成本。库开发方式则正好弥补了这两个缺陷。而坚持采用直接配置寄存器的方式开发的程序员,会列举以下原因:
  (1)、 更直观
  (2)、 程序运行占用资源少
  初学 STM32的读者,普遍因为第一个原因而选择以直接配置寄存器的方法来学习。认为这种方法直观,能够了解到是配置了哪些寄存器,怎样配置寄存器。事实上,库函数的底层实现恰恰是直接配置寄存器方式的最佳例子,想深入了解芯片是如何工作的话,只要追踪到库的最底层实现就能理解,相信你会为它严谨、优美的实现方式而陶醉。
  2.1、STM32F10X
Libraries 文件夹下面有 CMSIS 和 FWlib 两个目录,这两个目录包含固件库核心的所有子文件夹和文件。
其中CMSIS目录下面是启动文件 ,core_cm3.c 和 core_cm3.h 就是 CMSIS 核心文件,提供进入 M3 内核接口,这是 ARM 公司提供,对所有 CM3 内核的芯片都一样。你永远都不需要修改这个文件,所以这里我们就点到为止。
这个目录下面有三个文件: system_stm32f10x.c, system_stm32f10x.h 以及 stm32f10x.h 文件。其中 system_stm32f10x.c 和对应的头文件 system_stm32f10x.h 文件的功能是设置系统以及总线时钟,这个里面有一个非常重要的 SystemInit()函数,这个函数在我们系统启动的时候都会调用,用来设置系统的整个时钟系统。
stm32f10x.h 这个文件就相当重要了,只要你做 STM32 开发,你几乎时刻都要查看这个文件相关的定义。这个文件打开可以看到,里面非常多的结构体以及宏定义。

  在 Libraries\ CMSIS 同一级还有一个 startup 文件夹,这个文件夹里面放的文件顾名思义是启动文件。我们可以看到 8 个 startup 开头的.s 文件。 

  启动文件是任何处理器在上点复位之后最先运行的一段汇编程序。在我们编写的 c语言代码运行之前,需要由汇编为 c语言的运行建立一个合适的环境,接下来才能运行我们的程序。所以我们也要把启动文件添加进我们的的工程中去。
  总的来说,启动文件的作用是:
  (1)、初始化堆栈指针 SP;
  (2)、初始化程序计数器指针 PC;
  (3)、 设置堆、栈的大小;
  (4)、设置异常向量表的入口地址;
  (5)、 配置外部 SRAM作为数据存储器(这个由用户配置,一般的开发板可没有外部 SRAM);
  (6)、设置 C库的分支入口__main(最终用来调用 main 函数);
  (7)、启动文件还调用了在 system_stm32f4xx.c文件中的SystemIni()   函数配置系统时钟
FWlib放的是 STM32 固件库源码文件。源文件目录下面的 inc 目录存放的是 stm32f10x_xxx.h 头文件,无需改动。 src 目录下面放的是 stm32f10x_xxx.c 格式的固件库源码文件。每一个.c 文件和一个相应的.h 文件对应。这里的文件也是固件库的核心文件,每个外设对应一组文件。

2.2、STM32F4X
2.2.1、 库目录、文件简介
  解压库文件后进入其目录:
  “STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\”
  软件库各文件夹的内容说明见图 10-2。

  Libraries: 文件夹下是驱动库的源代码及启动文件。
  Project : 文件夹下是用驱动库写的例子和工程模板。
  Utilities:包含了基于 ST 官方实验板的例程,以及第三方软件库,如 emwin 图形软件库、 fatfs 文件系统。
  MCD-ST Liberty…:库文件的 License 说明。
  Release_Note.html::库的版本更新说明。
  stm32f4xx_dsp_stdperiph…: 库帮助文档,这是一个已经编译好的 HTML 文件,主要讲述如何使用驱动库来编写自己的应用程序。说得形象一点,这个 HTML 就是告诉我们: ST 公司已经为你写好了每个外设的驱动了,想知道如何运用这些例子就来向我求救吧。不幸的是,这个帮助文档是英文的,这对很多英文不好的朋友来说是一个很大的障碍。但这里要告诉大家,英文仅仅是一种工具,绝对不能让它成为我们学习的障碍。其实这些英文还是很简单的,我们需要的是拿下它的勇气。
  在使用库开发时,我们需要把 libraries 目录下的库函数文件添加到工程中,并查阅库帮助文档来了解 ST 提供的库函数,这个文档说明了每一个库函数的使用方法。
  进入 Libraries 文件夹看到,关于内核与外设的库文件分别存放在 CMSIS 和STM32F4xx_StdPeriph_Driver 文件夹中。
  先看看 CMSIS 文件夹。
  STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries\CMSIS\文件夹下内容见图 10-3。

  其中 Device 与 Include 中的文件是我们使用得最多的,先讲解这两个文件夹中的内容。
  (1)Include 文件夹
  在 Include 文件夹中包含了 的是位于 CMSIS 标准的核内设备函数层的 Cortex-M 核通用的头文件,它们的作用是为那些采用 Cortex-M 核设计 SOC 的芯片商设计的芯片外设提供一个进入内核的接口,定义了一些内核相关的寄存器(类似我们前面写的 stm32f4xx.h 文件,但定义的是内核部分的寄存器)。这些文件在其它公司的 Cortex-M 系列芯片也是相同的。
  至于这些功能是怎样用源码实现的,可以不用管它, 只需把这些文件加进我们的工程文件即可,有兴趣的朋友可以深究,关于内核的寄存器说明,需要查阅《cortex_m4_TechnicalReference Manual》及《Cortex™-M4 内核参考手册》文档,《STM32 参考手册》只包含片上外设说明,不包含内核寄存器。
  我们写 STM32F4 的工程,必须用到其中的四个文件: core_cm4.h、 core_cmFunc.h、corecmInstr.h、 core_cmSimd.h,其它的文件是属于其它内核的,还有几个文件是 DSP 函数库使用的头文件。
  core_cm4.c 文件有一些与编译器相关条件编译语句,用于屏蔽不同编译器的差异。里面包含了一些跟编译器相关的信息,如: “__CC_ARM ” (本书采用的 RVMDK、 KEIL),“__GNUC__ ” (GNU 编译器)、“ICC Compiler” (IAR 编译器)。 这些不同的编译器对于C 嵌入汇编或内联函数关键字的语法不一样,这段代码统一使用“__ASM、 __INLINE”宏来定义,而在不同的编译器下,宏自动更改到相应的值,实现了差异屏蔽, 见代码清单10-1。

较重要的是在 core_cm4.c 文件中包含了“stdint.h” 这个头文件,这是一个 ANSI C 文件,是独立于处理器之外的,就像我们熟知的 C 语言头文件 “stdio.h” 文件一样。位于RVMDK 这个软件的安装目录下,主要作用是提供一些类型定义。见代码清单 10-2。

这些新类型定义屏蔽了在不同芯片平台时,出现的诸如 int 的大小是 16 位,还是 32 位的差异。所以在我们以后的程序中,都将使用新类型如 uint8_t 、 uint16_t 等。
  在稍旧版的程序中还经常会出现如 u8、 u16、 u32 这样的类型,分别表示的无符号的 8位、 16 位、 32 位整型。初学者碰到这样的旧类型感觉一头雾水,它们定义的位置在STM32f4xx.h 文件中。建议在以后的新程序中尽量使用 uint8_t 、 uint16_t 类型的定义。
  core_cm4.c 跟启动文件一样都是底层文件,都是由 ARM 公司提供的,遵守 CMSIS 标准,即所有 CM4 芯片的库都带有这个文件,这样软件在不同的 CM4 芯片的移植工作就得以简化。
  (2)Device 文件夹
  在 Device 文件夹下的是具体芯片直接相关的文件,包含启动文件、芯片外设寄存器定义、系统时钟初始化功能的一些文件,这是由 ST 公司提供的。
   system_stm32f4xx.c 文件
    文件目录: \Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates
    这个文件包含了 STM32 芯片上电后初始化系统时钟、扩展外部存储器用的函数,例如我们前两章提到供启动文件调用的“SystemInit”函数,用于上电后初始化时钟,该函数的定义就存储在 system_stm32f4xx.c 文件。 STM32F429 系列的芯片,调用库的这个SystemInit 函数后,系统时钟被初始化为 180MHz,如有需要可以修改这个文件的内容,设置成自己所需的时钟频率。
   启动文件
    文件目录: Libraries\CMSIS\Device\ST\STM32F4xx\Source\Templates
    在这个目录下,还有很多文件夹,如“ARM”、“gcc_ride7”、“iar”等,这些文件夹下包含了对应编译平台的汇编启动文件,在实际使用时要根据编译平台来选择。我们使用的 MDK 启动文件在“ARM”文件夹中。其中的“strartup_stm32f40xx.s”即为STM32F407 芯片的启动文件。
   stm32f4xx.h 文件
    文件目录: Libraries\CMSIS\Device\ST\STM32F4xx\Include
    stm32f4xx.h 这个文件非常重要,是一个 STM32 芯片底层相关的文件。它是我们前两章自己定义的“stm32f4xx.h”文件的完整版,包含了 STM32 中所有的外设寄存器地址和结构体类型定义,在使用到 STM32 标准库的地方都要包含这个头文件。
  CMSIS 文件夹中的主要内容就是这样,接下来我们看看 STM32F4xx_StdPeriph_Driver文件夹。
  (3)STM32F4xx_StdPeriph_Driver 文件夹
  文件目录: Libraries\STM32F4xx_StdPeriph_Driver
  进入 libraries 目录下的 STM32F4xx_StdPeriph_Driver 文件夹,见图 10-4。

  STM32F4xx_StdPeriph_Driver 文件夹下有 inc(include 的缩写)跟 src(source 的简写)这两个文件夹,这里的文件属于 CMSIS 之外的的、芯片片上外设部分。 src 里面是每个设备外设的驱动源程序, inc 则是相对应的外设头文件。 src 及 inc 文件夹是 ST 标准库的主要内容,甚至不少人直接认为 ST 标准库就是指这些文件,可见其重要性。
  在 src 和 inc 文件夹里的就是 ST 公司针对每个 STM32 外设而编写的库函数文件,每个外设对应一个 .c 和 .h 后缀的文件。我们把这类外设文件统称为: stm32f4xx_ppp.c 或stm32f4xx_ppp.h 文件, PPP 表示外设名称。 
  如针对模数转换(ADC)外设,在 src 文件夹下有一个 stm32f4xx_adc.c 源文件,在 inc 文件夹下有一个 stm32f4xx_adc.h 头文件,若我们开发的工程中用到了 STM32 内部的 ADC,则至少要把这两个文件包含到工程里。见图 10-5。

  这两个文件夹中,还有一个很特别的 misc.c 文件,这个文件提供了外设对内核中的NVIC(中断向量控制器)的访问函数,在配置中断时,我们必须把这个文件添加到工程中。
  (4)stm32f4xx_it.c、 stm32f4xx_conf.h 文件
  文件目录:
  STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Project\STM32F4xx_StdPeriph_Templates
  在这个文件目录下, 存放了官方的一个库工程模板,我们在用库建立一个完整的工程时,还需要添加这个目录下的 stm32f4xx_it.c、 stm32f4xx_it.h、 stm32f4xx_conf.h 这三个文件。
  stm32f4xx_it.c:这个文件是专门用来编写中断服务函数的,在我们修改前,这个文件已经定义了一些系统异常(特殊中断)的接口,其它普通中断服务函数由我们自己添加。但是我们怎么知道这些中断服务函数的接口如何写?是不是可以自定义呢?答案当然不是的,这些都有可以在汇编启动文件中找到, 在学习中断和启动文件的时候我们会详细介绍stm32f4xx_conf.h: 这个文件被包含进 stm32f4xx.h 文件。 ST 标准库支持所有STM32F4 型号的芯片,但有的型号芯片外设功能比较多,所以使用这个配置文件根据芯片型号增减 ST 库的外设文件, 具体见代码清单 10-3,针对   STM32F429 和 STM32F427 型号芯片的差异,它们实际包含不一样的头文件,我们通过宏来指定芯片的型号。


   stm32f4xx_conf.h 这个文件还可配置是否使用“断言” 编译选项, 见代码清单 10-4。 

  在 ST 标准库的函数中,一般会包含输入参数检查,即上述代码中的“assert_param”宏,当参数不符合要求时,会调用“assert_failed”函数,这个函数默认是空的。
  实际开发中使用断言时,先通过定义 USE_FULL_ASSERT 宏来使能断言,然后定义“assert_failed”函数,通常我们会让它调用 printf 函数输出错误说明。 使能断言后,程序运行时会检查函数的输入参数,当软件经过测试,可发布时, 会取消 USE_FULL_ASSERT宏来去掉断言功能, 使程序全速运行。
  2.2.2、 库各文件间的关系
  前面向大家简单介绍了各个库文件的作用,库文件是直接包含进工程即可,丝毫不用修改,而有的文件就要我们在使用的时候根据具体的需要进行配置。接下来从整体上把握一下各个文件在库工程中的层次或关系,这些文件对应到 CMSIS 标准架构上。见图 10-6。

  图 10-6 描述了 STM32 库各文件之间的调用关系,这个图省略了 DSP 核和实时系统层部分的文件关系。在实际的使用库开发工程的过程中,我们把位于 CMSIS 层的文件包含进工程, 除了特殊系统时钟需要修改 system_stm32f4xx.c,其它文件丝毫不用修改,也不建议修改。
  对于位于用户层的几个文件,就是我们在使用库的时候,针对不同的应用对库文件进行增删(用条件编译的方法增删)和改动的文件。
 
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号