MM32L013x——LPTIM的应用介绍

描述

低功耗技术旨在减少设备电流消耗,延长电池寿命,可以有效的延长产品的使用寿命。这就需要合理分配运行时间和空闲时间,在空闲时可以通过使MCU进入低功耗模式降低系统的功耗,在需要MCU工作时唤醒MCU,低功耗定时器(LPTIM)有助于降低功耗,特别是当系统处于低功耗模式时(如 stop模式)可以在休眠模式下实现外部脉冲计数功能。通过外部输入的触发信号,能够实现低功耗超时唤醒。LPTIM 具有外部时钟计数,超时唤醒功能和 PWM 输出等多种用途。

本文主要介绍 MM32 全新低功耗系列 MM32L013x 产品中的 LPTIM 外设模块,它允许系统执行简单的任务,同时功耗保持在绝对最小。

1LPTIM 简介

LPTIM 由一个 16 位计数器组成,可以为用户提供便捷的计数和定时功能。LPTIM 运行在 CORE 电源域,可以工作在低功耗模式下,具有低功耗的特点,当然也可以被当做一个普通的 16 位基础定时器来使用。

2LPTIM 常见用途

脉冲计数功能

PWM 生成器

周期性地超时唤醒sleep模式、stop模式

以上所有功能应用均为普通 TIM 所不能实现的,正是由于 LPTIM 的时钟源具有多样性,使得其能够在所有电源模式(standby模式除外)下保持运行状态。

3LPTIM 主要特性

16 位递增计数器,相当于 LPT_CNT 值由模块时钟驱动加一递增最大到 65535,并且包括一个 16 位比较寄存器和目标值寄存器

3 位异步时钟预分频器,可以将输入进模块的时钟进行多种系数的预分频,包括:

1/2/4/8/16/32/64/128 分频

多种内部和外部的时钟源可选,包括:LSI/LSE/PCLK2

计数器

可以选择不同边沿的脉冲极性用作触发计数,触发源包括:LPTIM1_TRIGGER 引脚输入触发、COMP OUT 事件触发

可以设定不同的 LPT_CMP 和 LPT_TARGET 值从而通过 LPTIM1_OUT 引脚输出不同占空比的PWM 波形或者方波

可以设定不同的 LPT_TARGET 值从而进行不同时长的低功耗唤醒

可以开启不同的中断,包括:外部触发、比较匹配和计数器溢出中断,在唤醒 STOP 模式时,除了需要使能相应的中断外,还需配置 EXTI_Line23 并且使能相关的功能

4LPTIM 功能框图

LPTIM 的功能框图如下,主要包括了:触发源选择模块、时钟输入及分频模块、计数模块以及比较匹配输出单元等。

计数器

涉及到时钟选择的部分需要设置RCC_CFGR2[30:29],在 UM 手册中时钟配置寄存器2(RCC_CFGR2):

计数器

使能LPTIM时钟需要设置RCC_APB2ENR[31]位:

计数器

涉及到 LPTIM1_TRIGGER 和 LPTIM1_OUT 引脚的功能定义情况在 DS 手册中引脚复用及复用列表:

计数器

5LPTIM 寄存器表

由于 MM32L013x 系列产品中只有一个 LPTIM 模块,所以在文档和程序中也习惯称作 LPTIM1,它的基地址为 0x40012800,所有寄存器设计为 16 位,预留出 16位保持 32 位对齐,寄存器占用情况如下:

计数器

其中 LPT_CFG 、 LPT_IE 、 LPT_CTRL 、LPT_CMP 、 LPT_TARGET 为可读可写操作的,LPT_IF 为可读并且写 1 清零操作的,LPT_CNT 为只读操作的,具体功能描述参见 UM 对应章节内容。

6LPTIM 功能实现

6.1  带溢出中断的普通定时器

使能 APB2 总线上的 LPTIM 外设时钟,用于同步

初始化配置 LPT_CFG 寄存器 MODE=0,计数器被触发后保持运行,直到被关闭为止

初始化配置 LPT_CFG 寄存器 TMODE=00,选择普通计数器模式

选择外部时钟或内部时钟作为计数器的时钟源

配置 LPT_IE =1,使能 LPTIM 计数器溢出中断

配置 LPT_CTRL 寄存器 LPTEN=1,使能 LPTIM 计数器

