PWM应用笔记

PWM驱动说明

简介

PWM应用广泛,思澈平台可用于PWM输出的定时器类型包括:GPTIM(通用定时器),ATIM(高级定时器),LPTIM(低功耗定时器)。其中,GPTIM PWM更为常用,作为优先使用。

PWM列表

  • PWM 2

  • PWM 3

  • PWM 4

  • PWM 5

  • PWM 6

  • PWM A1

  • PWM A2

  • PWM LPTIM1

  • PWM LPTIM2

  • PWM LPTIM3

备注

pwm2/pwm3/A1/A2/lptim1 位于HCPU;
pwm4/pwm5/pwm6/lptim2/lptim3 位于LCPU;

小技巧

pwm2 ~ pwm6 与gptime对应关系, pwm2 对应gptime1, 以此类推; 最后一个:pwm6对应的gptime5;

PWM 在52x/55x/56x/58x的差异

差异点包括:

  1. 55x/58x系列,输出PWM的IO口固定,需要根据规格书确认IO的PWM通道;
    52x/56x系列,任何一个带有TIM功能的IO都能配置为任何一种PWM;
    规格对比,如下图:

../../_images/PWM_IO.png
  1. 52x/55x/56x/58x 使用HCPU的IO输出PWM时,如果打开了宏#define BSP_PM_FREQ_SCALING 1; HCPU会进行自动降频,HCPU的IO输出的PWM频率也会随着调整。
    解决办法:
    55x/56x/58x 建议使用LCPU的IO用于PWM, 因为LCPU的IO输出PWM频率不会随着主频变化。 如果坚持使用HCPU的IO用于输出PWM, 可以考虑关掉宏#define BSP_PM_FREQ_SCALING 1,不过这样会导致亮屏时功耗增加;
    52x HCPU的IO用于输出PWM, 优先使用GPTIM2的PWM。因为GPTIM2不受系统主频影响;

PWM使用

PWM的使用步骤如下:

  1. menuconfig 配置要使用的PWM;

../../_images/PWM_LIST.png
  1. 配置pinmux,确定使用的pin,以及对应的pwm通道,以PA20使用PWM2为例,配置如下:

HAL_PIN_Set(PAD_PA20, GPTIM2_CH1, PIN_NOPULL, 1);
  1. 配置应用使用的PWM及通道,以MOTOR使用 PA20 作为PWM(GPTIM2)通道1为例,配置如下:

../../_images/PWM_MOTOR.png
  1. 驱动PWM调用过程大致如下:

../../_images/PWM_USE_FLOW.png

参考代码如下:

struct rt_device_pwm *pwm_device = (struct rt_device_pwm *)rt_device_find("pwm1");
rt_pwm_set(pwm_device, 1, period, pulse);
rt_pwm_enable(pwm_device, 1);
rt_pwm_disable(pwm_device, 1);

备注

PWM通道的复用说明:

  1. 同一个PWM的不同通道可以配置不同的占空比输出;即:允许频率相同的两个设备选择同一个PWM的不同通道;
    例如:马达和光感控制 在PWM 频率相同时,可以使用同一个PWM的两个通道,而不会冲突;

  2. 不同频率的两个设备使用同一个PWM的两个通道时,必须确保不会同时使用;
    例如: 马达和蜂鸣器 在使用同一个PWM时,如果频率不相同,务必要确保二者不是同时使用;即:一个用的时候,另外一个没有使用;否则,二者会相互影响对方的效果。

  3. 不同频率,且无法分时复用的设备,不能使用同一个PWM;
    例如:背光在亮屏状态的时候是一直使用的,最好单独使用PWM,不要和其他设备复用;

PWM停止后的电平控制

PWM停止是指PWM不再输出波形,而保持为低电平或高电平状态; 一般情况下:rt_pwm_disable执行后,PWM channel处于高阻状态,电平无法立刻到低电平,如下图:

../../_images/PWM_stop0.png

如果想实现下图的效果:

sifli

可以通过配置占空比为0的方式实现;

小技巧

配置占空比为0% ==》输出低电平

配置占空比为100% ==》输出高电平

如何添加一个PWM马达

