/sys/class/pwm/ 是统一入口,需先检查 pwmchip* 目录确认控制器存在,再 export 通道,最后按顺序设置 period 和 duty_cycle(单位 ns),且需 root 权限与硬件配置匹配。

sysfs 节点路径怎么找对 PWM 设备
Linux 内核 4.8+ 的 PWM 子系统默认通过 sysfs 暴露接口,但路径不是固定的,得先确认硬件是否已由内核驱动正确识别。常见错误是直接去 /sys/class/pwm/ 目录下硬找,结果为空——这通常意味着 PWM 控制器没被启用或设备树没配对。
先查控制器是否存在:
ls /sys/class/pwm/如果为空,再看底层控制器节点:
ls /sys/class/pwm/pwmchip*正常会有类似
pwmchip0、pwmchip1 的目录。每个 pwmchipN 下的 npwm 文件会告诉你该控制器支持几个通道,比如:cat /sys/class/pwm/pwmchip0/npwm输出
2 表示有 2 个可用 PWM 输出口。
- 必须确保设备树中对应 PWM 控制器节点的
status = "okay",且子节点(如pwm@0)已正确定义pwms属性 - 某些 SoC(如 i.MX6ULL)需要额外使能
CONFIG_PWM_IMX或CONFIG_PWM_SUNXI等内核配置项,否则即使设备树写了也无节点 -
/sys/class/pwm/是统一入口,但实际通道需先echo 0 > /sys/class/pwm/pwmchip0/export才会生成pwm0子目录——不 export 就没有可操作节点
export 后怎么设置周期和占空比
PWM 通道导出后,比如 /sys/class/pwm/pwmchip0/pwm0/,关键参数只有两个:周期(period)和占空比(duty_cycle),单位都是纳秒(ns)。注意:必须先设 period,再设 duty_cycle,且 duty_cycle ≤ period,否则写入失败并报错 Invalid argument。
例如想输出 1kHz、50% 占空比的方波:
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period<br>echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
-
period和duty_cycle都只接受十进制整数,不能带单位后缀(如 ms、us) - 最小周期受硬件限制,比如某些 ARM PWM 控制器最低只能到 100ns;超出范围会返回
Operation not supported - 写入
duty_cycle前必须保证enable是 0(未启用),否则会提示Device or resource busy - 修改
period时,如果当前已启用,需先echo 0 > enable,改完再echo 1 > enable
C++ 怎么安全地读写这些 sysfs 文件
用 std::ofstream 或 write() 写 sysfs 是可行的,但必须处理三类典型失败:权限不足(需 root)、写入格式错误(如字符串含空格或换行)、目标文件不存在(比如忘记 export 或硬件未就绪)。
推荐封装一个最小可用函数,避免裸写:
bool set_pwm_param(const std::string& path, long long value) {<br> std::ofstream f(path);<br> if (!f.is_open()) return false;<br> f return f.good();<br>}调用时:set_pwm_param("/sys/class/pwm/pwmchip0/pwm0/period", 1000000LL);<br>set_pwm_param("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", 500000LL);
- 务必检查
f.good(),而不是只看is_open()—— 写入失败时流仍可能处于打开状态 - 不要用
std::filesystem::exists()判断节点是否存在,它可能因内核延迟返回 false;应直接尝试 open 并捕获 errno(如ENOENT) - 所有 sysfs 写操作都应以
\n结尾,否则部分内核版本会静默忽略 - 频繁开关 PWM(如做呼吸灯)时,避免反复
export/unexport,复用已导出的通道更可靠
为什么 echo 1 > enable 没反应或立刻变回 0
最常见原因是硬件级约束未满足:比如引脚复用冲突(同一引脚被 GPIO 或其他外设占用)、PWM 时钟未使能、或内核模块加载顺序问题。现象是写入 enable 后立即读回来仍是 0,且无任何错误日志。
排查步骤:
dmesg | grep -i pwm看是否有 “cannot request PWM”、“clock not enabled” 类提示;再检查引脚复用:
cat /sys/kernel/debug/pinctrl/*/pins | grep your_pin_name
- 某些平台(如 Allwinner H3)要求在 export 前先向
pwmchipN/device/下写入特定值(如echo 1 > pwmchip0/device/enable),文档极少提及 - 如果使用 devicetree overlay,确认 overlay 已成功加载:
cat /proc/device-tree/chosen/overlay_names - sysfs 接口本身不校验电压/负载能力,但过低周期或过高占空比可能触发硬件保护,导致自动禁用
真实嵌入式场景里,PWM 初始化失败往往不是代码写错,而是设备树、内核配置、引脚定义这三个环节中某一处没对齐——得从 dmesg 往回推,而不是盯着 C++ 代码改。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