计数器使能后有两个周期的同步过程,同步完成后,计数器开始工作,计数达到目标之后回到 0 重新开始计数,并产生溢出中断

按上述流程的代码配置如下:

 

void LPTIM1_Init(u16 arr)
{
    LPTIM_TimeBaseInit_TypeDef  init_struct;

    RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);

    LPTIM_TimeBaseStructInit(&init_struct);
    init_struct.ClockSource            = LPTIM_PCLK_Source;
    init_struct.CountMode              = LPTIM_CONTINUOUS_COUNT_Mode;
    init_struct.OutputMode             = LPTIM_NORMAL_WAV_Mode;
    init_struct.Waveform               = LPTIM_AdjustPwmOutput_Mode;
    init_struct.Polarity               = LPTIM_Positive_Wave;
    init_struct.ClockDivision          = LPTIM_CLK_DIV1;

    if(init_struct.ClockSource == LPTIM_LSE_Source) {
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);
        PWR_BackupAccessCmd(ENABLE);
        RCC_LSEConfig(RCC_LSE_ON);
        DELAY_Ms(5000);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));
        LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source);
    }
    else if(init_struct.ClockSource == LPTIM_LSI_Source) {
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);
        PWR_BackupAccessCmd(ENABLE);
        RCC_LSICmd(ENABLE);
        DELAY_Ms(500);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));
        LPTIM_CLKConfig(LPTIM1, LPTIM_LSI_Source);
    }
    else { //(init_struct.ClockSource == LPTIM_PCLK_Source)
        LPTIM_CLKConfig(LPTIM1, LPTIM_PCLK_Source);
    }

    LPTIM_TimeBaseInit(LPTIM1, &init_struct);

    LPTIM_SetTarget(LPTIM1, arr);
}

void LPTIMER1_IRQHandler(void)
{
    if(LPTIM_GetITStatus(LPTIM1, LPTIF_OVIF)) {
        LPTIM_ClearITPendingBit(LPTIM1, LPTIF_OVIF);
        LED3_TOGGLE();
        LED4_TOGGLE();
    }
}

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStruct;

    NVIC_InitStruct.NVIC_IRQChannel = LPTIMER1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 2;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

s32 main(void)
{
    DELAY_Init();
    LED_Init();
    LPTIM1_Init(4000 - 1);
    NVIC_Configuration();
    LPTIM_ITConfig(LPTIM1, LPTIE_OVIE, ENABLE);
    LPTIM_Cmd(LPTIM1, ENABLE);
    while (1)
    {
        LED1_TOGGLE();
        LED2_TOGGLE();
        DELAY_Ms(1000);
    }
}

 

6.2  PWM 输出

初始化中使用以上相同的步骤,需要额外配置 LPT_CFG 寄存器 PWM=1,选择 PWM 输出模式

再配置 LPT_CMP 和 LPT_TARGET 寄存器,设定比较值和目标值,PWM 的占空比由比较值和目标值决定,输出在计数器值等于比较值翻转为 1,在等于目标值时翻转为 0

另外需要配置一组 LPTIM1_OUT 引脚用于输出 PWM 波形,这里以 PB14 为例

代码配置如下:

 

void LPTIM_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_GPIO_ClockCmd(GPIOB, ENABLE);

    //set PB14 as LPTIM1 Output Pin
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_3);

    GPIO_InitStruct.GPIO_Pin  =  GPIO_Pin_14;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void LPTIM1_Init(u16 arr)
{
    LPTIM_TimeBaseInit_TypeDef  init_struct;

    RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);

    LPTIM_TimeBaseStructInit(&init_struct);
    init_struct.ClockSource            = LPTIM_PCLK_Source;
    init_struct.CountMode              = LPTIM_CONTINUOUS_COUNT_Mode;
    init_struct.OutputMode             = LPTIM_NORMAL_WAV_Mode;
    init_struct.Waveform               = LPTIM_AdjustPwmOutput_Mode;
    init_struct.Polarity               = LPTIM_Positive_Wave;
    init_struct.ClockDivision          = LPTIM_CLK_DIV1;

    if(init_struct.ClockSource == LPTIM_LSE_Source) {
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);
        PWR_BackupAccessCmd(ENABLE);
        RCC_LSEConfig(RCC_LSE_ON);
        DELAY_Ms(5000);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));
        LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source);
    }
    else if(init_struct.ClockSource == LPTIM_LSI_Source) {
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);
        PWR_BackupAccessCmd(ENABLE);
        RCC_LSICmd(ENABLE);
        DELAY_Ms(500);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));
        LPTIM_CLKConfig(LPTIM1, LPTIM_LSI_Source);
    }
    else { //(init_struct.ClockSource == LPTIM_PCLK_Source)
        LPTIM_CLKConfig(LPTIM1, LPTIM_PCLK_Source);
    }

    LPTIM_TimeBaseInit(LPTIM1, &init_struct);
}