添加PWM马达,步骤如下:

  1. 配置menuconfig,使能马达采用PWM方式驱动,以及配置PWM通道,周期,电源控制pin;

../../_images/MOTOR_CONFIG.png

备注

注意
PWM周期配置说明:
Enalbe PWM peroid unit use microsecond 没有选中时,motor period default: ms, but can chang to microsecond 单位是ms;
Enalbe PWM peroid unit use microsecond 选中时,motor period default: ms, but can chang to microsecond 单位是us;

  1. 配置pinmux,以及使能对应PWM设备;

  2. solution2.0已经封装了应用层使用的接口;

  • motor_power_on 马达初始化

  • motor_start 马达开启(默认配置)

  • motor_stop 马达停止

  • app_motor_get_level 马达当前占空比

  • app_motor_set_level 设置马达占空比

一般使用流程:
motor_power_on -> motor_start -> motor_stop ;
修改占空比:
app_motor_set_level ;

小技巧

硬件支持实时修改占空比,不需要执行停止,再改变占空比;有利于提高占空比的平滑性,避免蜂鸣器等器件切换占空比出现的噪声;

如何实现LCD背光使用PWM

LCD背光使用PWM的步骤如下:

  1. 修改文件“\solution2_0\sdk\customer\boards\Kconfig_lcd”,找到对应的LCD后,增加下图中的代码,LCD支持PWM背光;

../../_images/LCD_PWM_EN.png
  1. 修改在使用的board下的 Kconfig文件,例如:eh_lb523下的Kconfig文件。

../../_images/LCD_PWM_CONFIG.png
  1. 确保背光使用的PWM pinmux配置正常,PWM 设备处于使能状态;

  2. 在LCD 的背光接口,增加使用PWM调整背光的代码;

void  xxx_SetBrightness(LCDC_HandleTypeDef *hlcdc, uint8_t br)
{
    rt_device_t device = rt_device_find("lcdlight");
    if (device)
    {
        rt_err_t err = rt_device_open(device, RT_DEVICE_OFLAG_RDWR);
        uint8_t val = br;
        rt_device_write(device, 0, &val, 1);
        rt_device_close(device);
    }
    else
    {
        LOG_E("Can't find device lcdlight!");
    }
    LOG_I("XXX_SetBrightness


");
}

小心

如果LCD 驱动在大核,而PWM背光pin使用的小核PIN,需要对小核的RCC_Module 进行处理,处理过程如下:
修改drv_common.c中HAL_RCC_MspInit()函数,注释掉背光用的RCC_Module;

../../_images/LCD_PWM_MSP_INIT.png

如何睡眠情况下输出PWM

睡眠状态输出PWM,需要使用lcpu 的lptim3 输出PWM。 配置步骤如下:

  1. menuconfig 使能lcpu 的lptim3 PWM.

../../_images/PWM_LPTIM3.png
  1. 配置lptim3 PWM 对应的pin,常用的pin包括PB43~PB46;

HAL_PIN_Set(PAD_PB44, LPTIM3_OUT, PIN_NOPULL, 0)
MODIFY_REG(hwp_lpsys_aon->DBGMUX,LPSYS_AON_DBGMUX_PB44_SEL_Msk,
MAKE_REG_VAL(1,LPSYS_AON_DBGMUX_PB44_SEL_Msk,LPSYS_AON_DBGMUX_PB44_SEL_Pos));
  1. 配置唤醒源在睡眠的时候继续输出,使能宏PM_WAKEUP_PIN_AS_OUTPUT_IN_SLEEP;

../../_images/PWM_LPTIM3_SLEEP.png

备注

宏PM_WAKEUP_PIN_AS_OUTPUT_IN_SLEEP,针对所有的唤醒源;
所以务必确保其他的PB唤醒pin,要在硬件上固定上拉或下拉,确保不要漏电;

  1. 代码中使用lptim3 PWM;

struct rt_device_pwm *pwm_device = (struct rt_device_pwm *)rt_device_find("pwmlp3");
rt_pwm_set(pwm_device, 1, period, pulse);
rt_pwm_enable(pwm_device, 1);