8 脉宽调制发生器(PWM)
PWM 模块实现脉冲宽度调制信号的产生,控制 LED 等外部器件。通过 APB 总线读写 寄存器来实现整个过程。ING918x 包括 6 个 PWM 模块,每个模块包含 2 个通道,因 此可以使用 12 个 PWM 通道。
PWM 特性:
- 每个通道都可以通过寄存器或 PWM 序列来控制
- 每个通道都可以屏蔽
- 寄存器中定义最多四个占空比序列
- 可以使用多种模式:命令模式、单步模式、对称模式、空白区模式
8.1 PWM 工作模式
PWM 使用的时钟频率可配置,请参考 SYSCTRL。
每个 PWM 通道支持以下多种工作模式:
typedef enum
{
..._UP_WITHOUT_DIED_ZONE = ...,
..._UP_WITH_DIED_ZONE = ...,
..._UPDOWN_WITHOUT_DIED_ZONE = ...,
..._UPDOWN_WITH_DIED_ZONE = ...,
..._SINGLE_WITHOUT_DIED_ZONE = ...,
} PWM_WorkMode_t;
8.1.1 最简单的模式:UP_WITHOUT_DIED_ZONE
此模式需要配置两个门限:计数器回零门限 PERA_TH、高门限 HIGH_TH,HIGH_TH 必须小于 HIGH_TH。以伪代码描述 A、B 输出如下:
= 0;
cnt ()
on_clock_rising_edge{
= cnt < PERA_TH ? cnt + 1 : 0;
cnt = HIGH_TH <= cnt;
A = !A;
B }
8.1.2 UP_WITH_DIED_ZONE
与 UP_WITHOUT_DIED_ZONE 相比,此模式需要一个新的死区门限 DZONE_TH,DZONE_TH 必须小于 HIGH_TH。以伪代码描述 A、B 输出如下:
cnt = 0; on_clock_rising_edge() { cnt = cnt < PERA_TH ? cnt + 1 : 0; A = HIGH_TH + DZONE_TH <= cnt; B = DZONE_TH <= cnt < HIGH_TH); }
8.1.3 UPDOWN_WITHOUT_DIED_ZONE
此模式需要的门限参数与 UP_WITHOUT_DIED_ZONE 相同。以伪代码描述 A、B 输出如下:
= 0;
cnt ()
on_clock_rising_edge{
= cnt < 2 * PERA_TH ? cnt + 1 : 0;
cnt = PERA_TH - HIGH_TH <= cnt <= PERA_TH + HIGH_TH;
A = !A;
B }
8.1.4 UPDOWN_WITH_DIED_ZONE
与 UP_WITHOUT_DIED_ZONE 相比,此模式需要一个新的死区门限 DZONE_TH。 以伪代码描述 A、B 输出如下:
= 0;
cnt ()
on_clock_rising_edge{
= cnt < 2 * PERA_TH ? cnt + 1 : 0;
cnt = PERA_TH - HIGH_TH + DZONE_TH <= cnt <= PERA_TH + HIGH_TH;
A = (cnt < PERA_TH - HIGH_TH) || (cnt > PERA_TH + HIGH_TH + DZONE_TH);
B }
8.2 PWM 使用说明
8.2.1 启动与停止
共有两个开关与 PWM 的启动和停止有关:使能(Enable)、停机控制(HaltCtrl)。只有当 Enable
为 1,
HaltCtrl
为 0 时,PWM 才真正开始工作。
相关的 API 为:
// 使能 PWM 通道
void PWM_Enable(
const uint8_t channel_index, // 通道号
const uint8_t enable // 使能或禁用
);
// PWM 通道停机控制
void PWM_HaltCtrlEnable(
const uint8_t channel_index, // 通道号
const uint8_t enable // 停机(1) 或运转(0)
);
8.2.2 配置工作模式
void PWM_SetMode(
const uint8_t channel_index, // 通道号
const PWM_WorkMode_t mode // 模式
);
8.2.3 配置门限
// 配置 PERA_TH
void PWM_SetPeraThreshold(
const uint8_t channel_index,
const uint32_t threshold);
// 配置 DZONE_TH
void PWM_SetDiedZoneThreshold(
const uint8_t channel_index,
const uint32_t threshold);
// 配置 HIGH_TH
void PWM_SetHighThreshold(
const uint8_t channel_index,
const uint8_t multi_duty_index, // 对于 ING916XX,此参数无效
const uint32_t threshold);
各门限值最大支持 0xFFFFF,共 20 个比特。
8.2.4 输出控制
// 掩膜控制
void PWM_SetMask(
const uint8_t channel_index, // 通道号
const uint8_t mask_a, // A 路掩膜
const uint8_t mask_b // B 路掩膜
);
// 配置停机输出值
void PWM_HaltCtrlCfg(
const uint8_t channel_index, // 通道号
const uint8_t out_a, // A 路停机输出值
const uint8_t out_b // B 路停机输出值
);
// 反相
void PWM_SetInvertOutput(
const uint8_t channel_index, // 通道号
const uint8_t inv_a, // A 路是否反相
const uint8_t inv_b // B 路是否反相
);
8.2.5 综合示例
下面的例子将 channel_index
通道配置成输出频率为 frequency
、占空比为 (on_duty)%
的方波,
涉及 3 个关键参数:
生成这种最简单的 PWM 信号需要的模式为 UP_WITHOUT_DIED_ZONE;
PERA_TH 控制输出信号的频率,设置为
PWM_CLOCK_FREQ / frequency
;HIGH_TH 控制信号的占空比,设置为
PERA_TH * (100 - on_duty) %
void PWM_SetupSimple(
const uint8_t channel_index,
const uint32_t frequency,
const uint16_t on_duty)
{
uint32_t pera = PWM_CLOCK_FREQ / frequency;
uint32_t high = pera > 1000 ?
/ 100 * (100 - on_duty)
pera : pera * (100 - on_duty) / 100;
(channel_index, 1);
PWM_HaltCtrlEnable(channel_index, 0);
PWM_Enable(channel_index, pera);
PWM_SetPeraThreshold(channel_index, 0, high);
PWM_SetHighThreshold(channel_index, PWM_WORK_MODE_UP_WITHOUT_DIED_ZONE);
PWM_SetMode(channel_index, 0, 0);
PWM_SetMask(channel_index, 1);
PWM_Enable(channel_index, 0);
PWM_HaltCtrlEnable}