RK3576开发板PWM驱动教程(上)触觉智能开发板演示基础原理/设备树/红外收发捕获解析

图片

本篇作为基础上篇,先系统梳理PWM核心概念,重点拆解 RK3576平台PWM标准设备树配置方法,同时结合板载外设实操PWM脉冲捕获功能,延伸实现GPIO红外接收、PWM 调制红外发射两大常用案例,打好硬件配置与脉冲信号采集的理论实操基础,下篇再深入内核驱动开发、温控风扇项目落地与全套调试排错方案。

PWM的基本概率与工作原理

  • PWM是什么

PWM(Pulse Width Modulation,脉冲宽度调制)是一种数字信号技术,通过改变脉冲的占空比来控制平均电压。

  • PWM关键参数

参数

说明

典型应用

周期(T)

一个完整脉冲的时间

控制精度

占空比

高电平时间占比

LED亮度、电机速度

频率

每秒脉冲数

避免人耳可闻噪声

  • 触觉智能Purple Pi OH2 PWM的应用

Fan(风扇):PWM调速

Backlight(背光):PWM调光

Speaker:PWM音频(部分实现)

IR Remote(红外遥控):PWM红外发射/ GPIO红外接收

  • RK3576多路PWM资源说明

•pwm0~pwm7:常规PWM(支持输出、Capture、IR发射)

•pwm1_6ch_*:6通道PWM(用于背光等)

高级功能:波形发生器、频率计、Counter输入、Capture模式、IR发射

  • PWM工作原理-占空比控制

不同占空比直观展示:

25%占空比:██░░░░░░

50%占空比:████░░░░

75%占空比:██████░░

100%占空比:████████

  • PWM在Linux中的实现

用户空间通过ioctl/write操作PWM子系统,PWM子系统配置控制器寄存器,控制器输出波形至外部设备;外部设备在Capture模式下可将信号参数回传给控制器,GPIO IR接收头则通过rc-core子系统处理信号。附整体架构图

图片

PWM设备树配置

  • 使能PWM控制器

需编辑触觉智能Purple Pi OH的SDK的ido-evb7609-v1a-mipi.dtsi,配置代码如下:

&pwm1_6ch_5 { status = "okay"; };

  • 添加背光设备

配置代码如下:

