
清空记录
历史记录
取消
清空记录
历史记录

本系列PWM驱动教程,基于触觉智能RK3576开发板Purple Pi OH2进行讲解与真机调试。
PWM驱动开发
代码如下:
#include#include struct my_pwm_dev { struct pwm_device *pwm; struct device *dev;};/* 申请 PWM */static int my_pwm_probe(struct platform_device *pdev){ struct my_pwm_dev *priv; struct pwm_state state; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = &pdev->dev; /* 从设备树获取 PWM */ priv->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(priv->pwm)) { ret = PTR_ERR(priv->pwm); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to get PWM: %d\n", ret); return ret; } /* 配置 PWM 参数 */ pwm_init_state(priv->pwm, &state); /* 设置周期:25000ns = 40KHz */ state.period = 25000; /* 设置占空比:50% */ state.duty_cycle = 12500; /* 使能 PWM */ state.enabled = true; ret = pwm_apply_state(priv->pwm, &state); if (ret) { dev_err(&pdev->dev, "Failed to apply PWM state: %d\n", ret); return ret; } dev_info(&pdev->dev, "PWM initialized: period=%u, duty=%u\n", state.period, state.duty_cycle); platform_set_drvdata(pdev, priv); return 0;}/* 设置占空比 */static int my_pwm_set_duty(struct my_pwm_dev *priv, unsigned int duty_percent){ struct pwm_state state; u64 duty_cycle; int ret; if (duty_percent > 100) return -EINVAL; pwm_get_state(priv->pwm, &state); /* 计算新的占空比 */ duty_cycle = (u64)state.period * duty_percent; do_div(duty_cycle, 100); state.duty_cycle = duty_cycle; state.enabled = (duty_percent > 0); ret = pwm_apply_state(priv->pwm, &state); if (ret) dev_err(priv->dev, "Failed to set PWM duty: %d\n", ret); return ret;}/* LED 调光函数 */static int my_pwm_set_brightness(struct my_pwm_dev *priv, int brightness){ /* brightness: 0-255 */ int duty = (brightness * 100) / 255; return my_pwm_set_duty(priv, duty);}static int my_pwm_remove(struct platform_device *pdev){ struct my_pwm_dev *priv = platform_get_drvdata(pdev); /* 禁用 PWM */ pwm_disable(priv->pwm); return 0;}static const struct of_device_id my_pwm_of_match[] = { { .compatible = "mycompany,my-pwm-device", }, { }};static struct platform_driver my_pwm_driver = { .probe = my_pwm_probe, .remove = my_pwm_remove, .driver = { .name = "my-pwm", .of_match_table = my_pwm_of_match, },};module_platform_driver(my_pwm_driver);MODULE_LICENSE("GPL");
配置代码如下:
# 导出 PWM(如果内核支持 sysfs 接口)echo 0 > /sys/class/pwm/pwmchip0/export# 设置周期(ns)echo 25000 > /sys/class/pwm/pwmchip0/pwm0/period# 设置占空比(ns)echo 12500 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle# 使能 PWMecho 1 > /sys/class/pwm/pwmchip0/pwm0/enable# 修改占空比echo 5000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle # 20%echo 20000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle # 80%# 禁用 PWMecho 0 > /sys/class/pwm/pwmchip0/pwm0/enable
配置代码如下:
#include#include #include #include #include #define PWM_PATH "/sys/class/pwm/pwmchip0/pwm0"int pwm_write(const char *file, const char *val){ char path[256]; int fd; snprintf(path, sizeof(path), "%s/%s", PWM_PATH, file); fd = open(path, O_WRONLY); if (fd < 0) { perror("open"); return -1; } if (write(fd, val, strlen(val)) < 0) { perror("write"); close(fd); return -1; } close(fd); return 0;}int main(int argc, char *argv[]){ int duty; char buf[32]; if (argc < 2) { printf("Usage: %s \n", argv[0]); return -1; } duty = atoi(argv[1]); if (duty < 0 || duty > 100) { printf("Duty must be 0-100\n"); return -1; } /* 设置周期 25us (40KHz) */ pwm_write("period", "25000"); /* 设置占空比 */ snprintf(buf, sizeof(buf), "%d", duty * 250); pwm_write("duty_cycle", buf); /* 使能 PWM */ pwm_write("enable", "1"); printf("PWM set to %d%% duty cycle\n", duty); return 0;}
配置代码如下:
/ { /* 温度传感器 */ thermal-zones { cpu_thermal: cpu-thermal { polling-delay-passive = <250>; /* 被动轮询间隔 */ polling-delay = <1000>; /* 主动轮询间隔 */ /* 热传感器 */ thermal-sensors = <&tsadc 0>; trips { cpu_cool: cpu-cool { temperature = <55000>; /* 55°C */ hysteresis = <5000>; type = "active"; }; cpu_hot: cpu-hot { temperature = <70000>; /* 70°C */ hysteresis = <5000>; type = "active"; }; cpu_crit: cpu-crit { temperature = <95000>; /* 95°C */ hysteresis = <2000>; type = "critical"; }; }; cooling-maps { map0 { trip = <&cpu_cool>; cooling-device = <&fan THERMAL_NO_LIMIT 1>; }; map1 { trip = <&cpu_hot>; cooling-device = <&fan 2 THERMAL_NO_LIMIT>; }; }; }; };};
温度控制风扇实现
设备树温控配置如下,实现温度与风扇转速的联动调控:
/ { /* 温度传感器 */ thermal-zones { cpu_thermal: cpu-thermal { polling-delay-passive = <250>; /* 被动轮询间隔 */ polling-delay = <1000>; /* 主动轮询间隔 */ /* 热传感器 */ thermal-sensors = <&tsadc 0>; trips { cpu_cool: cpu-cool { temperature = <55000>; /* 55°C */ hysteresis = <5000>; type = "active"; }; cpu_hot: cpu-hot { temperature = <70000>; /* 70°C */ hysteresis = <5000>; type = "active"; }; cpu_crit: cpu-crit { temperature = <95000>; /* 95°C */ hysteresis = <2000>; type = "critical"; }; }; cooling-maps { map0 { trip = <&cpu_cool>; cooling-device = <&fan THERMAL_NO_LIMIT 1>; }; map1 { trip = <&cpu_hot>; cooling-device = <&fan 2 THERMAL_NO_LIMIT>; }; }; }; };};红外遥控使用 NEC 协议传输数据,载波频率通常为 38KHz。NEC 协议帧结构:
# 查看 PWM 设备ls /sys/class/pwm/# 查看 PWM 状态cat /sys/kernel/debug/pwm# 查看背光状态cat /sys/class/backlight/backlight/brightnesscat /sys/class/backlight/backlight/max_brightness
数据如下:
# PWM 参数计算# 频率 = 1 / 周期(s)# 占空比 = 高电平时间 / 周期 × 100%# 25KHz 风扇 PWM周期 = 40us = 40000ns# 50% 占空比高电平时间 = 20us
配置代码如下:
# 配置 PWMpwm-tool -d /sys/class/pwm/pwmchip0/pwm0 \ -p 25000 -c 12500 -e# 调整占空比pwm-tool -d /sys/class/pwm/pwmchip0/pwm0 -c 20000
配置代码如下:
# 查看红外设备状态ir-keytable# 实时监控按键事件ir-keytable -t# 发送 NEC 红外码ir-ctl -d /dev/lirc0 --send=nec:0x12ff01# 查看 rc-core 调试信息cat /sys/kernel/debug/ir_raw_event# 验证红外接收/发射回路# 终端 1: ir-keytable -t# 终端 2: ir-ctl -d /dev/lirc0 --send=nec:0x12ff01# 观察终端 1 是否收到事件
如图所示:
•检查 GPIO 极性是否正确(GPIO_ACTIVE_LOW)
•确认 rc-core 驱动已加载(lsmod | grep gpio_ir)
•使用ir-keytable -t 查看原始事件
•确认红外接收头供电正常(通常 3.3V)
•检查设备树status = "okay"
•确认 pinctrl 配置正确
•验证 PWM 时钟是否使能
•检查 PWM 时钟源精度
•周期值是否过小而超出分辨率
•PWM 频率是否合适(通常 25KHz)
•检查风扇 PWM 输入类型(正逻辑/负逻辑)
•确认最小启动占空比
•确认 PWM 处于禁用状态(不能同时输出和捕获)
•检查外部信号是否有足够的边沿变化
•超时值是否设置过小(建议 >= 100ms)
•确认 PWM 引脚已正确配置为输入模式
•确认CONFIG_RC_CORE=y 已启用
•检查设备树中rockchip,pwm-ir-transmit 属性
•PWM 引脚是否连接到 IR LED
•使用示波器验证 PWM 引脚是否有 38KHz 载波输出
•RKDocs/common/PWM/
•Documentation/devicetree/bindings/pwm/pwm.txt
•Documentation/devicetree/bindings/media/gpio-ir-receiver.yaml
•Documentation/devicetree/bindings/rc/rc.yaml
•drivers/pwm/pwm-rockchip.c — Rockchip PWM 驱动(Capture + IR 发射)
•drivers/media/rc/gpio-ir-recv.c — GPIO IR 接收驱动
•include/linux/pwm.h — PWM 子系统 API 头文件
•include/media/rc-core.h — rc-core 子系统 API
本教程适用于 Purple Pi OH2 (RK3576) 开发板,基于 Android 14 / Linux 6.1 内核
产品简介
