Linux PWM (脉冲宽度调制) 全面技术指南
目录
- 技术原理深度解析
- Linux PWM 子系统架构
- 用户空间控制 (Sysfs)
- 内核驱动开发实践
- 应用场景案例
- 附录
1. 技术原理深度解析
1.1 什么是 PWM?
PWM (Pulse Width Modulation) ,即脉冲宽度调制,是一种利用数字信号控制模拟电路的技术。它通过快速开关电源输出,在负载上产生一个平均电压,从而实现对功率的连续控制。
1.2 核心概念与公式

图1:PWM波形参数示意图
- 周期 (Period, TTT): 脉冲信号重复一次所需的时间。单位通常为纳秒(ns)。
- 频率 (Frequency, fff) : 每秒钟脉冲重复的次数。f=1/Tf = 1/Tf=1/T。
- 占空比 (Duty Cycle, DDD) : 高电平持续时间 (TonT_{on}Ton) 与整个周期 (TTT) 的比值。
D=TonT×100% D = \frac{T_{on}}{T} \times 100\% D=TTon×100% - 平均电压 (VavgV_{avg}Vavg) : 输出到负载上的等效电压。
Vavg=Vcc×D V_{avg} = V_{cc} \times D Vavg=Vcc×D
1.3 功率控制原理
当PWM频率足够高时(超过负载的响应时间),负载(如电机或LED)不会看到电压的快速切换,而是看到一个稳定的平均电压。
- LED: 调节占空比 = 调节电流有效值 = 调节亮度。
- 电机: 调节占空比 = 调节电枢电压 = 调节转速/扭矩。
2. Linux PWM 子系统架构
Linux内核通过通用的PWM子系统(PWM Subsystem)来管理不同SoC的PWM控制器,为上层驱动和用户空间提供统一的接口。

图2:Linux PWM子系统架构图
2.1 核心组件
- Consumer Drivers : 使用PWM功能的内核驱动(如
leds-pwm,pwm-beeper,pwm-fan)。 - PWM Core : 核心层 (
drivers/pwm/core.c),提供pwm_get,pwm_config,pwm_enable等API,并管理Sysfs接口。 - Chip Drivers : SoC厂商提供的具体硬件驱动(如
pwm-rockchip.c,pwm-imx.c),实现pwm_ops回调函数。
2.2 设备树 (DTS) 配置
在Device Tree中,PWM控制器通常作为提供者(Provider),具体设备(如背光)作为消费者(Consumer)。
Provider (SoC端):
dts
pwm0: pwm@ff1b0020 {
compatible = "rockchip,rk3399-pwm";
reg = <0x0 0xff1b0020 0x0 0x10>;
#pwm-cells = <3>; /* cell 0: channel, cell 1: period, cell 2: polarity */
status = "okay";
};
Consumer (板级端 - LED):
dts
backlight {
compatible = "pwm-backlight";
pwms = <&pwm0 0 25000 0>; /* Channel 0, Period 25000ns (40kHz), Normal Polarity */
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
};
3. 用户空间控制 (Sysfs)
对于没有特定内核驱动接管的PWM通道,用户可以通过 /sys/class/pwm/ 接口直接控制。这在调试或简单应用中非常有用。
3.1 接口详解
路径: /sys/class/pwm/pwmchipN/ (N为控制器编号)
- export : 写入通道号(如0)以导出对应的
pwm0目录。 - pwmX/period: 设置周期(纳秒)。
- pwmX/duty_cycle: 设置高电平时间(纳秒)。必须小于周期。
- pwmX/polarity : 设置极性 (
normal或inversed)。 - pwmX/enable: 写入1使能,写入0禁止。
3.2 操作示例 (Shell脚本)
bash
# 1. 导出 pwmchip0 的通道 0
echo 0 > /sys/class/pwm/pwmchip0/export
# 2. 设置周期为 1ms (1,000,000 ns) -> 1kHz
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period
# 3. 设置占空比为 50% (500,000 ns)
echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
# 4. 使能 PWM
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

图3:示波器实测波形 (50% Duty Cycle)
4. 内核驱动开发实践
编写一个使用PWM控制风扇的简单平台驱动。
4.1 驱动代码示例
c
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/slab.h>
struct my_pwm_fan {
struct pwm_device *pwm;
u32 period_ns;
};
static int my_pwm_fan_probe(struct platform_device *pdev)
{
struct my_pwm_fan *fan;
int ret;
fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
if (!fan) return -ENOMEM;
/* 1. 获取 PWM 设备 (对应DTS中的 pwms 属性) */
fan->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(fan->pwm)) {
dev_err(&pdev->dev, "Failed to get pwm\n");
return PTR_ERR(fan->pwm);
}
/* 2. 设置初始参数: 周期 20ms (50Hz), 占空比 0 */
fan->period_ns = 20000000;
pwm_set_period(fan->pwm, fan->period_ns);
/* 3. 配置并使能 (初始转速 50%) */
ret = pwm_config(fan->pwm, fan->period_ns / 2, fan->period_ns);
if (ret < 0) return ret;
ret = pwm_enable(fan->pwm);
if (ret < 0) return ret;
platform_set_drvdata(pdev, fan);
dev_info(&pdev->dev, "PWM Fan initialized\n");
return 0;
}
static int my_pwm_fan_remove(struct platform_device *pdev)
{
struct my_pwm_fan *fan = platform_get_drvdata(pdev);
if (fan->pwm) {
pwm_disable(fan->pwm);
}
return 0;
}
static const struct of_device_id my_pwm_fan_match[] = {
{ .compatible = "vendor,my-pwm-fan" },
{ },
};
MODULE_DEVICE_TABLE(of, my_pwm_fan_match);
static struct platform_driver my_pwm_fan_driver = {
.probe = my_pwm_fan_probe,
.remove = my_pwm_fan_remove,
.driver = {
.name = "my-pwm-fan",
.of_match_table = my_pwm_fan_match,
},
};
module_platform_driver(my_pwm_fan_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AI Assistant");
MODULE_DESCRIPTION("Simple PWM Fan Driver");
4.2 关键API说明
devm_pwm_get(): 从设备树获取PWM句柄。pwm_config(pwm, duty_ns, period_ns): 核心配置函数。注意这里的周期参数可能会覆盖pwm_set_period的设置。pwm_enable() / pwm_disable(): 开启/关闭PWM信号输出。
5. 应用场景案例
5.1 电机控制 (H桥驱动)
对于直流电机,通常使用PWM控制其转速。结合H桥电路,可以实现正反转。
- 方案: 两个PWM通道连接H桥的两个输入端。
- 正转: PWM1输出波形,PWM2低电平。
- 反转: PWM1低电平,PWM2输出波形。
- 调速: 改变占空比。
5.2 呼吸灯 (Breathing LED)
利用人眼视觉暂留效应,动态连续改变占空比。
- 算法: 使用正弦函数或指数函数生成占空比序列(Gamma校正),使亮度变化符合人眼感知线性度。
5.3 动态电压调节 (DVS)
在PMIC(电源管理芯片)中,通过PWM反馈控制Buck电路的输出电压。
- 原理: 占空比越高 -> 反馈电压越高 -> PMIC输出电压越低(或越高,取决于电路拓扑)。这常用于CPU的DVFS(动态电压频率调整)。
6. 附录
参考文献
- Kernel Documentation :
Documentation/pwm.txt - Device Tree Bindings :
Documentation/devicetree/bindings/pwm/ - Source Code :
include/linux/pwm.h