s32 main(void)
{
    DELAY_Init();
    LED_Init();
    LPTIM1_Init(4000 - 1);
    LPTIM_SetCompare(LPTIM1, 4000 / 2 - 1);
    LPTIM_SetTarget(LPTIM1, 4000 );
    LPTIM_GPIO_Init();
    LPTIM_Cmd(LPTIM1, ENABLE);
    while (1)
    {
        LED1_TOGGLE();
        LED2_TOGGLE();
        DELAY_Ms(1000);
    }
}

 

6.3  Trigger 脉冲触发计数

初始化中使用以上相同的步骤,需要修改配置 LPT_CFG 寄存器 TMODE=01,选择 Trigger 脉冲触发计数模式

配置 LPT_CFG 寄存器 TRIGSEL = 0,选择外部引脚触发计数

配置 LPT_CFG 寄存器 TRIGCFG,选择外部触发信号的有效沿

用户可以根据需求选择是否使能滤波器,配置LPT_CFG 寄存器

根据需求是否使能外部触发中断位

另外需要配置一组 LPTIM1_TRIGGER 引脚用于触发输入,这里以 PB13 为例

代码配置如下:

 

void LPTIM_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_GPIO_ClockCmd(GPIOB, ENABLE);

    //set PB13 as LPTIM1 Trigger Pin
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_3);

    GPIO_InitStruct.GPIO_Pin  =  GPIO_Pin_13;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void LPTIM1_Init(u16 arr)
{
    LPTIM_TimeBaseInit_TypeDef  init_struct;

    RCC_APB2PeriphClockCmd(RCC_APB2ENR_LPTIM1, ENABLE);

    LPTIM_TimeBaseStructInit(&init_struct);
    init_struct.ClockSource            = LPTIM_PCLK_Source;
    init_struct.CountMode              = LPTIM_CONTINUOUS_COUNT_Mode;
    init_struct.OutputMode             = LPTIM_PULSE_TRIG_Mode;
    init_struct.Waveform               = LPTIM_AdjustPwmOutput_Mode;
    init_struct.Polarity               = LPTIM_Positive_Wave;
    init_struct.ClockDivision          = LPTIM_CLK_DIV1;

    if(init_struct.ClockSource == LPTIM_LSE_Source) {
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);
        PWR_BackupAccessCmd(ENABLE);
        RCC_LSEConfig(RCC_LSE_ON);
        DELAY_Ms(5000);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSERDY));
        LPTIM_CLKConfig(LPTIM1, LPTIM_LSE_Source);
    }
    else if(init_struct.ClockSource == LPTIM_LSI_Source) {
        RCC_APB1PeriphClockCmd(RCC_APB1ENR_PWR | RCC_APB1ENR_BKP, ENABLE);
        PWR_BackupAccessCmd(ENABLE);
        RCC_LSICmd(ENABLE);
        DELAY_Ms(500);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));
        LPTIM_CLKConfig(LPTIM1, LPTIM_LSI_Source);
    }
    else { //(init_struct.ClockSource == LPTIM_PCLK_Source)
        LPTIM_CLKConfig(LPTIM1, LPTIM_PCLK_Source);
    }

    LPTIM_TimeBaseInit(LPTIM1, &init_struct);

    LPTIM1->CFGR = LPTIM_ExInputUpEdge;
    LPTIM1->CFGR = LPTIM_External_PIN_Trig;
}

 

6.4  1s 周期性唤醒 STOP 模式

详细可以参见灵动微课堂 (第196讲) | 使用MM32F0270 LPTIM从STOP模式唤醒(点击跳转)。

计数器

 

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分