STM32L0系列控制器低功耗模式详解 6 X/ n' Y9 v8 t/ E! S
: G* |2 S8 a2 i; f意法半导体(STMicroelectronics)的超低功耗MCU系列采用低泄漏技术和优化设计,以实现出色的低电流消耗,使其非常适合电池供电和能量收集应用。为了充分利用这些器件的低功耗功能,有必要知道可用的低功耗模式,如何配置它们以及最适合哪些任务。本文概述了STM32L053C8 MCU上的低功耗模式。但是,由于该系列的低功耗模式相同,因此可以使用任何STM32L0器件。 STM32L1系列和STM32L4系列还包括在超低功耗系列中。这些器件是性能更高的产品,具有更高级的内核,更多的内存和更多的外围设备。它们具有与L0系列相同的低功耗模式(对于L4系列,还具有一些其他功能),因此,本文也是从了解L4系列的好入门。图1摘自ST的宣传册之一,简要总结了L0、L1和L4系列的功能和优点。
( j# f6 e$ M) E9 B& w& ?# c图1:STM32超低功耗产品系列的比较 2 m; }- Q, g' ~7 p. u' }3 x9 d
当使用ST的MCU进行任何工作时,应该有两个可用的文档。首先是参考手册,对于STM32L053C8,则是STM32L0x3参考手册。本文档包含有关STM32L0x3系列的详细信息,即如何使用存储器和外设集。有关产品线中特定设备的更多详细信息,例如引脚映射、电气特性和封装信息,应使用数据表作为参考。就低功耗模式而言,参考手册将明确详细说明如何进入和退出它们,而数据手册将专门定义外围设备的可用性、可能的唤醒源和电流消耗估算。( w) _4 L. M* I0 y. s4 p
! l. l8 {* M+ o, E, e
背景介绍2 x. C8 O+ } O% t+ ^2 H- D
F- ?# g+ E5 J" n* n( N# a6 I+ Y" \0 [ T( C, p8 o& H$ d z/ r
STM32L0基于Cortex-M0 +内核,这意味着其低功耗功能取决于该内核的电源管理功能。可以使用系统控制块中的系统控制寄存器(SCR)来配置这些功能。不幸的是,参考手册或数据表中都没有记录内核寄存器。 ST则为那些寻求有关Cortex-M0 +的简洁文档的人员提供了STM32L0系列Cortex-M0 +编程手册。有关Cortex-M0、M0 +和M1内核的完整文档,可以在《 ARMv6-M体系结构参考手册》中找到。这两个文档都有一个关于电源管理的部分,这是开始本主题的好地方。
( Q1 K4 Q1 d8 @( e* C图2:SCR寄存器位 v- g8 x& F- l5 O. P- u
) d9 X9 Y. a( A* l3 F5 Y
如图2所示,SCR由三位组成:SEVONPEND、SLEEPONEXIT和SLEEPDEEP。 SEVONPEND(发送事件在待命状态)位允许中断进入待命状态以触发唤醒事件。请注意,如果未在NVIC中启用这些中断,则仍会产生唤醒事件,但不会输入ISR。有关未决中断,使能中断或一般而言NVIC的更多信息,请参见前述Cortex-M0 +手册中的“嵌套向量中断控制器”部分。 SLEEPONEXIT位提供了一个选项,可以在异常恢复后使处理器继续执行程序之前将处理器置于低功耗模式。对于仅需要唤醒服务中断的应用程序来说,这是理想的选择。最后,SLEEPDEEP位允许进入深度睡眠状态,而不是常规睡眠状态。利用Cortex-M0 +内核的芯片制造商可以确定这些状态下设备的确切性能。睡眠状态用作睡眠模式和低功耗睡眠模式的基础,而深度睡眠状态用作停止模式和待机模式的基础。
: m4 v( i, _$ X# B$ f ~2 n
. n( s( }0 J/ n; O0 e6 u0 R) ?: y' W+ n; N
有三种方法可以在Cortex-M0 +上进入低功耗模式。第一种是使用WFI(等待中断)指令。顾名思义,如果设备由于该指令而进入低功耗模式,则中断(在NVIC中启用)能够唤醒设备。进入低功耗模式的第二种方法是执行WFE(等待事件)指令。这与WFI指令非常相似,但具有更大的灵活性。不仅可以通过扩展中断和事件控制器(EXTI)中配置的事件唤醒设备,还可以通过NVIC中禁用的中断(只要它们在相应的外设控制寄存器中启用)唤醒。已经提到了进入低功耗模式的第三种方法。通过将SCR中的SLEEPONEXIT位置1,异常返回将使设备进入低功耗模式,就像执行WFI指令一样。请注意,在所有这些情况下,仅当没有中断或事件挂起时才进入低功耗模式。由于不能保证WFI和WFE会中止程序执行,因此通常将它们称为“提示指令”。% r, |7 J1 p7 z% u( k
! s* v; v3 U, M1 y+ i& {值得一提的最后一个内核寄存器是PRIMASK寄存器。它仅包含一个可配置位PM(可优先中断屏蔽),如果将其设置为1,它将禁用所有具有可配置优先级的中断。如果首先需要将系统恢复到工作状态,这不仅可以用于执行原子操作,而且可以延迟执行ISR。在详细说明停止模式的部分中将提供一个示例。0 v6 r- A% }7 N; W
v' b! `: p! J( _为了使程序员在开发C应用程序时轻松访问WFI和WFE指令,CMSIS-CORE标准提供了__WFI()和__WFE()函数。以下各节中的所有示例函数都使用__WFI()执行WFI指令并进入低功耗模式。另外,CMSIS不会直接提供对PRIMASK寄存器的访问,而是实现__disable_irq()和__enable_irq()函数,以便分别设置和清除PM位。为了检查PM位的状态,__ get_PRIMASK()函数将返回其当前状态。大多数IDE使将CMSIS驱动程序添加到项目变得非常简单。例如,在Keil中,请确保在包安装程序中安装了ARM :: CMSIS,并在创建新项目时在运行时环境管理器中仅检查“ CORE”包(在CMSIS组件)。& R! O: z1 s5 B3 N% \2 e) U0 M& F
, l0 ^# Q/ s+ l+ {& o低功耗模式(Low-Power)( R# v" X* z# S% J
4 N* y8 H' C# G0 A$ s* x7 ?) }4 e9 I
$ V2 w, y; d9 s) C6 c) e4 [STM32L0器件实现了五种低功耗模式:低功耗运行模式、睡眠模式、低功耗睡眠模式、停止模式和待机模式。这些模式之间的差异可以用功耗,性能、唤醒时间和唤醒源来描述。如果对于这些参数中的每一个,将模式按从最佳(1)到最差(5)的顺序进行排序,则可以清楚地了解哪些取舍。一般而言,随着功耗的下降;性能下降,唤醒时间增加,唤醒源数量减少。表1总结了低功耗模式的排名。作为、示例,请考虑低功耗运行模式。它具有最佳的性能、最多的唤醒源,第二快的唤醒时间和第四低的电流消耗。
- ?. b$ w$ q0 o
* K( R8 n8 d. h" v8 n0 `表1:基于各种工作参数的STM32L0低功耗模式的排列
4 w/ Q" g+ G. M; j0 Y在本节中,将很清楚如何得出这些排名。但是,重要的是要及早意识到它们仅在一般意义上是正确的。例如,停止模式完全有可能比低功耗睡眠模式消耗更多电流,这取决于它们的配置以及启用/禁用的外设。但是通常情况并非如此,因为停止模式对设备功能的限制远比低功耗睡眠模式所限制,以节省更多功率。
! I! g' A+ @3 T3 U' E2 M {: p4 A0 ?& g# X
+ q8 G/ s4 u. ^# [0 s低功耗运行模式(Low-Power Run)! C4 s1 ]6 E/ L' A
& \5 E, ^) w/ q8 ^
3 `9 `, M9 s$ B D. ^ ?
将其作为低功耗模式推销是相当诱人的,因为它节省能耗的主要方法是要求较低的系统时钟频率。将任何微控制器的时钟速度降低到千赫兹范围将极大地降低电流消耗,使其与普通睡眠模式相比更具竞争力。但是,通常不这样做的原因是,从长远来看,性能的降低以及静态电流消耗(不取决于时钟频率)会消耗更多的能量。取决于应用,即正在使用哪种睡眠模式或设备唤醒的频率,在较短的时间段内消耗更多的电流而不是在较长的时间段内消耗较少的电流可能更有效。 ST之所以可以将其分类为低功耗模式,是因为它们提供了将内部稳压器置于低功耗状态的能力。这将减少设备消耗的静态电流,从而将其对性能与总电流消耗之间的折衷影响降至最低。! H7 r0 ~3 g+ h r- C
. l0 a! J2 o" ~4 V) ?. F. `9 S+ V* y! U0 q: z
为了将调节器切换到低功耗模式,必须满足两个条件。首先,调节器电压(VCORE)必须在2范围内。幸运的是,根据PWR_CR寄存器文档,这是调节器的默认配置。因此,除非利用器件的动态电压缩放功能,否则无需担心此先决条件。第二个条件是系统频率不超过fMSI范围1。根据MSIRANGE位的描述(在RCC_ICSCR寄存器中),它对应于大约131.072 kHz的频率。在这种速度和功率水平下,USB,ADC和TSC(触摸感应控制器)外围设备不可用。更改系统频率后,必须重新初始化之前在运行模式下初始化的所有与频率相关的外围设备(USART、计时器等),以便继续正常运行。. `; N* G' O2 C ]& K. h6 B5 `5 i& i0 A
' U! U1 n `4 a! t
与其他低功耗模式不同,CPU不会在低功耗运行模式下停止。这意味着它不是通过前面讨论的WFI / WFE指令输入的,而是通过设置PWR_CR寄存器中的LPSDSR(低功耗睡眠-深度/睡眠/低功耗运行)和LPRUN(低功耗运行)位来输入的。 。请注意,必须在设置LPRUN之前设置LPSDSR,在清除LPSDSR之前必须清除LPRUN,并且在进入任何其他低功耗模式之前应清除LPRUN。由于程序在低功耗运行模式下继续执行,因此该设备被软件“唤醒”,而不是局限于有限的一组中断或事件。只需清除LPRUN位并使系统频率恢复到全速,即可使系统返回运行模式。清单1显示了使用参考手册中概述的步骤进入低功耗运行模式的整个过程。清单2演示了当设备不再需要处于低功耗运行模式时如何重新进入运行模式。
! r. D: ^) O* Q) J( g2 Y( x
* { x. Q$ H' L* p! n清单1:进入低功耗运行模式的示例
1 [1 j$ {! y' n: w- void enter_LPRun( void ); t) g5 |2 \, V, l9 | z6 z
- {
1 H6 a, L# ?$ f: h4 ]4 C. H - /* 1. Each digital IP clock must be enabled or disabled by using the! L- _- \2 m: X4 g8 m, ]" ^% S0 P
- RCC_APBxENR and RCC_AHBENR registers */6 t2 }) t, k$ j. _: a+ C/ U: g
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;0 s7 d% ^4 |! S, K- a: r
- /* 2. The frequency of the system clock must be decreased to not exceed the
8 J A' E8 w4 E$ e! K& q/ m - frequency of f_MSI range1. */
6 R$ p( S% D" V! x& B7 U - Config_SysClk_MSI_131();
( Z, u! N4 o! |8 H" m) W - // Reinitialize peripherals dependent on clock speed
4 c; w0 q& Q0 _# r {2 H) | - USART1_Init();
, d" P4 y+ o0 V+ ]" z2 L - SysTick_Init( 0.001 );( `& `' u6 S, N2 K' w7 _5 ^% Z
- I2C1_Init();5 R: ~. @2 R! H+ z, j
- /* 3. The regulator is forced in low-power mode by software M( Z4 @/ Q2 b: ?, U8 S( }0 m
- (LPRUN and LPSDSR bits set ) */4 Q% I2 Y a0 y f3 g6 \! e
- PWR->CR &= ~PWR_CR_LPRUN; // Be sure LPRUN is cleared!
$ o# r* L0 D: p. \4 i -
) t, d4 P7 @4 y: B( W4 v% P - PWR->CR |= PWR_CR_LPSDSR; // must be set before LPRUN4 |2 l7 p. b% N p7 C
- PWR->CR |= PWR_CR_LPRUN; // enter low power run mode9 ^6 Y) {0 c8 k% B9 t$ o
- }
复制代码 清单2:进入运行模式的示例) \; [ h3 ^5 v- V
- void enter_Run( void )
7 P: t: W& [ c" q* Q: u7 K - {
A: L8 z: n) a, v - /* Enable Clocks */) N; T- ]0 o" S. g6 z/ s
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;
# ~; {( H5 H/ f0 R9 p$ x
4 S+ t$ x( a: l# G a- /* Force the regulator into main mode */
. W, W. T( }3 j. A4 d* [ - // Reset LPRUN bit- s( Y' l# @9 E7 [8 \$ C
- PWR->CR &= ~( PWR_CR_LPRUN );; r/ Q/ F) N3 ~- m8 ^/ T9 c
- // LPSDSR can be reset only when LPRUN bit = 0;8 {: [# ~( S" W C2 S. X, a( T8 |
- PWR->CR &= ~( PWR_CR_LPSDSR );* U2 p3 @' x/ u# o/ E0 Q. j
- /* Set HSI16 oscillator as system clock */0 o. W V1 R( d
- Config_SysClk_HSI16();9 _7 C6 V& S9 p
- // Reinitialize peripherals dependent on clock speed) H2 h2 ~6 @6 Z6 ?
- USART1_Init();4 ] i+ P& [1 B+ b) f- }
- SysTick_Init( 0.001 );
# K+ J$ l6 s, m3 s; c. @ - I2C1_Init();' @' i. d) [- E$ i1 W2 b$ h
- }
复制代码 睡眠模式(Sleep Mode)
. Q6 P2 M) h7 A; F& d* M. E8 @0 G8 p: D7 E( z
# ?$ V4 t3 C; K( j# \6 q
睡眠模式是低功耗模式中最简单的一种,它以最省电的方式提供最短的唤醒时间。数据手册指出,在禁用所有外设且系统频率为16 MHz的情况下,将消耗约1 mA的电流。这远高于其他低功耗模式,后者可以实现微安或什至纳安的数量级。但是,唤醒时间几乎是最具竞争力的低功耗模式的十倍。表2显示了设备从每种低功耗模式唤醒并进入运行模式所花费的时间。唤醒时间的值取自数据表的表4。
- k1 k1 k7 q/ S& K0 ^ T4 ~7 h
8 P, B t7 P# m5 H( k8 b
: S3 a) N: x* v% J表2:每种低功耗模式的唤醒到运行模式时间
/ _1 Q# S$ O9 E5 M在休眠模式下,所有外设继续运行时,仅内核停止运行。由于不必降低系统频率并且所有设备的外围设备都可以使用,因此这使进入睡眠模式几乎毫不费力。同样,退出休眠模式非常容易,因为在运行模式下可用的任何中断或事件都可以唤醒设备并以极低的延迟进行服务。因此,几乎在CPU处于自旋锁等待事件发生的任何情况下都可以使用睡眠模式。用户无需进入繁忙等待循环,只需执行WFI或WFE(取决于唤醒方法)即可暂停执行并节省功耗,直到再次需要内核为止。这是因为SCR默认情况下配置为睡眠模式,即SLEEPDEEP位被清除。对于只需要CPU处理中断的应用,将SLEEPONEXIT位置1并在处理完中断后始终进入睡眠模式更为有意义,这与恢复程序执行相反。' N$ `0 N' b' `0 N6 z
2 Q, T" M* d5 p+ W9 j0 {. q
清单3是可用于进入睡眠模式的函数示例。因为此函数取自使用多个低功耗模式的程序,所以第一条语句可确保清除SLEEPDEEP位,以避免意外行为。同样,为了避免唤醒延迟,闪存访问控制寄存器配置为在设备处于休眠模式时使非易失性存储器保持空闲状态。在低功耗睡眠模式部分中将进一步讨论如何停止闪存接口时钟。
0 }; l8 S; A7 Y4 e/ y5 G
' D1 m+ H' P. N8 _& l3 d' H% a' j! p/ G& |4 A% L0 T$ x& Y0 [
清单3:进入睡眠模式的示例
3 r7 | U7 o3 l" N# W' q( Z! j, S7 K- void enter_Sleep( void )1 V, k `# y; y* T0 S& A% v
- {0 G( {5 U0 n" H) H' C7 p0 r
- /* Configure low-power mode */
~1 _4 h# z) \ - SCB->SCR &= ~( SCB_SCR_SLEEPDEEP_Msk ); // low-power mode = sleep mode3 \* k" G& y3 X4 q
- SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; // reenter low-power mode after ISR0 q/ l2 |5 r& S! g4 m
- + P) S( n h) X: `( o3 H
- /* Ensure Flash memory stays on */
: q4 E# b K5 t0 G9 G% h5 E - FLASH->ACR &= ~FLASH_ACR_SLEEP_PD;4 O/ y% W5 B$ Y" i
- __WFI(); // enter low-power mode" |+ }, P( u2 a
- }
复制代码 低功耗睡眠模式(Low-Power Sleep Mode)
+ H: Z6 k H8 d6 t' m# Q, B: _
# O k, y# A) h) n0 A5 x: L, Y6 S
低功耗睡眠模式本质上是低功耗运行模式和睡眠模式的组合。不仅Cortex-M0 +内核停止了,而且调节器进入了低功耗模式,这意味着必须满足与低功耗运行模式相同的条件。回想一下,VCORE必须在范围2(默认配置)中,并且系统时钟频率必须降低到不超过fMSI范围1(131.072 kHz)。因此,在此模式下,USB,ADC和TSC外设不可用。此外,任何继续在低功耗睡眠模式下运行的频率相关外围设备都必须重新初始化,以便它们继续正常运行。
. z8 I& K, i: _, a4 z2 |3 i: l1 Q3 k- v3 X" }0 f2 v! ]
! D7 A8 G g9 M; \' A; C. S' U( z
与低功耗运行模式不同,LPRUN位不用于使稳压器进入低功耗模式。一旦系统频率降低,就应将LPSDSR位置1,并遵循进入睡眠模式的相同步骤。即,确保清除SLEEPDEEP位并执行WFI指令,WFE指令,或者将SLEEPONEXIT位置1,然后等待异常返回。当器件进入低功耗模式时,LPSDSR位将自动将调节器置于低功耗状态。当器件在唤醒事件后退出低功耗模式时,将进入稳压器全功率运行的运行模式。
1 S) m7 S$ d I) S3 O; F$ p/ ]$ t, D7 b# A1 y8 [
A6 s( C9 C6 g# e$ s参考手册在“低功耗睡眠模式”部分中提到了关闭闪存的选项。当器件进入睡眠模式或低功耗睡眠模式时,将FLASH_ACR寄存器中的SLEEP_PD(SLEEP掉电)位置1将使非易失性存储器进入掉电模式。虽然这确实增加了唤醒等待时间,但功耗却降低了约12 µA(数据表中的表34),这可能因应用而异。唤醒时间的增加大概是因为在参考手册的“睡眠模式”部分中没有提及此选项的原因(即使它确实在睡眠模式下也起作用)。如果使用睡眠模式的应用程序不需要它提供的惊人的快速唤醒时间,则应该改为使用低功耗睡眠模式。清单4显示了一个示例功能,该功能用于按照参考手册中列出的步骤进入低功耗睡眠模式。* G9 B8 k0 V* u/ N( \
t; s2 \9 l6 M% e7 A% b" @4 m清单4:进入低功耗睡眠模式的示例
4 a& i8 a+ g" j$ i- void enter_LPSleep( void )' f% j3 I% [" e! |; o
- {
* c8 q' [/ ^: G% d; } - /* 1. The Flash memory can be switched off by using the control bits% {' \1 B/ D: m+ b% Q8 u
- (SLEEP_PD in the FLASH_ACR register). This reduces power consumption$ v/ v& U2 v; D( S( a7 ^2 W
- but increases the wake-up time. */
! o2 H+ \# o. E - FLASH->ACR |= FLASH_ACR_SLEEP_PD;; o6 ~" ^: ?. K. q
- /* 2. Each digital IP clock must be enabled or disabled by using the
* z/ A3 ?2 a2 V% }" m( b+ |+ X - RCC_APBxENR and RCC_AHBENR registers */% F2 x9 |- G( S# _; U) y
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;
% c/ S. I* a% b+ |1 s* N+ q: A - /* 3. The frequency of the system clock must be decreased to not exceed the& r$ R+ j8 s- ^8 ^* A. ]* Y
- frequency of f_MSI range1. */0 J+ i0 G3 I& h, Q5 _" [+ P1 J+ f$ r
- // Set MSI 131.072 kHz as system clock
3 a: n- b; S% o. S - Config_SysClk_MSI_131();
: u$ ^* J" c5 a - // Reinitialize peripherals dependent on clock speed
: R* v( K9 U4 V1 l - USART1_Init();
( c( s+ E! w9 @9 h - SysTick_Init( 0.001 );9 t8 c6 E* D& s
- I2C1_Init();( q/ }1 H) m. a e# h5 ?
- /* 4. The regulator is forced in low-power mode by software
7 }) {; E5 k7 T" f. {: h8 e8 R4 j - (LPSDSR bits set ) */
8 F/ r s( h- y* M- R5 s - PWR->CR |= PWR_CR_LPSDSR; // voltage regulator in low-power mode during sleep
( L) H' A3 K7 X0 ^4 E6 u3 D3 u' x - /* 5. Follow the steps described in Section 6.3.5: Entering low-power mode */5 G; p+ c" c8 H4 X! O- O3 Q
- SCB->SCR &= ~( SCB_SCR_SLEEPDEEP_Msk ); // low-power mode = sleep mode7 j3 |. p* ?) p2 B0 y* j$ I
- SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; // reenter low-power mode after ISR) l% c( u: ` N% t# d( E& v
- __WFI(); // enter low-power mode. a: x6 B. O& n$ J1 Y4 V: O7 N3 _
- }
复制代码 停止模式(Stop Mode)) B" ?+ b8 J& M7 B% S
' a8 D* B9 I2 \8 n0 O2 `/ V1 v L
+ ]! ^. U: m5 D停止模式可以说是STM32L0系列中最复杂的低功耗模式,它有可能在保持SRAM和寄存器内容的同时实现纳安量级的电流消耗。但是,如果唤醒时间更重要,则可以忽略许多节能选项,以实现与低功耗运行模式相同的延迟。更为复杂的问题是可用的唤醒源数量有限,勘误表中多次提及“停止”模式以及增加的调试复杂性。但是,对于那些希望使用最少电量而又不必在唤醒时重新初始化系统的用户来说,停止模式可能是最佳选择。
0 R) W" S& ]6 K& H! C. Y' V! S" X0 b* G6 U' s [( Y- v8 _
1 z* |$ G/ q) ]; A0 k) t在停止模式下,内核被停止,并且只有有限容量的LSE,LSI和HSI能够运行的振荡器。低速时钟允许RTC和IWDG继续运行并唤醒设备。 HSI可以为能够在停止模式下运行的外围设备提供有限的功能。例如,通过在需要时唤醒HSI,USART和I2C仍能够在停止模式下接收数据。 HSI将仅提供请求它的外围设备,并且在不再需要它时将自动被禁用。有关在停止模式下可用的所有外设的完整列表以及可用的唤醒源,请参见数据表中的表4。请注意,由于核心时钟已停止,因此一旦进入停止模式,调试连接将无法维持。但是,根据参考手册,将DBGMCU_CR寄存器中的DBG_STOP位置1将允许在停止模式下进行调试。
! X7 v" E6 R; s, A: l6 r' f' n; v6 n5 Q
为了进入停止模式,必须将SLEEPDEEP位置1,因为停止模式和待机模式都是由Cortex-M0 +内核提供的深度睡眠状态的实现。清除PWR_CR寄存器中的PDDS(掉电DeepSleep)位是在待机模式下选择停止模式的方式。另外,有必要确保清除PWR_CSR寄存器中的WUF(唤醒标志)位。不幸的是,该位不能由软件修改,必须通过向PWR_CR寄存器的CWUF(清除唤醒标志)位写入1来清除。这将在2个系统时钟周期后清除WUF。一旦满足这些条件,用户只需执行WFI指令,WFE指令或将SLEEPONEXIT位置1,然后等待异常返回。请注意,默认情况下,从停止模式唤醒时,设备会选择MSI振荡器作为系统时钟。通过在进入停止模式之前将RCC_CFGR寄存器中的STOPWUCK(停止唤醒时钟)位设置为1,将选择HSI16振荡器作为系统时钟。清单5显示了一个示例函数,它将使用此最低限度的配置进入Stop模式。它还显示了如何启用能够唤醒设备的外部中断。0 U8 H) H+ `# W* A
' m! ^ Z2 s5 K. E5 D: l* A清单5:进入停止模式的简单示例
, i% r4 a+ p. B6 a `- void enter_Stop( void )" ^. ~4 @7 b9 R) z, Z" v
- { - K* v% U/ Q4 R$ I
- /* Enable Clocks */2 t$ a9 A( k1 H- j' n7 B
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;
/ b& Y2 h0 C# a; d, b" b3 y9 H - RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
# o2 F' k7 N u5 u9 @ - 4 J6 P& W a, R
- /* Configure PA0 as External Interrupt */" `; s+ z4 u1 A/ ~; }1 t: }" b
- GPIOA->MODER &= ~( GPIO_MODER_MODE0 ); // PA0 is in Input mode+ }2 @- d" k6 U3 p9 e
- EXTI->IMR |= EXTI_IMR_IM0; // interrupt request from line 0 not masked8 `& H1 J2 w) ]6 L- m' x- J
- EXTI->RTSR |= EXTI_RTSR_TR0; // rising trigger enabled for input line 0 u% E3 q7 D! q( Y1 f
-
8 {. I4 r! @$ ^: M- O - // Enable interrupt in the NVIC0 q, O( J6 s2 ~+ p N$ }- w3 ^" i
- NVIC_EnableIRQ( EXTI0_1_IRQn );7 I8 @5 H3 M. |9 T
- NVIC_SetPriority( EXTI0_1_IRQn, BTN_INT_PRIO );
7 H$ Z. E$ I7 Q* W - . z' s! A( v5 @/ e
- /* Prepare to enter stop mode */
9 ?# G% Z3 D, l9 W$ C' Z - PWR->CR |= PWR_CR_CWUF; // clear the WUF flag after 2 clock cycles- b, m9 q* w" i
- PWR->CR &= ~( PWR_CR_PDDS ); // Enter stop mode when the CPU enters deepsleep
9 i& e: W+ P4 e" \$ y - RCC->CFGR |= RCC_CFGR_STOPWUCK; // HSI16 oscillator is wake-up from stop clock
7 ^0 R$ p! @& D; t$ A/ d - SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // low-power mode = stop mode& R+ c7 E0 e- e- L
- __WFI(); // enter low-power mode
2 ]( o7 a" C7 Q1 v1 Q$ y) c6 E - }
复制代码 如果希望节省更多的电量,而唤醒时间就不再那么重要了,则可以在进入停止模式之前进行其他配置。最简单的方法是通过将PWR_CR寄存器中的LPSDSR位置1使稳压器进入低功耗模式。在同一寄存器中,如果任何模拟外设都没有使用VREFINT(内部参考电压),也可以将ULP(超低功耗模式)位置1以将其禁用。此外,如果唤醒后不需要立即使用VREFINT,将FWU(快速唤醒)位置1不会增加设置ULP可能引起的额外唤醒延迟。( l* d% G( Q0 y: e; @, K4 B! D0 `
) ^2 ^& Z! f+ ^. z
( T9 d/ E' a0 t
前述更改将显着降低电流消耗,但该设备可能仍在以微安为单位订购。为了进入纳安范围,必须将所有GPIO引脚置于模拟模式。根据参考手册第9.3.12节,当I / O引脚配置为模拟引脚时,施密特触发器输入被禁用,每个引脚的功耗为零。但是,这样做意味着必须将每个端口的GPIOx_MODER寄存器保存,然后再将每个引脚切换到模拟模式。这样,设备唤醒后,每个引脚都可以恢复到其先前的模式。另外,为了避免意外错误,在保存和恢复过程中都应禁用中断。
$ \: v# x! |! m7 H |
4 U% h. W1 m7 Y1 q
: ^( _* ?/ z; G% V清单6中的功能建立在清单5中的基本功能的基础上。不仅将调节器置于低功耗模式并且VREFINT已关闭,而且在进入停止模式之前还保存了I / O上下文。由于在执行WFI时即禁用了中断,即PM位置1,因此外部中断将唤醒设备,但不会输入其ISR。程序从WFI指令继续执行,从而允许立即恢复上下文。重新启用中断后,由于中断仍处于挂起状态,因此将输入外部中断的ISR。
) p0 `5 x5 u5 \( K1 x+ b% b2 S3 W" \
" s c0 \! d. r0 W; x2 N清单6:进入停止模式的高级示例
! f- f; W" c; }& |4 G; }- void enter_Stop( void ), D5 |" e. ? \& q2 C0 G6 l" o
- { m- V/ d5 R( W% M8 _! G& b2 Q; y5 |
- /* Enable Clocks */0 E8 Y Q% V, e
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;, Q4 H2 H. ~% r- u! X' [
- RCC->IOPENR |= RCC_IOPENR_GPIOAEN;- [2 c/ E ~; o% Z7 \
-
% P0 G0 `( p+ m" q, L - /* Configure PA0 as External Interrupt */& g. x! z% D o5 g7 Q7 c& d
- GPIOA->MODER &= ~( GPIO_MODER_MODE0 ); // PA0 is in Input mode
! b' g' P% |) z+ e9 Z- ? - EXTI->IMR |= EXTI_IMR_IM0; // interrupt request from line 0 not masked7 l; Q: j I' C9 ]7 k4 z7 U1 y( g
- EXTI->RTSR |= EXTI_RTSR_TR0; // rising trigger enabled for input line 07 k/ A0 K2 K( B: ]
-
: R8 |9 `7 l6 |$ y! u; Z - // Enable interrupt in the NVIC
8 a3 [% E( J1 v. X( K5 [* a - NVIC_EnableIRQ( EXTI0_1_IRQn );
* _2 K) C) t. R3 x - NVIC_SetPriority( EXTI0_1_IRQn, BTN_INT_PRIO );
+ m- z: j0 q4 X+ A6 v -
! [3 m4 n8 C9 j. b - /* Prepare to enter stop mode */
/ H9 {! }% ^+ m* @- ? - PWR->CR |= PWR_CR_CWUF; // clear the WUF flag after 2 clock cycles
' C Z3 s4 j* D- I7 F4 J - PWR->CR &= ~( PWR_CR_PDDS ); // Enter stop mode when the CPU enters deepsleep/ _% f: ?; z: ]) n: q0 d
- // V_REFINT startup time ignored | V_REFINT off in LP mode | regulator in LP mode6 {0 `9 }" U( B9 X
- PWR->CR |= PWR_CR_FWU | PWR_CR_ULP | PWR_CR_LPSDSR;' d! c5 y& |$ f+ v+ S
- RCC->CFGR |= RCC_CFGR_STOPWUCK; // HSI16 oscillator is wake-up from stop clock
/ G0 o3 b" l5 ~3 A) s - SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // low-power mode = stop mode1 i7 @ u* ^# Q& r/ E; Q2 [' M- [% Z
-
5 w1 U) R5 N8 O8 f, Q$ w- S - __disable_irq();
: M3 D$ k/ b9 u8 E7 W3 O& b7 P2 a - , v' W; |% C" f# F; [
- Idd_SaveContext();
1 o; E9 X2 r1 P: @5 c. ` - I2C1->CR1 &= ~I2C_CR1_PE; // Address issue 2.5.1 in Errata
( q9 p( @6 q& B- [5 `5 l - __WFI(); // enter low-power mode5 m3 @# l, z j( x
- # O6 K# a# n$ Z5 K# h& m" _
- I2C1->CR1 |= I2C_CR1_PE;4 k- J0 j2 ^& e% q2 U) Y: J( J' b
- Idd_RestoreContext();
) a. x$ r" U, ] -
9 @( k9 e4 C1 u - __enable_irq(); // <-- go to isr' P9 Y3 A1 V8 l. k$ S' Z& ]4 q
- }
复制代码 清单5和清单6均使用来自PA0引脚的外部中断来唤醒设备。这是因为外部中断是由EXTI控制的,并且除了系统复位以外,只有它可以使设备退出停止模式。简而言之,EXTI管理着30条内部和外部线路,能够产生中断和事件。参考手册中的表52指定了每条线路的线路来源以及它们是可配置线路还是直接线路。在上述示例中,默认情况下,EXTI行0映射到PA0,因此不必自行配置行。所有要做的就是使该线路成为中断源,选择如何触发中断,并在NVIC中启用相应的中断。如果使用WFE指令进入了停止模式,则该行将在事件模式下启用。
. Z1 b0 }7 W# e5 K, o+ M4 w0 L' u7 T8 ^2 E" b
表3总结了STM32L053x6 / 8勘误表中记录的停止模式的局限性。显然,无论使用什么版本的芯片,程序员都应该解决一些问题,以避免出现意外错误。清单6中的函数实现了针对未配置I2C外设以将设备从停止模式唤醒而导致的问题的建议解决方法。勘误表中的2.5.1节解释说,在进入停止模式之前禁用I2C外设并在唤醒后立即重新启用它可以避免任何错误。幸运的是,该解决方法可以与保存和还原I / O上下文一起完成。
" }6 t9 C% L% m( E, U/ [( Y; i
, a0 a6 m9 K r待机模式(Standby Mode)
4 p; p# r" \! f; s6 u$ r- O0 ^6 g3 X- ]7 G8 R
c! U& w. ~. D8 n与停止模式不同,进入待机模式非常简单,因为用户的选项更少。唯一可用的振荡器是LSI和LSE,唯一可以工作的外设是RTC和IWDG,电压调节器被完全禁用,并且所有I / O引脚都设置为高阻抗(因此节省上下文毫无意义)。用户进入待机模式所需要做的全部工作就是将SLEEPDEEP位置1,将PDDS位置1,并确保通过向CWUF位写入1来清除WFU位。然后,在异常返回之前执行WFI指令,WFE指令或设置SLEEPONEXIT将导致设备进入此低功耗模式。退出待机模式的选项也更少。只有唤醒引脚(PA0或PC13)上的上升沿,RTC唤醒事件之一或IWDG复位才会唤醒设备。在进入待机模式之前,必须配置选择的方法并清除相应的唤醒标志。请注意,STM32L053C8芯片仅具有两个唤醒引脚,而参考手册和数据表中通常会提到仅在引脚数较高的封装中才可使用的第三个唤醒引脚。
- z, a6 w. P3 `" h$ b. E/ Y7 f* h8 A. p) J5 O v f, P
待机模式的最大问题是它不保留SRAM或寄存器(RTC寄存器,RTC备份寄存器和待机电路除外)的内容。从待机模式唤醒后,程序执行将以与发生复位相同的方式重新开始。为了确定系统是否从待机模式中唤醒,只要输入main()函数,就可以检查PWR_CSR寄存器中的SBF(待机标志)位。如果该位置1,则该设备先前处于待机模式,并且应设置CSBF(清除待机标志)以清除SBF。然后,用户知道是否应该在首次运行时初始化系统,或者是否应该将系统还原到以前的状态。8 }" H- ]# r& `! D' L
" r! h6 [2 ]5 W& J
- v) G- c( q* o F" ~请注意,表2中的待机模式具有最长的唤醒时间。此估算不包括重新初始化系统和恢复程序执行所需的时间。这种增加的等待时间不仅使对唤醒事件的立即响应几乎不可能,而且会严重限制待机模式的节能功能。为了将平均消耗电流保持在“停止”模式之下,该设备将必须处于“待机”模式很长时间。时间长短取决于唤醒/重新初始化过程中消耗了多少电流。清单7显示了一个示例函数,该函数可用于进入待机模式,在该模式下,任一唤醒引脚都将唤醒设备。# C+ K* K" i9 N& U
0 E/ ]. b: ]+ G8 D: M$ e
) q& g6 B& A0 }/ g7 U( g, l) a
* N; L. E% s5 j. d
3 ]- @5 Q! c5 f- h
清单7:进入待机模式的示例
( Z( o9 f9 n& l7 B3 c4 d- void enter_Standby( void )
- G2 n- X$ Z2 B - {+ i/ i% F! V; X) h" |
- /* Enable Clocks */1 J* y* l. B% ~' k1 o4 K
- RCC->APB1ENR |= RCC_APB1ENR_PWREN;8 X$ ?, d7 u. p) x' y
-
* g6 C1 o- ^& P( [8 M! l# W" K - /* Prepare for Standby */
; M% [& {8 v& \% Y4 E/ n2 z - // if WKUP pins are already high, the WUF bit will be set
" c$ V- K+ t: J- O; M' G3 A - PWR->CSR |= PWR_CSR_EWUP1 | PWR_CSR_EWUP2;
2 |3 _* m h$ Z3 Q( z% H - - ?- X* q6 h+ ?6 }& b/ r
- PWR->CR |= PWR_CR_CWUF; // clear the WUF flag after 2 clock cycles6 ?7 A3 Q9 z7 Z3 X5 u0 i+ E
- PWR->CR |= PWR_CR_ULP; // V_{REFINT} is off in low-power mode- @9 `) g" T1 L
- PWR->CR |= PWR_CR_PDDS; // Enter Standby mode when the CPU enters deepsleep0 H0 B, v. ~, \% p' d `
- 8 c+ Z) F5 g' ?; K- z9 P; H
- SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // low-power mode = stop mode) N0 H5 o6 q d
- SCB->SCR |= SCB_SCR_SLEEPONEXIT_Msk; // reenter low-power mode after ISR
- k, u# p0 m/ ]( k - __WFI(); // enter low-power mode
6 O+ ]$ T3 o5 B4 D* Y4 J - }
复制代码 结论
% {$ G/ j% w' [( x' I
. D& J( e' r! K+ P/ p
2 [ u; C3 ^* L3 I7 o适用于超低功率应用,例如燃气/水表、可穿戴设备或物联网传感器,STM32L系列微控制器具有许多低功耗模式,允许用户仔细地在性能与功耗之间取得平衡。尤其是,STM32L0系列利用了最节能的ARM处理器(Cortex-M0 +),并提供了五种低功耗模式,以适应大多数入门级应用。
' N+ ?+ p' O1 |1 l% c' z9 h0 V$ Z
- T7 n, e( w* y/ U) K( j ~5 u
2 d+ O5 c; T8 ~
4 m! o1 m" g' S+ @) _低功耗运行模式可产生最佳性能,同时仍比睡眠模式消耗更少的电流。因为CPU一直在运行,所以唤醒器件的决定是由软件决定的,从而在这方面提供了最大的灵活性。不幸的是,使稳压器处于低功耗模式会导致唤醒延迟,这对于许多实时应用而言太大了。这是睡眠模式真正出类拔萃的地方,它具有0.36 µs的唤醒时间,这是因为在内核被禁用的情况下允许所有外设全速运行。但是,这也使它成为最耗电的低功耗模式,外围设备性能和全套硬件唤醒源对此几乎没有补偿。低功耗睡眠模式使用与低功耗运行模式相同的方法,以将电流消耗降低到与停止模式相当的水平,而不会限制唤醒源的数量。但是,如果足以使EXIT唤醒器件,则停止模式将提供最低的电流消耗,同时仍保留SRAM和寄存器内容。它还具有与低功耗运行模式相当的唤醒时间。最后,对于长时间不需要MCU的应用,待机模式可能是合适的。它使用最少的功耗,但却消耗了很少的唤醒源和最长的唤醒时间。
' Q8 s' d& g0 M
/ f2 T) o" X i) h# u) H5 s1 ?& U; z7 [% R6 y+ _. z
+ @, B7 W6 v6 `9 _1 b
' }! { o; ~/ `7 G: G- T1 D j
: S- ~8 y, |( C, ?4 I
3 \; J# ]9 w' G: W( i( Y
& w' @9 V$ K$ w. u( P
; J! ]7 Y% k0 } W% K$ [) g/ G8 y
7 a7 b' I1 v; i
. [/ Q) z1 E5 e" k, _ |
我按照文档DS111000的6.3.4节计算了Run Mode时功耗在100uA/MHz以上。* q6 C( @, d9 @( W6 N2 M
很疑惑76 μA/MHz在什么状态可以达到
这是否算是虚标?