|
STM32 Embedded Software 工作以来一直使用 ST 的 STM32 系列芯片,ST 为开发者提供了非常方便的开发库。到目前为止,有标准外设库(SPL 库)、HAL 库、LL 库 三种。前两者都是常用的库,后面的 LL 库是 ST 最近才添加,随 HAL 源码包一起提供,目前支持的芯片也偏少。各库如下所示: & q, b% G; A y
' N6 E9 j6 `( J: p) c% R9 r
: l! j w4 p6 L! H, M ] 其中,SPL 库 和 HAL 库两者相互独立,互不兼容。几种库的比较如下:8 B/ J4 S0 o) Q7 `7 z# P( c
3 K7 o, X5 f# s- t1 W" R
( f. c3 A& U0 [/ o& p) [. a; Y7 ^
2 ?( h0 D, `$ W
目前几种库对不同芯片的支持情况如下:
2 z/ l: y, Y5 I# Z8 h* c1 @) n7 r- k9 C
. J. F6 F6 p/ Q1 B# {6 t5 V ST 中文官网上有一篇《关于ST库函数的代码性能对比》的文章,其中对比了各种库的性能如下:
' |3 \9 d, G4 q* j7 i
% _& Q( Q- c6 l z- j. w3 T
/ \3 Y6 I$ q1 h) S" t/ s; n5 b: h
+ m0 _* `2 e* h5 `7 @6 ~. {
X7 m Y( |8 ~8 gSTM32 Snippets' q7 X7 L0 H( q1 H! c8 {
它是代码示例的集合,直接基于 STM32 外设寄存器,可在文档和软件包中使用。由于处在最底层,因此需要开发者直接操作外设寄存器,对开发者要求比较高,通常针对于对汇编程序比较了解的资深嵌入式工程师!
( n l9 ]- x- P% N: I7 X0 s 这个库使用比较少,目前只在 STM32F0 和 STM32L0 系列中有提供。两个库都有各自的说明文档。主要就是下图所示的这些:
* N: ~! T+ Q: l ; Q: I5 d: ]# T
6 p6 }/ t v+ m- \/ Q* E
严格来说,它不能称为库,仅仅就是将 MCU 中的寄存器进行了结构化的封装,库文件主要就是一些 .h 文件。如下是对 ADC 的封装( E) Z Z6 J4 u
& r( _# C' i' t% k
- /**! Q/ g: X& p2 M% H
- * @brief Analog to Digital Converter
! D0 j2 q! G9 W A! L - */
) B3 k: E E6 d# V - 8 z; M. s$ |# S+ x
- typedef struct# I1 u! C) w! Y5 Y9 X# n; T9 L
- {
1 o l& g2 w; `" ~$ R& F - __IO uint32_t ISR; /*!< ADC Interrupt and Status register, Address offset:0x00 */
3 T/ K! s2 K* t - __IO uint32_t IER; /*!< ADC Interrupt Enable register, Address offset:0x04 */
! e6 h1 L2 E$ p5 K6 d3 ^ - __IO uint32_t CR; /*!< ADC Control register, Address offset:0x08 */
. S4 {! w- j. V7 N. Q - __IO uint32_t CFGR1; /*!< ADC Configuration register 1, Address offset:0x0C */) `* S% l7 ?$ x" t! p
- __IO uint32_t CFGR2; /*!< ADC Configuration register 2, Address offset:0x10 */7 a: m- D; T+ }! ?
- __IO uint32_t SMPR; /*!< ADC Sampling time register, Address offset:0x14 */
% F+ I1 x8 k. L. V4 u - uint32_t RESERVED1; /*!< Reserved, 0x18 */ c: _2 C$ l0 t8 t0 h* \% P
- uint32_t RESERVED2; /*!< Reserved, 0x1C */
! s+ a" X5 _. w0 C ` - __IO uint32_t TR; /*!< ADC watchdog threshold register, Address offset:0x20 */ q2 F" v6 Y9 k( G2 E4 C8 J; ^
- uint32_t RESERVED3; /*!< Reserved, 0x24 */
) g$ _1 F8 [( f3 |, p/ P - __IO uint32_t CHSELR; /*!< ADC channel selection register, Address offset:0x28 */. \2 G5 K9 K+ a$ {
- uint32_t RESERVED4[5]; /*!< Reserved, 0x2C */4 l$ ~& b5 a3 ~: K
- __IO uint32_t DR; /*!< ADC data register, Address offset:0x40 */6 _8 {. {6 z8 A! B6 k; u5 ~ s& P/ g$ @
- }ADC_TypeDef;% B. v; T2 I# |% B$ W! B
! a, J5 P% }, E6 [+ j" z, w- typedef struct1 B8 @/ w0 Y. O6 `' [2 `5 q) r$ x
- {
- D6 V& u9 B; A4 j - __IO uint32_t CCR;
/ z! H2 s+ u: X2 z: _# b - }ADC_Common_TypeDef;
复制代码
3 e9 V+ F% \- u) v1 J- X7 j( U' \7 S" g9 V+ K/ S
9 D- Y, \& W* p T
在实际使用时,我们就可以结构化的访问 MCU 的寄存器,如下是配置 ADC 的函数实现: 6 |; J, J8 p+ Q e
- /**
+ H% L3 I; L, h2 H - * @brief This function configure the ADC to convert the internal reference voltage (VRefInt) O4 B. A2 ?9 f8 q# p! [3 ^* T2 {
- * The conversion frequency is 14MHz 4 o! Q: g4 O. s3 j. `% x9 V
- * @param None; k) S8 r( E! [# }
- * @retval None
! @& ~! r3 H) P3 X" } - */
3 V) Z5 s- p% x. ]' |& T. V5 U - __INLINE void ConfigureADC(void)
: M" F. g9 Y6 ^' X% i- l - {1 P3 B5 w8 N6 t' n" L
- /* (1) Select the clock mode (refer ADC_PRESCALER definition :
: x0 s: B3 I! { - HSI14 by writing 00 in CKMODE (reset value)
: P0 K# L! }5 h! t1 E/ u8 j$ ~+ h1 S - DIV2 or DIV 4 */
K$ i2 C H0 A - /* (2) Select the auto off mode *// t8 H. Z" J- r: R: ^
- /* (3) Select CHSEL17 for VRefInt */" P* e, g0 ?2 E2 y8 \: v
- /* (4) Select a sampling mode of 111 i.e. 239.5 ADC clk to be greater than 17.1us */
' l x& a* |5 P' s2 W5 S% e0 f5 f - /* (5) Wake-up the VREFINT (only for VBAT, Temp sensor and VRefInt) */
7 d( n. n9 G5 M' p. q* ~: u - ADC1->CFGR2 |= ADC_PRESCALER; /* (1) */: t# z( m+ J5 D) R8 Q: \6 Y
- ADC1->CFGR1 |= ADC_CFGR1_AUTOFF; /* (2) */8 E/ z! S7 G1 j1 v$ _
- ADC1->CHSELR = ADC_CHSELR_CHSEL17; /* (3) */
/ [! p* }) F- n, F; I2 T# s7 g - ADC1->SMPR |= ADC_SMPR_SMP_0 | ADC_SMPR_SMP_1 | ADC_SMPR_SMP_2; /* (4) */4 k+ Y2 j3 ?- x4 q) u/ p, R8 G" S
- ADC->CCR |= ADC_CCR_VREFEN; /* (5) */
* d1 a5 y) [5 ~$ m - }
复制代码 # A' Q" v* Q, o% S- v! f
标准外设库(Standard Peripheral Libraries)0 K' _2 w7 o) [9 C: t4 u& u6 M- `
标准外设库(Standard Peripherals Library)是对 STM32 芯片的一个完整的封装,包括所有标准器件外设的器件驱动器。这应该是目前使用最多的 ST 库。几乎全部使用 C 语言实现。但是,标准外设库也是针对某一系列芯片而言的,没有可移植性。
! u$ T: }1 T8 b1 |: _4 N/ S5 G, | $ K" [ B* y4 Q; K
; n4 Y1 H/ S+ Y& w c. @1 p, ]8 w 相对于 HAL 库,标准外设库仍然接近于寄存器操作,主要就是将一些基本的寄存器操作封装成了 C 函数。开发者需要关注所使用的外设是在哪个总线之上,具体寄存器的配置等底层信息。- a% l3 V4 F2 R
$ }, K- U+ a2 Y& k4 B5 B& G
相对于 STM32 Snippets,标准外设库对各外设的进行了一次封装,而不是仅仅局限在对寄存器的封装。实现了各外设的基本操作接口。
; F3 R( [6 X; A, H) j$ l 在文档方面,我只发现了针对 F2 系列和 F3 系列的详细说明文档,如下图所示:
( c# K; V s* x. a- z* M
; ^& ^+ _1 X( ]/ U- k- U
: T: O) o$ u8 e' Q( t! h* k标准外设库的文件基本架构并不复杂。下图显示了 STM32F10xx 标准外设库文件的基本架构# T* ?$ }! X2 T
# A+ s' w' e# j9 E& d5 U' Q
" J* V7 K4 m$ C
! S* A% C2 V( c+ `
其他系列的库文件结构和上图基本都是一致的!
% w a3 `5 N3 G
# ^* J, u* s) L; D! k2 N ST 为各系列提供的标准外设库稍微有些区别。例如,STM32F1x 的库和 STM32F3x 的库在文件结构上就有些不同,此外,在内部的实现上也稍微有些区别,这个在具体使用(移植)时,需要注意一下!但是,不同系列之间的差别并不是很大,而且在设计上是相同的。STM32 的标准外设库涵盖以下 3 个抽象级别:
7 T" @' r1 \+ ]5 ]4 A- [
- 包含位,位域和寄存器在内的完整的寄存器地址映射
- 涵盖所有外围功能(具有公共API的驱动器)的例程和数据结构的集合。
- 一组包含所有可用外设的示例,其中包含最常用的开发工具的模板项目。7 \6 ^* Z5 U4 m) L) }9 P0 T
9 y4 m2 N% c. i+ L
关于更详细的信息,可以参考 ST 的官方文档,文档中对于标准外设库函数命名、文件结构等都有详细的说明。 ( D7 ^- u. N: H I1 ~4 l4 |& S
STM32Cube
& M: e9 f$ r* {7 G7 o0 w& x9 M2 M9 ] ST 为新的标准库注册了一个新商标:STMCube™。并且,ST专门为其开发了配套的桌面软件 STMCubeMX,开发者可以直接使用该软件进行可视化配置,大大节省开发时间。0 N# `7 R) R$ K. G9 [
0 T5 T6 m e2 t5 E
3 O3 b, r0 K$ b 这其中就包含了 HAL 库和最近新增的 LL 库。如下图:1 I. K! I$ O5 t) M& z9 i
) E+ L% b# `5 B* }
: j2 I) d# x/ W! m/ Q2 {! c2 _, D! z: H! V1 t% C
从上图不难看出,LL 库和 HAL 库两者相互独立,只不过 LL 库更底层。而且,部分 HAL 库会调用LL库(例如:USB驱动)。同样,LL 库也会调用 HAL 库6 x" O% _7 h! U7 d
用户可以使用 STMCubeMX 直接生成对应芯片的整个项目(目前主流开发工具的项目基本全支持),STMCubeMX 负责给整理各种需要的源码文件。 - `7 T6 ~* |7 I8 l( J% s/ m2 C
注意:
8 @6 q1 S* X. D% ] 1. 个人感觉STMCubeMX生成的项目并不够简洁,源码的组织结构也并不是很好。
, J4 K% G$ M- {. q6 \. N 2. STMCubeMX在生产项目时,可以选择使用HAL库或者LL库。但是部分组件的HAL库会调用LL库 1 f+ A- D+ y% x
HAL 库
3 c1 z+ W$ F l* \ HAL是 Hardware Abstraction Layer 的缩写,中文名:硬件抽象层。HAL 库是 ST 为 STM32 最新推出的抽象层嵌入式软件,可以更好的确保跨 STM32 产品的最大可移植性。该库提供了一整套一致的中间件组件,如 RTOS,USB,TCP/IP 和 图形 等。! J1 f# p6 V6 k/ g M& x5 e# ?
HAL 库是基于一个非限制性的 BSD 许可协议(Berkeley Software Distribution)而发布的开源代码。 ST 制作的中间件堆栈(USB 主机和设备库,STemWin)带有允许轻松重用的许可模式, 只要是在 ST 公司的 MCU 芯片上使用,库中的中间件(USB 主机/设备库,STemWin)协议栈即被允许随便修改,并可以反复使用。至于基于其它著名的开源解决方案商的中间件(FreeRTOS,FatFs,LwIP和PolarSSL)也都具有友好的用户许可条款。) Y/ m7 O( B* \/ V! c. ~+ o6 l9 k
作为目前 ST 主推的外设库,HAL库相关的文档还是非常详细的。
* p; X: @( \! t3 c! v* x u2 [
! X y' q9 |$ o/ Z4 a5 \' s! d6 D, X# m
可以说HAL 库就是用来取代之前的标准外设库的。相比标准外设库,STM32Cube HAL 库表现出更高的抽象整合水平,HAL API 集中关注各外设的公共函数功能,这样便于定义一套通用的用户友好的API函数接口,从而可以轻松实现从一个STM32产品移植到另一个不同的STM32系列产品。HAL库是ST未来主推的库,从前年开始ST新出的芯片已经没有STD库了,比如 F7 系列。目前,HAL库已经支持STM32全线产品。" c0 q9 Q7 Z. w
6 e/ s2 @& I# H; O! ?
使用HAL库编程,最好尽量符合HAL库编程的整体架构。
# \4 j" r* ^8 }$ i; E LL 库
4 l" `. Z# m/ w; V) S LL库(Low Layer)是 ST 最近新增的库,与 HAL 库捆绑发布,文档也是和 HAL 库文档在一起的,比如:在STM32F3x 的 HAL 库说明文档中,ST 新增了LL库这一章节,但是在 F2x 的HAL文档中就没有。
4 a t; e3 w5 k( q, C/ J LL 库更接近硬件层,对需要复杂上层协议栈的外设不适用,直接操作寄存器。其支持所有外设。使用方法: - 独立使用,该库完全独立实现,可以完全抛开 HAL 库,只用LL库编程完成。在使用STM32CubeMX生成项目时,直接选LL库即可。如果使用了复杂的外设,例如 USB,则会调用 HAL 库
- 混合使用,和 HAL 库结合使用。6 z) T" j) K' W7 |3 _
- b. h$ b, ?3 Y9 p) `
目前,CubeMX 在生成项目时,可以选择采用 LL 库。
LL 库文件的命名方式和 HAL 库基本相同。个人感觉,LL 库就是原来的标准外设库移植到 Cube下的新的实现,但是其实现方法更加高效、简洁。使用 LL 库编程和使用标准外设库的方式基本一样,但是确会得到比标准外设库更高的效率。
! N3 A3 Q w D& y% o d" R& R# _, x. |6 l1 x6 v; o2 q: M
|