1. 项目背景与核心价值
在嵌入式系统开发中,PWM(脉冲宽度调制)技术堪称"万能工具"。从调节LED亮度到控制电机转速,从电源管理到音频模拟,PWM的应用几乎无处不在。这次我们在RK平台(瑞芯微系列芯片)上实战PWM驱动开发,目标直指两个经典应用场景:LED呼吸灯效果和直流电机调速。
为什么选择RK平台?作为国产芯片的佼佼者,RK3566/RK3588等芯片在智能硬件领域占据重要地位。其PWM控制器通常支持多通道输出,具备灵活的分频配置和占空比调节能力,非常适合需要精确时序控制的场景。通过本次实战,你将掌握:
- 如何在内核中正确配置PWM控制器
- 编写符合Linux PWM子系统规范的驱动
- 实现用户空间与内核的交互控制
- 调试PWM输出波形的实用技巧
提示:实际操作前请确认开发板原理图,明确PWM引脚复用情况。我曾遇到过因引脚冲突导致PWM无法输出的情况,排查了整整一天!
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 硬件环境准备
2.1 硬件选型要点
本次实验以RK3568开发板为例,其PWM控制器主要特性如下:
| 特性 | 参数 | 备注 |
|---|---|---|
| 通道数 | 4 | PWM0-PWM3 |
| 时钟源 | 24MHz | 可软件分频 |
| 分辨率 | 16bit | 占空比调节精度 |
| 输出极性 | 可编程 | 正常/反转 |
所需外设:
- LED模块:普通GPIO LED即可,需串联限流电阻(通常220Ω)
- 电机驱动:建议使用L298N等H桥驱动模块
- 示波器:用于验证波形(非必须但推荐)
2.2 电路连接注意事项
-
LED连接:
- PWM输出引脚 → 限流电阻 → LED阳极
- LED阴极接地
- 典型接线示例:PWM0 → R220 → LED → GND
-
电机连接:
- PWM输出 → 驱动模块信号输入
- 驱动模块电源独立供电(与开发板共地)
- 启用死区控制防止短路(硬件或软件实现)
重要:务必确认PWM引脚电压与外围器件匹配。我有次烧毁电机驱动就是因为忽略了3.3V与5V电平转换。
3. 内核驱动开发
3.1 PWM子系统框架解析
Linux内核的PWM子系统采用控制器-设备分层设计:
code复制用户空间
│
▼
/sys/class/pwm/ ← PWM控制接口
│
▼
PWM core ← 核心框架
│
▼
PWM控制器驱动 ← 芯片相关实现
关键数据结构:
c复制struct pwm_chip {
struct device *dev;
const struct pwm_ops *ops;
int base;
unsigned int npwm;
};
struct pwm_device {
const char *label;
unsigned int hwpwm;
unsigned int pwm;
struct pwm_chip *chip;
};
3.2 RK平台PWM驱动实现
驱动开发主要步骤:
- 设备树配置:
dts复制pwm: pwm@ff420000 {
compatible = "rockchip,rk3568-pwm";
reg = <0x0 0xff420000 0x0 0x10>;
clocks = <&cru CLK_PWM1>, <&cru PCLK_PWM1>;
clock-names = "pwm", "pclk";
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pins>;
#pwm-cells = <3>;
status = "okay";
};
- 驱动代码关键函数:
c复制static const struct pwm_ops rk_pwm_ops = {
.apply = rk_pwm_apply,
.get_state = rk_pwm_get_state,
.owner = THIS_MODULE,
};
static int rk_pwm_probe(struct platform_device *pdev)
{
struct rk_pwm_chip *pc;
pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
pc->chip.dev = &pdev->dev;
pc->chip.ops = &rk_pwm_ops;
pc->chip.npwm = 4;
// 时钟和寄存器配置
pc->clk = devm_clk_get(&pdev->dev, "pwm");
pc->pclk = devm_clk_get(&pdev->dev, "pclk");
return pwmc