/ { /* 背光设备 */ backlight: backlight { compatible = "pwm-backlight"; pwms = <&pwm1_6ch_5 0 25000 0>; /* PWM, channel, period(ns), polarity */ /* 亮度等级表 */ brightness-levels = < 0 20 20 21 21 22 22 23 23 24 24 25 25 26 26 27 /* ... 更多等级 ... */ 248 249 250 251 252 253 254 255 >; default-brightness-level = <200>; /* 电源控制 */ enable-gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_HIGH>; }; /* 风扇 PWM 控制 */ fan: pwm-fan { compatible = "pwm-fan"; pwms = <&pwm2 0 40000 0>; /* 25KHz PWM 频率 */ /* 温度与转速曲线 */ cooling-levels = <0 100 150 200 255>; #cooling -cells = <2>; }; };

  • Pinctrl配置

配置代码如下:

&pinctrl { pwm1 { pwm1m0_pins: pwm1m0-pins { rockchip,pins = <1 RK_PB6 2 &pcfg_pull_none>; }; }; pwm2 { pwm2m0_pins: pwm2m0-pins { rockchip,pins = <1 RK_PB7 2 &pcfg_pull_none>; }; }; };

图片

PWM脉冲捕获

  • 什么是PWM Capture?

PWM Capture式将PWM引脚从输出切换为输入,用于捕获外部信号的周期和占空比,是PWM控制器的双向能力。

  • RK3576 Capture工作原理

RK3576的PWM控制器(v4版本)实现Capture流程:

图片

1.将PWM引脚配置为输入模式(PWM_IN_SEL)

2.使能边沿检测中断(CAP_LPR_INT低电平周期中断、CAP_HPR_INT高电平周期中断)

3.硬件自动将高/低电平时间分别写入HPC(High Period Counter)和LPC(Low Period Counter)寄存器

4.驱动读取寄存器并计算为纳秒值

1.将PWM引脚配置为输入模式(PWM_IN_SEL)

2.使能边沿检测中断(CAP_LPR_INT低电平周期中断、CAP_HPR_INT高电平周期中断)

3.硬件自动将高/低电平时间分别写入HPC(High Period Counter)和LPC(Low Period Counter)寄存器

4.驱动读取寄存器并计算为纳秒值

  • 内核空间Capture API

配置代码如下:

#include struct pwm_capture { unsigned int period; /* 捕获到的周期 (ns) */ unsigned int duty_cycle; /* 捕获到的占空比 (ns) */ }; /* 捕获外部 PWM 信号 */ int pwm_capture(struct pwm_device *pwm, struct pwm_capture *result, unsigned long timeout);

  • Capture驱动示例

配置代码如下:

#include #include #include struct my_pwm_capture_dev { struct pwm_device *pwm; struct device *dev; }; static int my_capture_probe(struct platform_device *pdev) { struct my_pwm_capture_dev *priv; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = &pdev->dev; /* 获取 PWM 设备(与 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; } platform_set_drvdata(pdev, priv); dev_info(&pdev->dev, "PWM capture device initialized\n"); return 0; } /* 读取捕获结果 */ static int my_capture_read(struct my_pwm_capture_dev *priv, unsigned int *period_ns, unsigned int *duty_ns) { struct pwm_capture result; int ret; /* 捕获外部信号,超时 100ms */ ret = pwm_capture(priv->pwm, &result, 100); if (ret) { dev_err(priv->dev, "Failed to capture PWM: %d\n", ret); return ret; } *period_ns = result.period; *duty_ns = result.duty_cycle; dev_info(priv->dev, "Captured: period=%uns, duty=%uns\n", result.period, result.duty_cycle); return 0; } /* 计算频率和占空比百分比 */ static void my_capture_calc_freq_duty(unsigned int period_ns, unsigned int duty_ns, unsigned int *freq_hz, unsigned int *duty_pct) { if (period_ns == 0) return; *freq_hz = 1000000000 / period_ns; *duty_pct = (duty_ns * 100) / period_ns; } static int my_capture_remove(struct platform_device *pdev) { return 0; } static const struct of_device_id my_capture_of_match[] = { { .compatible = "mycompany,my-pwm-capture", }, { } }; static struct platform_driver my_capture_driver = { .probe = my_capture_probe, .remove = my_capture_remove, .driver = { .name = "my-pwm-capture", .of_match_table = my_capture_of_match, }, }; module_platform_driver(my_capture_driver); MODULE_LICENSE("GPL");

  • Capture注意事项

要点

说明

PWM不能同时输出和捕获

Capture模式下PWM必须处于禁用状态

超时设置

建议100ms,过短可能导致无中断触发而超时

时钟精度

捕获精度取决于PWM控制器的输入时钟频率

pinctrl复用

Capture复用同一PWM引脚,无需额外pinctrl配置

RK3576支持

PWM v3/v4均支持Capture模式

GPIO IR 红外接收与发射

  • 红外遥控基础

红外遥控使用 NEC 协议传输数据,载波频率通常为 38KHz。NEC 协议帧结构:引导码(9ms高+4.5ms低) + 地址码(8bit) + 地址反码(8bit) + 命令码(8bit) + 命令反码(8bit)

逻辑

编码方式

逻辑"0"

560μs高+ 560μs低(总1.12ms)

逻辑"1"

560μs高+ 1.69ms低(总2.25ms)

重复码

9ms高+ 2.25ms低+ 560μs高

NEC协议时序图示意图:

图片

  • Linux rc-core 子系统

Linux 通过 rc-core 子系统统一管理红外遥控,支持 NEC、NEC32、RC-5、RC-6、Sony SIRC、JVC、Sharp、XMP 等协议。

  • 红外接收的设备树与内核配置

设备树配置代码如下:

/ { /* GPIO 红外接收头 */ ir_receiver: ir-receiver { compatible = "gpio-ir-receiver"; gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>; linux,rc-map-name = "rc-rc6-mce"; /* 使用预定义的按键映射 */ linux,autosuspend-period = <125>; /* 自动挂起延迟 (ms) */ }; };

属性

说明

必填

compatible

必须为"gpio-ir-receiver"

gpios

红外接收头连接的GPIO

linux,rc-map-name

按键映射表名称

否(默认使用rc-empty-map

linux,autosuspend-period

自动挂起延迟(ms)

确保以下内核配置已启用:

CONFIG_RC_CORE=y CONFIG_GPIO_IR_RECEIVER=m # 或 y CONFIG_RC_DECODERS=y # 包含 NEC、RC5、RC6 等解码器 CONFIG_RC_MAP=y

  • 自定义按键映射表

创建/etc/rc_keymaps/my_remote.map,配置代码如下:

# 按键映射表格式:scancode keycode # scancode: 遥控器发送的原始 NEC 码 # keycode: 映射到的 Linux 按键 0x12ff01 KEY_POWER 0x12ff02 KEY_VOLUMEUP 0x12ff03 KEY_VOLUMEDOWN 0x12ff04 KEY_UP 0x12ff05 KEY_DOWN 0x12ff06 KEY_LEFT 0x12ff07 KEY_RIGHT 0x12ff08 KEY_ENTER

加载映射表:

iir-keytable -c # 清除现有映射 ir-keytable -p NEC -p RC-6 # 启用解码协议 ir-keytable -w /etc/rc_keymaps/my_remote.map # 加载映射

  • 用户空间调试

配置代码如下:

# 查看红外设备 ir-keytable # 输出示例: # Found /sys/class/rc/rc0/ with: # Name: gpio_ir_recv # Driver: gpio-ir-recv # Default keymap: rc-rc6-mce # Input device: /dev/input/event2 # Enabled protocols: nec # 实时监控按键事件 ir-keytable -t # 输出示例: # 1234.567890: event type EV_MSC, evscancode = 0x12ff01 # 1234.567891: event type EV_KEY, KEY_POWER(116) pressed # 1234.567891: event type EV_KEY, KEY_POWER(116) released # 查看原始事件 cat /dev/input/event2 | hexdump # 使用 evtest 测试 evtest /dev/input/event2

  • RK3576 硬件 IR发射

RK3576的PWM控制器内置硬件IR发射引擎,支持NEC协议的自动调制,无需CPU干预时序。IR 硬件引擎工作流程如图所示:

图片

1.用户写入NEC码数据(7字节格式)

2.PWM控制器通过IR_TRANS_CTRL0寄存器启动发射

3.硬件自动产生38KHz载波并按NEC协议调制

4.发射完成后触发IR_TRANS_END_INT中断

1.用户写入NEC码数据(7字节格式)

2.PWM控制器通过IR_TRANS_CTRL0寄存器启动发射

3.硬件自动产生38KHz载波并按NEC协议调制

4.发射完成后触发IR_TRANS_END_INT中断

IR 相关寄存器:

寄存器

偏移

功能

IR_TRANS_ARBITER

0x180

通道仲裁

IR_TRANS_CTRL0

0x184

发射控制

IR_TRANS_PRE

0x188

引导码预装值

IR_TRANS_SPRE

0x18C

重复码预装值

IR_TRANS_LD

0x190

数据低电平周期

IR_TRANS_HD

0x194

数据高电平周期

IR_TRANS_DATA_VALUE

0x1A0

NEC码数据值

INT_EN

-

中断使能

  • 红外发射的设备树与内核配置

设备树配置代码如下:

&pwm2 { status = "okay"; pinctrl-0 = <&pwm2m0_pins>; rockchip,pwm-ir-transmit; /* 使能 IR 发射功能 */ };

属性

说明

必填

rockchip,pwm-ir-transmit

使能PWM硬件IR发射

内核配置代码如下:

CONFIG_RC_CORE=y # 必须启用(IR 发射依赖 rc-core) CONFIG_PWM_ROCKCHIP=y # 或 m

  • NEC码数据格式

IR 发射使用 7 字节缓冲区,格式如下:

txbuf[0]: NEC 引导码低电平时间 (μs),通常9000 txbuf[1]: NEC 引导码高电平时间 (μs),通常 4500 txbuf[2]: 重复码高电平时间 (μs),通常 2250 txbuf[3]: 逻辑 "0" 和 "1" 低电平时间 (μs),通常 560 txbuf[4]: 逻辑 "0" 高电平时间 (μs),通常 560 txbuf[5]: 逻辑 "1" 高电平时间 (μs),通常 1690 txbuf[6]: 32位 NEC 数据

32位数据格式(txbuf[6]):

bit[31:24] bit[23:16] bit[15:8] bit[7:0] 命令反码 命令码 地址反码 地址码

例如:地址 0x01,命令 0x10

•地址码 = 0x01

•地址反码 = 0xFE(~0x01)

•命令码 = 0x10

•命令反码 = 0xEF(~0x10)

•txbuf[6] = 0xEF10FE01

  • IR发射驱动示例

配置代码如下:

#include #include #include struct my_pwm_ir_dev { struct rc_dev *rcdev; struct platform_device *pdev; }; /* NEC 协议红外发射 */ static int my_pwm_ir_tx(struct rc_dev *dev, unsigned int *txbuf, unsigned int count) { struct my_pwm_ir_dev *priv = dev->priv; struct pwm_device *pwm; int ret; if (count < 2) return -EINVAL; pwm = dev->priv; if (!pwm) return -ENODEV; /* 通过 PWM IR 硬件发射 */ /* 注意:实际发射由 pwm-rockchip 驱动的 * rockchip_pwm_ir_transmit 处理 */ ret = pwm_ir_transmit(pwm, txbuf, count); if (ret < 0) dev_err(&dev->dev, "IR transmit failed: %d\n", ret); return ret; } static int my_pwm_ir_probe(struct platform_device *pdev) { struct my_pwm_ir_dev *priv; struct rc_dev *rcdev; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* 注册 rc_dev */ rcdev = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW_TX); if (!rcdev) return -ENOMEM; rcdev->driver_name = "my-pwm-ir"; rcdev->device_name = "PWM IR Transmitter"; rcdev->tx_ir = my_pwm_ir_tx; rcdev->priv = priv; rcdev->allowed_protocols = RC_BIT_NEC | RC_BIT_NECX | RC_BIT_NEC32; ret = devm_rc_register_device(&pdev->dev, rcdev); if (ret) { dev_err(&pdev->dev, "Failed to register rc device: %d\n", ret); return ret; } priv->rcdev = rcdev; priv->pdev = pdev; dev_info(&pdev->dev, "PWM IR transmitter registered\n"); return 0; } static const struct of_device_id my_pwm_ir_of_match[] = { { .compatible = "mycompany,my-pwm-ir", }, { } }; static struct platform_driver my_pwm_ir_driver = { .probe = my_pwm_ir_probe, .driver = { .name = "my-pwm-ir", .of_match_table = my_pwm_ir_of_match, }, }; module_platform_driver(my_pwm_ir_driver); MODULE_LICENSE("GPL");

  • 用户空间IR 发射

配置代码如下:

# 使用 ir-ctl 发送 NEC 码 # 格式:ir-ctl --transmit= --send="protocol:scancode" # 发送 NEC POWER 键(地址 0x01,命令 0x10) ir-ctl -d /dev/lirc0 --send=nec:0x12ff01 # 查看 IR 设备 ir-ctl -i # 输出示例: # lirc0: PWM IR Transmitter # driver: my-pwm-ir # Features: send # Allowed protocols: NEC NECX NEC32 # 发送重复码(长按效果) ir-ctl -d /dev/lirc0 --send=nec:0x12ff01 --send=nec:0x12ff01 --send=nec:0x12ff01 # 使用 evtest 验证(发射 + 接收回路测试) ir-ctl -d /dev/lirc0 --send=nec:0x12ff01 ir-keytable -t # 在另一终端中观察

  • IR发射注意事项

要点

说明

CONFIG_RC_CORE必须启用

IR发射依赖rc-core子系统

PWM输出和IR互斥

IR发射时PWM不能处于输出模式

pinctrl配置

确保PWM引脚连接到IR LED

载波频率

硬件自动使用PWM配置的载波频率(通常38KHz)

超时处理

驱动自动等待发射完成,超时3倍帧时间

产品简介

触觉智能Purple Pi OH2 RK3576开发板,4核A72+4核A53+M0多核异构处理器,主频最高2.2GHz,6Tops算力NPU!配套RK3576核心板40.5×40.5mm极致小尺寸,全新Linux6.1内核,广泛支持Linux、AndroidOpenHarmony开源鸿蒙等多个操作系统

配套RK3576核心板40.5×40.5mm极 致小尺寸,全新Linux6.1内核,广泛支持Linux、Android、OpenHarmony开源鸿蒙等多个操作系统。

  • 随机文章
  • 热门文章

您可以还会对下面的文章感兴趣:

暂无相关文章