2.4. PWM 设备

2.4.1. 简介

脉冲宽度调制(Pulse width modulation,简称 PWM)是一种用数字方式实现模拟电压控制的技术。它是通过对一系列脉冲的宽度进行调制,等效出所需要的波形(包含形状以及幅值),对模拟信号电平进行数字编码,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。博流系列 MCU 中 DMA 设备具有以下特性:

  • 支持5通道 PWM 信号生成

  • 三种时钟源可选择(总线时钟 <bclk>、晶振时钟 <xtal_ck>、慢速时钟 <32k>),搭配 16-bit 时钟分频器

  • 双门限值域设定,增加脉冲弹性

2.4.2. PWM 设备结构体定义

typedef struct pwm_device {
    struct device parent;
    uint8_t ch;
    uint8_t polarity_invert_mode;
    uint16_t period;
    uint16_t threshold_low;
    uint16_t threshold_high;
    uint16_t it_pulse_count;

} pwm_device_t;
  • parent 继承父类属性

  • ch 通道号,使能PWM通道0则ch为0,使能PWM通道0则ch为1,以此类推

  • polarity_invert_mode 极性翻转使能

  • period PWM 周期值

  • threshold_low PWM 低门限阈值,不能大于period

  • threshold_high PWM 高门限阈值,不能大于period

  • it_pulse_count 触发中断条件的周期计数值

注解

PWM 实际频率 = PWM 时钟源/分频/period ,period 非 PWM 实际周期,

注解

PWM 占空比 = (threshold_high-threshold_low)/period * 100%

2.4.3. PWM 设备参数配置表

每一个 PWM 设备都有一个参数配置宏,宏定义位于 bsp/board/xxx 目录下 peripheral_config.h 文件,变量定义位于 hal_pwm.c 中,因此无需用户自己定义变量。当用户打开对应设备的宏,该设备的配置才生效。例如打开宏 BSP_USING_PWM_CH2PWM_CH2_CONFIG 即生效,同时 PWM 设备的通道2就可以进行注册和使用了。

/*参数配置宏*/
#if defined(BSP_USING_PWM_CH2)
#ifndef PWM_CH2_CONFIG
#define PWM_CH2_CONFIG                   \
    {                                    \
        .ch = 2,                         \
        .polarity_invert_mode = DISABLE, \
        .period = 0,                     \
        .threshold_low = 0,              \
        .threshold_high = 0,             \
        .it_pulse_count = 0,             \
    }
#endif
#endif


/*变量定义*/
static pwm_device_t pwmx_device[PWM_MAX_INDEX] = {
#ifdef BSP_USING_PWM_CH0
    PWM_CH0_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH1
    PWM_CH1_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH2
    PWM_CH2_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH3
    PWM_CH3_CONFIG,
#endif
#ifdef BSP_USING_PWM_CH4
    PWM_CH4_CONFIG,
#endif
};

注解

上述配置可以通过 PWM_DEV(dev)->xxx 进行修改,只能在调用 device_open 之前使用。

2.4.4. PWM 设备接口

PWM 设备接口全部遵循标准设备驱动管理层提供的接口。并且为了方便用户调用,将某些标准接口使用宏来重定义。

2.4.4.1. pwm_register

pwm_register 用来注册一个 PWM 设备的一个通道的标准驱动接口,在注册之前需要打开对应 PWM 设备某个通道的宏定义,例如定义 BSP_USING_PWM_CH0 方可使用 PWM 通道0 设备。注册完成以后才可以使用其他接口,如果没有定义宏,则无法使用 PWM 设备。

int pwm_register(enum pwm_index_type index, const char *name);
  • index 要注册的设备索引

  • name 为注册的设备命名

index 用来选择 PWM 设备某个通道的配置,一个 index 对应一个 PWM 设备的一个通道配置,比如 PWM_CH0_INDEX 对应 PWM 通道0 配置,index 有如下可选类型

enum pwm_index_type
{
#ifdef BSP_USING_PWM_CH0
    PWM_CH0_INDEX,
#endif
#ifdef BSP_USING_PWM_CH1
    PWM_CH1_INDEX,
#endif
#ifdef BSP_USING_PWM_CH2
    PWM_CH2_INDEX,
#endif
#ifdef BSP_USING_PWM_CH3
    PWM_CH3_INDEX,
#endif
#ifdef BSP_USING_PWM_CH4
    PWM_CH4_INDEX,
#endif
    PWM_MAX_INDEX
};

2.4.4.2. device_open

device_open 用于打开一个 PWM 设备的一个通道,实际调用 pwm_open

