36.1 初学者重要提示
使用LPTIM的好处是系统处于睡眠、停机状态依然可以正常工作(除了待机模式)。停机状态可以正常工作的关键是LSE,LSI时钟不会被关闭,同时也可以选择使用外部时钟源。
重点学习本章的2.9小节,对于LPTIM的认识起到至关重要的作用。
36.2 低功耗定时器基础知识
下面将低功耗定时器应用中要用到的基础知识做个介绍。
36.2.1 定时器的硬件框图
认识一个外设,最好的方式就是看它的框图,方便我们快速的了解定时器的基本功能,然后再看手册了解细节。
下面我们直接看最复杂的LPTIM1&LPTIM2框图:
通过这个框图,我们可以得到如下信息:
lptim_pclk接口
主要用于LPTIM的寄存器提供时钟,寄存器操作需要高速时钟,不能像LPTIM的其它部分一样使用LSI,LSE等低速时钟。
lptim_it接口
用于触发中断。
lptim_ker_ck接口
内核时钟,供lptim使用。lptim_ker_tim接入到CLKMUX双路选择器的一个输入端,另一个输入端是LPTIM_IN1或者LPTIM_IN2的输入。也就是说LPTIM的计数器可以选择lptim_ker_ck,也可以选择LPTIM_IN1或者LPTIM_IN。
注意:CLKMUX双路选择器对应的是CFGR寄存器的bit0:CKSEL,用于控制内核时钟选择由内部时钟源(APB时钟或LSE、LSI和HSI等任何其他内置振荡器)提供时钟。也可以选择由外部时钟源通过 LPTIM 外部 Input提供时钟。
Count mode对应的是CFGR寄存器的bit23:COUNTMODE计数模式位,用于选择 LPTIM 使用哪个时钟源来为计数器提供时钟。可以选择计数器在每个内部时钟脉冲后递增,或者在 LPTIM 外部 Input上的每个有效时钟脉冲后递增。
lptim_wkup
用于将系统从睡眠或者停机模式唤醒。
lptim_out和LPTIM_OUT
lptim_out表示计数器输出,用于内部触发。
LPTIM_OUT表示GPIO的输出通道,用于PWM。
LPTIM_ETR
通过GPIO为LPTIM提供外部触发。
lptim_ext_trigx
LPTIM的计数器既可以通过软件启动,也可以通过外部触发启动,有8种触发方式可供选择,以LPTIM1为例,支持的触发如下:
LPTIM_IN1,lptim_in1_mux1,lptim_in1_mux2和lptim_in1_mux3
LPTIM_IN2实际对应的是多路选择器的mux0,通过GPIO输入。
lptim_in1_mux1到lptim_in1_mux3对应的是内部输入,以LPTIM1为例,支持的输入信号如下:
LPTIM_IN2,lptim_in2_mux1,lptim_in2_mux2和lptim_in2_mux3
LPTIM_IN2实际对应的是多路选择器的mux0,通过GPIO输入。
lptim_in2_mux1到lptim_in2_mux3对应的是内部输入,以LPTIM1为例,支持的输入信号如下:
Glitch filter(干扰滤波器)
从框图中可以看到有三组Glitch filter,LPTIM_IN1和LPTIM_IN2接入多路选择器后各有一组,LPTIM_ETR接入后,也有一组。Glitch filter的作用是避免任何毛刺和噪声干扰在 LPTIM 内部传播,从而防止产生意外计数或触发。
注意:使用Glitch filter要向LPTIM 提供内部时钟源。
36.2.2 低功耗定时器的基本功能
LPTIM1 – LPTIM5都是16位的低功耗定时器(自动重载寄存器、比较寄存器和计数器都是16位的),相比TIM1 – TIM17这种通用定时器,在睡眠或者停机模式下依然可以工作(待机模式除外)。低功耗模式下要工作,就必然要支持低速时钟LSI、LSE或者外部输入时钟,这点是与通用定时器的本质区别。同时LPTIM的中断还可以唤醒停机模式,这点比较重要(休眠模式是任何中断都可以唤醒的,而停机模式可以LPTIM中断唤醒)。
以下几点是大家在使用中必须要了解到的:
1、 TIM1 – TIM17有专门的分频寄存器,而LPTIM1 – LPTIM5的分频是几种固定的值。
2、 低功耗定时器支持以下6种模式:
PWM模式
单脉冲模式
单次模式
在此模式下,当满足匹配条件时,输出可以切换高低电平(如果输出极性配置为高,则为低电平至高电平变化,反之亦然)。
编码器模式
超时模式
有效的边沿触发输入可复位定时器。第一个触发事件将启动计时器,任何连续触发事件将重置计数器并重新开始。
计数器模式:
计数器可用于计算来自Input1的外部事件或用于计算内部时钟周期。
36.2.3 低功耗定时器时钟选择问题(重要)
这个知识点比较重要,可以帮助大家更好的理解LPTIM。下面先看框图:
首先将框图里面两个最重要的标识跟寄存器对上号。
1、lptim_ker_ck接口
内核时钟,供lptim使用。lptim_ker_tim接入到CLKMUX双路选择器的一个输入端,另一个输入端是LPTIM_IN1或者LPTIM_IN2的输入。也就是说LPTIM的计数器可以选择lptim_ker_ck,也可以选择LPTIM_IN1或者LPTIM_IN。
2、最关键的地方来了
(1) CLKMUX多路选择器对应的是CFGR寄存器的bit0:CKSEL
用于控制内核时钟选择由内部时钟源(APB时钟或LSE、LSI和HSI等任何其他内置振荡器)提供时钟。
也可以选择由外部时钟源通过 LPTIM 外部 Input提供时钟。
(2) Count mode对应的是CFGR寄存器的bit23:COUNTMODE计数模式位,用于选择 LPTIM 使用哪个时钟源来为计数器提供时钟。
可以选择计数器在每个内部时钟脉冲后递增。
或者在 LPTIM 外部 Input上的每个有效时钟脉冲后递增。
3、应用的时候,我们可以选择
(1) CKSEL = 0 , COUNTMODE = 0
表示LPTIM内核时钟使用的内部时钟源,计数器通过内部时钟脉计数。
(2) CKSEL = 0 , COUNTMODE = 1
表示LPTIM内核时钟使用的内部时钟源,计数器通过外部输入脉冲计数。
(3) CKSEL = 1 , COUNTMODE = x
表示LPTIM内核时钟使用的外部时钟源,计数器通过外部输入脉冲计数。
36.2.4 干扰滤波器(Glitch filter)
Glitch filter干扰滤波器的作用是避免任何毛刺和噪声干扰在 LPTIM 内部传播,从而防止产生意外计数或触发。
实现原理就是LPTIM的CFGR寄存器有专门的控制位TRGFLT[1:0](用于滤波外部触发信号)和CKFLT[1:0](用于滤波外部输入时钟)来控制信号,其有效电平变化必须至少稳定2/4/8个时钟周期才能将其视为有效触发。
比如下面的截图,配置为稳定2个时钟周期才算有效信号。
36.2.5 单次触发和连续模式
单次触发的含义就是定时器由触发事件启动,当达到 ARR 值时停止,效果如下:
连续模式的含义是定时器由触发事件启动,并且直到被禁止才会停止,效果如下:
36.2.6 溢出模式
注:这个模式用来做停机模式唤醒比较方便。
检测引脚第1次检查到触发信号,LPTIM就开始工作了,在溢出时间内检测到的触发信号都将复位计数,定时器重新开始工作。如果溢出内没有再接收到触发信号,仅进入溢出中断。
36.2.7 波形输出
通过下面的截图,可以让大家对低功耗定时器的波形输出效果有个全面认识。
LPTIM_ARR是自动重载寄存器,Compare是比较寄存器。当定时器的计数器达到Compare后,GPIO输出高电平还是低电平,是由CFGR寄存器的bit2:1:WAVPOL波形极性决定的。
以PWM输出为例:
如果WAVPOL = 0表示计数器的数值介于Compare和LPTIM_ARR之间时,GPIO输出高电平。其它时间是低电平。
如果WAVPOL = 1表示计数器的数值介于Compare和LPTIM_ARR之间时,GPIO输出低电平。其它时间是高电平。
One–Shot效果跟PWM一样,不过GPIO仅输出1次脉冲。
Set–Once特殊些,计数到ARR后,GPIO输出结果将一直保持达到Compare寄存器数值的输出电平。
36.2.8 低功耗定时器LPTIM1 – LPTIM5的区别
关于这五个低功耗定时器的区别,可以直接通过参考手册里面的框图看它们的区别。我们这里也简单整理下:
LPTIM1和LPTIM2的功能是一样的,且支持编码器模式,而LPTIM3,LPTIM4和LPTIM5均不支持。
LPTIM3跟LPTIM1的区别是仅有1组LPTIM_IN输入,且不支持LTPTIM_ETR。
LPTIM4和LPTIM5的功能是一样的,这两个功能最弱。跟LPTIM1的区别是没有LPTIM_IN输入端,也不支持LPTIM_ETR,仅有一个内部触发lptim_ext_trigx。
36.3 低功耗定时器的HAL库用法
低功耗定时器的HAL库用法其实就是几个结构体变量成员的配置和使用,然后配置GPIO、时钟,并根据需要配置NVIC,中断和DMA。下面我们逐一展开为大家做个说明。
36.3.1 定时器寄存器结构体LPTIM_TypeDef
低功耗定时器相关的寄存器是通过HAL库中的结构体LPTIM_TypeDef定义的,在stm32h743xx.h中可以找到这个类型定义:
typedef struct
{
__IO uint32_t ISR; /*!< LPTIM Interrupt and Status register, Address offset: 0x00 */
__IO uint32_t ICR; /*!< LPTIM Interrupt Clear register, Address offset: 0x04 */
__IO uint32_t IER; /*!< LPTIM Interrupt Enable register, Address offset: 0x08 */
__IO uint32_t CFGR; /*!< LPTIM Configuration register, Address offset: 0x0C */
__IO uint32_t CR; /*!< LPTIM Control register, Address offset: 0x10 */
__IO uint32_t CMP; /*!< LPTIM Compare register, Address offset: 0x14 */
__IO uint32_t ARR; /*!< LPTIM Autoreload register, Address offset: 0x18 */
__IO uint32_t CNT; /*!< LPTIM Counter register, Address offset: 0x1C */
uint16_t RESERVED1; /*!< Reserved, 0x20 */
__IO uint32_t CFGR2; /*!< LPTIM Option register, Address offset: 0x24 */
} LPTIM_TypeDef;
这个结构体的成员名称和排列次序和CPU的定时器寄存器是一 一对应的。
__IO表示volatile, 这是标准C语言中的一个修饰字,表示这个变量是非易失性的,编译器不要将其优化掉。core_m7.h 文件定义了这个宏:
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
下面我们看下LPTIM1,LPTIM2,LPTIM3,LPTIM4和LPTIM5的定义,在stm32h743xx.h文件。
#define PERIPH_BASE ((uint32_t)0x40000000)
#define D2_APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define D3_APB1PERIPH_BASE (PERIPH_BASE + 0x18000000)
#define LPTIM1_BASE (D2_APB1PERIPH_BASE + 0x2400)
#define LPTIM2_BASE (D3_APB1PERIPH_BASE + 0x2400)
#define LPTIM3_BASE (D3_APB1PERIPH_BASE + 0x2800)
#define LPTIM4_BASE (D3_APB1PERIPH_BASE + 0x2C00)
#define LPTIM5_BASE (D3_APB1PERIPH_BASE + 0x3000)
#define LPTIM1 ((LPTIM_TypeDef *) LPTIM1_BASE) #define LPTIM2 ((LPTIM_TypeDef *) LPTIM2_BASE)
#define LPTIM3 ((LPTIM_TypeDef *) LPTIM3_BASE)
#define LPTIM4 ((LPTIM_TypeDef *) LPTIM4_BASE)
#define LPTIM5 ((LPTIM_TypeDef *) LPTIM5_BASE)
我们访问LPTIM的ISR寄存器可以采用这种形式:LPTIM->ISR = 0。
36.3.2 定时器句柄结构体LPTIM_HandleTypeDef
HAL库在LPTIM_TypeDef的基础上封装了一个结构体LPTIM_HandleTypeDef,定义如下:
typedef struct
{
LPTIM_TypeDef *Instance; /*!< Register base address */
LPTIM_InitTypeDef Init; /*!< LPTIM required parameters */
HAL_StatusTypeDef Status; /*!< LPTIM peripheral status */
HAL_LockTypeDef Lock; /*!< LPTIM locking object */
__IO HAL_LPTIM_StateTypeDef State; /*!< LPTIM peripheral state */
}LPTIM_HandleTypeDef;
这里重点介绍前两个参数,其它参数主要是HAL库内部使用的。
TIM_TypeDef *Instance
这个参数是寄存器的例化,方便操作寄存器,比如使能定时器的计数器。
SET_BIT(huart->Instance->CR, LPTIM_CR_CNTSTRT)。
LPTIM_InitTypeDef Init
这个参数是用户接触最多的,用于配置低功耗定时器的基本参数。
LPTIM_InitTypeDef结构体的定义如下:
typedef struct
{
LPTIM_ClockConfigTypeDef Clock;
LPTIM_ULPClockConfigTypeDef UltraLowPowerClock;
LPTIM_TriggerConfigTypeDef Trigger;
uint32_t OutputPolarity;
uint32_t UpdateMode;
uint32_t CounterSource;
uint32_t Input1Source;
uint32_t Input2Source;
}LPTIM_InitTypeDef;
成员Clock
用于设置时钟源和时钟分频,结构体变量LPTIM_ClockConfigTypeDef的定义如下。
typedef struct
{
uint32_t Source;