Linux 下 PWM 调试实战指南
一、前言
在嵌入式系统中,PWM(脉宽调制)被广泛用于控制风扇、LED 灯、蜂鸣器等外设的亮度、速度或音调。本文将结合高通 QRB5165 平台,介绍如何在 Linux 系统下调试 PWM 功能,涵盖设备树配置、用户空间控制及调试技巧。
二、PWM 基本原理与 Linux 架构
2.1 什么是 PWM?
PWM(Pulse Width Modulation)是一种通过调节脉冲宽度来控制模拟信号输出的技术。其核心是周期性地开关信号,调节平均输出电压或功率。
关键参数包括:
period
:一个完整周期的持续时间,单位为纳秒(ns)duty_cycle
:高电平持续的时间,决定输出的平均功率
举例说明:
周期为 20ms,duty_cycle 为 10ms,表示 50% 占空比,输出为方波的半个周期为高电平。
2.2 Linux PWM 子系统概览
Linux 提供统一的 PWM 子系统,主要分为三层架构:
- PWM 控制器驱动层:实现对具体硬件的寄存器控制,如
qcom,geni-pwm
- PWM 框架层:位于
drivers/pwm/
,提供标准接口 - PWM 消费者驱动层:如 LED、蜂鸣器等,作为 PWM 的使用者
常见用户控制方式:
- sysfs 接口(旧方式)
- PWM framework API(用于驱动开发)
- 通过设备树绑定控制器和通道
三、设备树配置(以 QRB5165 为例)
3.1 PWM 控制器节点定义
pwm_lpg: pwm@c440000 {
compatible = "qcom,geni-pwm";
reg = <0x0 0x0c440000 0x0 0x1000>;
clocks = <&rpmhcc RPMH_PWM_CLK>;
clock-names = "core";
#pwm-cells = <2>;
status = "okay";
};
说明:
#pwm-cells = <2>
表示后续引用此 PWM 时,需提供channel
和period
reg
为寄存器地址,compatible
匹配对应控制器驱动
3.2 添加 PWM 消费者节点(如 LED)
led_pwm {
compatible = "pwm-leds";
pinctrl-names = "default";
pinctrl-0 = <&pwm_led_pin>;
led0 {
label = "user-led";
pwms = <&pwm_lpg 0 5000000>; // channel 0,周期 5ms
max-brightness = <255>;
brightness = <128>;
};
};
其中:
pwms
的格式为<控制器句柄 通道 周期>
brightness
为默认启动亮度,可通过echo
修改
3.3 IO 复用配置
pwm_led_pin: pwm-led-pin {
mux {
pins = "gpio48";
function = "gpio"; // 有些平台是 "pwm"
drive-strength = <2>;
bias-disable;
};
};
确保使用的 GPIO 被正确复用为 PWM 功能。
四、用户空间 PWM 调试方法(sysfs)
4.1 导出 PWM 通道
echo 0 > /sys/class/pwm/pwmchip0/export
注意:如果导出失败,检查内核是否已加载驱动,或该通道是否已被占用。
4.2 设置周期与占空比
echo 20000000 > /sys/class/pwm/pwmchip0/pwm0/period # 设置周期为 20ms
echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle # 设置高电平为 10ms(50% 占空比)
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable # 启用 PWM
4.3 停止 PWM 输出
echo 0 > /sys/class/pwm/pwmchip0/pwm0/enable
五、常见问题排查与调试技巧
问题描述 | 可能原因 |
---|---|
无波形输出 | IO 未复用成 PWM;GPIO 被占用或驱动未加载 |
设置 duty_cycle 报错 | duty_cycle 必须小于 period |
输出波形不稳定 | 检查供电与 IO 电平是否匹配 |
5.1 使用示波器观察波形
将示波器探头接到 PWM 输出脚,调节 duty_cycle 可观察波形宽度变化。
5.2 查看内核日志
使用 dmesg
命令查看是否有 PWM 相关错误或初始化信息:
dmesg | grep pwm
六、进阶:在内核驱动中使用 PWM API
在设备驱动中调用 PWM 接口实现控制流程:
#include <linux/pwm.h>
struct pwm_device *pwm;
pwm = pwm_get(dev, NULL);
pwm_config(pwm, duty_ns, period_ns); // 设置占空比和周期
pwm_enable(pwm); // 启用 PWM
// 释放资源
pwm_disable(pwm);
pwm_put(pwm);
提示:驱动中可通过设备树获取
pwm
资源,并进行生命周期管理。
七、总结
PWM 是嵌入式开发中常用的控制手段。本文以高通 QRB5165 为例,从设备树配置、sysfs 调试,到内核驱动集成,系统性地介绍了在 Linux 下调试 PWM 的完整流程。掌握这些方法,有助于高效验证硬件连接与软件逻辑,为复杂系统开发奠定基础。