PWM 驱动
本文档介绍 RK3588 PWM 控制器在 Linux 6.1 内核中的 sysfs(内核把设备状态映射成 /sys 下文件的接口,写文件就能改参数)控制方法和设备树配置。
适用范围: RK3588 Linux 6.1 Debian 12 / Ubuntu 22.04 系统,C-3588LQ V1.0 + SHIMETAPI-M5-R2A V1.0 底板。
1. 概念基础
1.1 PWM 是什么
PWM(Pulse Width Modulation,脉冲宽度调制)让引脚输出一串固定周期的方波,通过调节高电平在一个周期里所占的时间比例(占空比)来控制平均输出功率。RK3588 内置 16 路 PWM 控制器(RK3588S 为 12 路),特性:
- 32 位计数器
- APB 时钟分频
- 连续输出 / 单次脉冲
- 输入捕获测量
- 比较匹配中断 / 周期中断
1.2 应用场景
| 用途 | 说明 |
|---|---|
| 电机控制 | 直流电机、步进电机调速 |
| LED 调光 | 通过占空比调节亮度 |
| 蜂鸣器 | 有源 / 无源蜂鸣器 |
| 舵机 | 20ms 周期 + 1~2ms 高电平控制角度 |
| 电源管理 | DC-DC 反馈 |
1.3 控制器基地址
| 控制器 | 基地址 |
|---|---|
| PWM0 | 0xfd8b0000 |
| PWM1 | 0xfd8b0010 |
| PWM2 | 0xfd8b0020 |
| PWM3 | 0xfd8b0030 |
| PWM4-7 | 0xfe860000 + 0x10*n |
| PWM8-15 | 0xfe870000 + 0x10*n |
2. 准备工作
2.1 硬件清单
| 组件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | C-3588LQ 核心板 + SHIMETAPI-M5-R2A 底板 | 1 | |
| 调试串口线 | USB 转 TTL(3.3V) | 1 | 波特率 1500000 |
| LED 模块 | 5mm 发光二极管 | 1 | 用于 PWM 调光测试 |
| 示波器(可选) | 100 MHz+ | 1 | 用于观察波形 |
| 杜邦线 | 母对母 | 若干 |
2.2 引脚连接示例
以 PWM12(底板原理图中 LED 背光控制引脚)为例:
| 主控板引脚 | 外设引脚 | 功能说明 |
|---|---|---|
| PWM12(Sheet 8/21) | LED 正极 | PWM 调光输出 |
| GND | LED 负极 | 共地 |
实际操作请选择未被其他外设占用的 PWM 通道。
3. 软件准备
3.1 内核配置
CONFIG_PWM=y
CONFIG_PWM_ROCKCHIP=y /* RK3588 PWM 驱动 */
CONFIG_PWM_SYSFS=y /* 用户态 /sys/class/pwm 接口 */
CONFIG_OF=y驱动源码
drivers/pwm/pwm-rockchip.c。
3.2 设备树
SoC 级定义(rk3588.dtsi):
pwm0: pwm@fd8b0000 {
compatible = "rockchip,rk3588-pwm", "rockchip,rk3399-pwm";
reg = <0x0 0xfd8b0000 0x0 0x10>;
clocks = <&cru PCLK_PWM0>, <&cru CLK_PWM0>;
clock-names = "pclk", "clk";
#pwm-cells = <3>;
status = "okay"; /* 需在板级 dts enable */
};4. 设备端 PWM 操作
4.1 查看当前 PWM 控制器
ls /sys/class/pwm/实机输出如下:
pwmchip0
pwmchip1
pwmchip2
pwmchip3本机有 4 个 PWM 控制器(pwmchip0~3)。如需更多通道,应在 PC 端 DTS enable 对应 PWM。
# 查每个控制器支持的 PWM 通道数
for f in /sys/class/pwm/pwmchip*; do echo -n "$f: "; cat $f/npwm; done每个控制器的通道数输出:
/sys/class/pwm/pwmchip0: 1
/sys/class/pwm/pwmchip1: 1
/sys/class/pwm/pwmchip2: 1
/sys/class/pwm/pwmchip3: 14.2 导出 PWM 通道
和 GPIO 一样,PWM 通道要先导出,系统才会生成对应的操作目录:
# 导出 pwmchip0 的通道 0
echo 0 > /sys/class/pwm/pwmchip0/export4.3 设置周期与占空比
先设周期再设占空比,单位都是纳秒:
# 周期(纳秒):1kHz = 1,000,000 ns
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period
# 占空比:500,000 ns = 50%
echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle4.4 使能与禁用
参数设好后使能输出,波形才会真正出现在引脚上:
# 使能输出
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
# 调光:25% 亮度
echo 250000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
# 调光:75% 亮度
echo 750000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
# 禁用输出
echo 0 > /sys/class/pwm/pwmchip0/pwm0/enable
# 释放通道
echo 0 > /sys/class/pwm/pwmchip0/unexport4.5 查看 PWM 当前状态
cat /sys/class/pwm/pwmchip0/pwm0/period
cat /sys/class/pwm/pwmchip0/pwm0/duty_cycle
cat /sys/class/pwm/pwmchip0/pwm0/enable # 0 / 1
cat /sys/class/pwm/pwmchip0/pwm0/polarity # normal / inversed4.6 PWM 时钟源频率
cat /sys/kernel/debug/clk/clk_pwm/clk_rate5. PWM 输入捕获
RK3588 PWM 支持输入模式,可以捕获外部信号的周期 / 占空比:
5.1 PC 端 DTS 配置输入捕获
&pwm0 {
status = "okay";
/* 配置为输入捕获模式 */
pinctrl-0 = <&pwm0_input_pins>;
};5.2 设备端读取输入信号
echo 0 > /sys/class/pwm/pwmchip0/export
echo 0 > /sys/class/pwm/pwmchip0/pwm0/polarity # normal / inversed
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
# 周期 / 占空比
cat /sys/class/pwm/pwmchip0/pwm0/period
cat /sys/class/pwm/pwmchip0/pwm0/duty_cycle6. 设备树配置引用
[电脑端] 板级 .dts 中配置 PWM 输出(LED 调光示例):
/* PWM12 复用为 LED 背光 */
&pwm12 {
status = "okay";
pinctrl-0 = <&pwm12m0_pins>;
};
&backlight {
pwms = <&pwm12 0 5000000 0>; /* period = 5 ms, duty = 0 */
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
};[电脑端] 重新编译并烧录:
./build.sh kernel
./mkfirmware.sh
# 用 RKDevTool 烧录 boot.img7. 代码解读
7.1 驱动注册
// drivers/pwm/pwm-rockchip.c(简化)
static struct platform_driver rockchip_pwm_driver = {
.probe = rockchip_pwm_probe,
.remove = rockchip_pwm_remove,
.driver = {
.name = "rockchip-pwm",
.of_match_table = rockchip_pwm_match,
},
};
static const struct of_device_id rockchip_pwm_match[] = {
{ .compatible = "rockchip,rk3588-pwm" },
{ /* sentinel */ }
};7.2 sysfs 调用链
用户空间: echo 0 > /sys/class/pwm/pwmchip1/export
→ pwm_export_store()
→ pwm_request()
→ rockchip_pwm_request() /* 申请通道 */
→ 配置 PWM 时钟 / 占空比寄存器
用户空间: echo 1 > .../pwm0/enable
→ pwm_enable_store()
→ pwm_enable()
→ rockchip_pwm_enable()
→ 启动定时器输出8. 故障排除
8.1 export 失败
现象:echo 0 > /sys/class/pwm/pwmchip0/export 报错。
先检查节点状态和通道占用:
# 设备树节点 status 是否为 okay
cat /proc/device-tree/soc/pwm@fd8b0000/status
# 通道是否已被占用
cat /sys/kernel/debug/pwm8.2 频率不正确
现象:实际频率 ≠ 设定值。
先看时钟源频率:
cat /sys/kernel/debug/clk/clk_pwm/clk_ratePWM 频率 ≈ 时钟源频率 / (prescaler × period)。调整
period或 DTS 中的 prescaler。
8.3 波形异常
按下面的顺序排查:
- pinctrl 中 PWM 引脚功能是否正确(不能被占用)
- 示波器验证 SCK 占空比
- 检查电压域(1.8V / 3.3V)是否与 LED 一致