int device_open(struct device *dev, uint16_t oflag);
  • dev 设备句柄

  • oflag 设备的打开方式

  • return 错误码,0 表示打开成功,其他表示错误

oflag 提供以下类型

#define DEVICE_OFLAG_STREAM_TX  0x001 /* 设备以轮训发送模式打开 */
#define DEVICE_OFLAG_STREAM_RX  0x002 /* 设备以轮训接收模式打开 */
#define DEVICE_OFLAG_INT_TX     0x004 /* 设备以中断发送模式打开 */
#define DEVICE_OFLAG_INT_RX     0x008 /* 设备以中断接收模式打开 */
#define DEVICE_OFLAG_DMA_TX     0x010 /* 设备以 DMA 发送模式打开 */
#define DEVICE_OFLAG_DMA_RX     0x020 /* 设备以 DMA 接收模式打开 */

2.4.4.3. device_close

device_close 用于关闭一个 PWM 设备的一个通道,实际调用 pwm_close

int device_close(struct device *dev);
  • dev 设备句柄

  • return 错误码,0 表示关闭成功,其他表示错误

2.4.4.4. device_control

device_control 用于对 PWM 设备的一个通道进行控制和参数的修改,实际调用 pwm_control

int device_control(struct device *dev, int cmd, void *args);
  • dev 设备句柄

  • cmd 设备控制命令

  • args 控制参数

  • return 不同的控制命令返回的意义不同。

PWM 设备除了标准的控制命令,还具有自己特殊的控制命令。

#define DEIVCE_CTRL_PWM_IT_PULSE_COUNT_CONFIG 0x10

args 根据不同的 cmd 传入不同,具体如下:

table1

cmd

args

description

DEVICE_CTRL_RESUME

NULL

开启当前 PWM 通道

DEVICE_CTRL_SUSPEND

NULL

关闭当前 PWM 通道

DEVICE_CTRL_PWM_FREQUENCE_CONFIG

uint32_t

配置当前 PWM 通道周期值

DEVICE_CTRL_PWM_DUTYCYCLE_CONFIG

pwm_dutycycle_config_t

配置当前 PWM 通道占空比

DEVICE_CTRL_PWM_IT_PULSE_COUNT_CONFIG

uint32_t

配置触发 PWM 中断周期值

2.4.4.5. device_set_callback

device_set_callback 用于注册一个 PWM 设备的一个通道中断回调函数。

int device_set_callback(struct device *dev, void (*callback)(struct device *dev, void *args, uint32_t size, uint32_t event));
  • dev 设备句柄

  • callback 要注册的中断回调函数

    • dev 设备句柄

    • args 无用

    • size 无用

    • event 中断事件类型

event 类型如下

enum pwm_event_type
{
    PWM_EVENT_COMPLETE,
};

2.4.4.6. pwm_channel_start

pwm_channel_start 用于开启 PWM 通道。实际是调用 device_control ,其中 cmdDEVICE_CTRL_RESUME

pwm_channel_start(dev)
  • dev 需要开启的 pwm 通道句柄

2.4.4.7. pwm_channel_stop

pwm_channel_stop 用于关闭 PWM 通道。实际是调用 device_control ,其中 cmdDEVICE_CTRL_SUSPEND

pwm_channel_stop(dev)
  • dev 需要关闭的 pwm 通道句柄

2.4.4.8. pwm_channel_freq_update

pwm_channel_freq_update 用于更新 PWM 通道的频率。实际是调用 device_control ,其中 cmdDEIVCE_CTRL_PWM_FREQUENCE_CONFIG

pwm_channel_freq_update(dev,count)
  • dev 需要更新的 pwm 通道句柄

  • count 周期值,实际频率 = pwm_clk/pwm_div/count

2.4.4.9. pwm_channel_dutycycle_update

pwm_channel_dutycycle_update 用于更新 PWM 通道的频率。实际是调用 device_control ,其中 cmdDEIVCE_CTRL_PWM_DUTYCYCLE_CONFIG

pwm_channel_dutycycle_update(dev,cfg)
  • dev 需要更新周期计数值的 pwm 通道句柄

  • cfg pwm_dutycycle_config_t 句柄

2.4.4.10. pwm_it_pulse_count_update

pwm_it_pulse_count_update 用于更新 PWM 通道的计数值,需要先使能 PWM 中断才起作用,当 pwm 计数达到设置的周期计数值则会产生中断。实际是调用 device_control ,其中 cmdDEIVCE_CTRL_PWM_IT_PULSE_COUNT_CONFIG

pwm_it_pulse_count_update(dev,count)
  • dev 需要更新周期计数值的 pwm 通道句柄

  • count 周期计数值