一、什么是固件库?
-
固化到EEPROM或者是芯片的FLASH中。
-
操作的是最底层的设备
按照我的理解就是,它就是一个封装好的函数库,跟前几次自己写库差不多。
二、CMSIS标准及库层次关系
因为基于 Cortex 系列芯片采用的内核都是相同的,区别主要为核外的片上外设的差异, 这些差异却导致软件在同内核,不同外设的芯片上移植困难。为了解决不同的芯片厂商生产的 Cortex 微控制器软件 的兼容性问题,ARM 与芯片厂商建立了 CMSIS 标准(Cortex MicroController Software Interface Standard)。 所谓 CMSIS 标准,实际是新建了一个软件抽象层。
CMSIS 标准中最主要的为 CMSIS 核心层,它包括了:
-
内核函数层:其中包含用于访问内核寄存器的名称、地址定义,主要由 ARM 公司提供。
-
设备外设访问层:提供了片上的核外外设的地址和中断定义,主要由芯片生产商提供。
可见 CMSIS 层位于硬件层与操作系统或用户层之间,提供了与芯片生产商无关的硬件抽象层,可以为接口外设、实时操作系统提供简单的处理器软件接口,屏蔽了硬件差异, 这对软件的移植是有极大的好处的。
三、固件库文件分析
打开固件库文件,我们可以看到这几个文件:
打开Libraries--CMSIS--Device--ST,里面这个文件就是代表你所要开发的芯片的厂商,点开后点进Source--Templates,会看到很多开发环境,我们点开arm,里面就是我们启动时所需要的启动文件。
在CMSIS中,以上圈出的两个文件是较为重要的。
-
Include文件夹
在 Include 文件夹中包含了 的是位于 CMSIS 标准的核内设备函数层的 Cortex-M 核通用的头文件,它们的作用是为那些采用 Cortex-M 核设计 SOC 的芯片商设计的芯片外设提供 一个进入内核的接口,定义了一些内核相关的寄存器(类似我们前面写的 stm32f4xx.h 文件, 但定义的是内核部分的寄存器)。
我们写 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”宏 来定义,而在不同的编译器下,宏自动更改到相应的值,实现了差异屏蔽。
较重要的是在 core_cm4.c 文件中包含了“stdint.h” 这个头文件,这是一个 ANSI C 文 件,是独立于处理器之外的,就像我们熟知的 C 语言头文件 “stdio.h” 文件一样。位于 RVMDK 这个软件的安装目录下,主要作用是提供一些类型定义。
1. /* exact-width signed integer types */
2. typedef signed char int8_t;
3. typedef signed short int int16_t;
4. typedef signed int int32_t;
5. typedef signed __int64 int64_t;
6.
7. /* exact-width unsigned integer types */
8. typedef unsigned char uint8_t;
9. typedef unsigned short int uint16_t;
10.typedef unsigned int uint32_t;
11.typedef unsigned __int64 uint64_t;
这些新类型定义屏蔽了在不同芯片平台时,出现的诸如 int 的大小是 16 位,还是 32 位 的差异。
2.Device文件夹
在 Device 文件夹下的是具体芯片直接相关的文件,包含启动文件、芯片外设寄存器定义、系统时钟初始化功能的一些文件,这是由 ST 公司提供的。
-
system_stm32f4xx.c 文件
这个文件包含了 STM32 芯片上电后初始化系统时钟、扩展外部存储器用的函数,例如 我们前几天提到供启动文件调用的“SystemInit”函数,用于上电后初始化时钟,该函数的 定义就存储在 system_stm32f4xx.c 文件。STM32F429 系列的芯片,调用库的这个 SystemInit 函数后,系统时钟被初始化为 180MHz,如有需要可以修改这个文件的内容,设 置成自己所需的时钟频率。
作用:初始化系统环境,配置系统时钟。
-
启动文件
在这个目录下,还有很多文件夹,如“ARM”、“gcc_ride7”、“iar”等,这些文件 夹下包含了对应编译平台的汇编启动文件,在实际使用时要根据编译平台来选择。我们使 用的 MDK 启动文件在“ARM”文件夹中。其中的“strartup_stm32f429_439xx.s”即为 STM32F429 芯片的启动文件,工程中使用的启动文件就是从这里复制过去的。如果使用其它型号的芯片,要在此处选择对应的启动文件。
-
stm32f4xx.h 文件
stm32f4xx.h 这个文件非常重要,是一个 STM32 芯片底层相关的文件。它是我们前几次自己定义的“stm32f4xx.h”文件的完整版,包含了 STM32 中所有的外设寄存器地址和结构体类型定义,在使用到 STM32 标准库的地方都要包含这个头文件。打开后就可以看到前几次学习寄存器时所配置的地址,非常的亲切...T T
3.STM32F10x_StdPeriph_Driver 文件夹
-
打开\STM32F4xx_DSP_StdPeriph_Lib_V1.8.0\Libraries\STM32F4xx_StdPeriph_Driver\src中的misc.c文件,这个文件是非常重要的中断文件。这个文件提供了外设对内核中的 NVIC(中断向量控制器)的访问函数,在配置中断时,我们必须把这个文件添加到工程中。
-
STM32F4xx_StdPeriph_Driver 文件夹下有 inc(include 的缩写)跟 src(source 的简写) 这两个文件夹,这里的文件属于 CMSIS 之外的的、芯片片上外设部分。
-
在 src 和 inc 文件夹里的就是 ST 公司针对每个 STM32 外设而编写的库函数文件,每个 外设对应一个 .c 和 .h 后缀的文件。昨天在自己写库函数的stm32f4xx_gpio.c 及 stm32f4xx_gpio.h 文件,就属于这一类。
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:使用这个配置文件根据芯片 型号增减 ST 库的外设文件,通过宏来指定芯片的型号,还可配置是否使用“断言”编译选项。
#if defined(STM32F429_439xx) || defined(STM32F446xx) || defined(STM32F469_479xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_ltdc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F429_439xx || STM32F446xx || STM32F469_479xx */
#if defined(STM32F427_437xx)
#include "stm32f4xx_cryp.h"
#include "stm32f4xx_hash.h"
#include "stm32f4xx_rng.h"
#include "stm32f4xx_can.h"
#include "stm32f4xx_dac.h"
#include "stm32f4xx_dcmi.h"
#include "stm32f4xx_dma2d.h"
#include "stm32f4xx_fmc.h"
#include "stm32f4xx_sai.h"
#endif /* STM32F427_437xx */
在 ST 标准库的函数中,一般会包含输入参数检查,即上述代码中的“assert_param” 宏,当参数不符合要求时,会调用“assert_failed”函数,这个函数默认是空的。 实际开发中使用断言时,先通过定义 USE_FULL_ASSERT 宏来使能断言,然后定义 “assert_failed”函数,通常我们会让它调用 printf 函数输出错误说明。使能断言后,程序运行时会检查函数的输入参数,当软件经过测试,可发布时,会取消 USE_FULL_ASSERT 宏来去掉断言功能,使程序全速运行。
#ifdef USE_FULL_ASSERT
/**
* @brief The assert_param macro is used for function's parameters check.
* @param expr: If expr is false, it calls assert_failed function
* which reports the name of the source file and the source
* line number of the call that failed.
* If expr is true, it returns no value.
* @retval None
*/
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
#endif /* __STM32F4xx_CONF_H */
5.最后,我们按照开机的流程来理一理以上的文件:
那明天就学学如何新建固件库工程吧!