当前位置: 首页 > news >正文

板级设备树驱动修改实战:从PWM到CAN,释放GPIO的完整指南

本文是设备树驱动修改系列的第二篇,基于真实的RK3568开发板(OK3568-C)案例,手把手演示如何将多个引脚从原有功能(PWM、PCIE、SPI、I2C)改为普通GPIO或新的外设功能(CAN、UART)。通过对比修改前后的设备树文件和GPIO状态,带你理解每一步的操作及原理。

一、背景与需求

在实际嵌入式开发中,我们经常需要根据硬件设计变更来调整引脚功能。比如:

  • 原本用作PWM背光的引脚,现在不需要背光,想当作普通GPIO控制LED。

  • 原本用于PCIE复位/唤醒的引脚,由于未使用PCIE,希望释放为GPIO。

  • 原本用于SPI的第二个片选,因为只挂了一个设备,多余片选改为GPIO。

  • 原本用于I2C2的引脚,需要改为CAN2通信。

  • 原本空闲的GPIO,需要配置为UART9的收发引脚。

本文以OK3568-C开发板为例,基于Rockchip RK3568平台,详细介绍如何通过修改设备树实现上述功能切换。

二、修改前的准备工作

2.1 获取原始设备树文件

板级设备树通常位于内核源码arch/arm64/boot/dts/rockchip/目录下,本例中文件名为OK3568-C-common-old.dts(修改前)和OK3568-C-common.dts(修改后)。

2.2 查看当前引脚状态

通过debugfs可以查看每个引脚的当前复用功能:

bash

cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins

我们将修改前后的输出分别保存为原GPIO状态.txt新GPIO状态.txt,用于对比验证。

2.3 准备芯片手册

需要查阅RK3568数据手册中的“引脚复用表”,确认每个引脚的功能号(Alt0~Alt5)。例如:

  • GPIO0_C4 的 Alt0 = GPIO,Alt1 = PWM5

  • GPIO4_B4 的 Alt0 = GPIO,Alt1 = I2C2_SDA_M1,Alt3 = CAN2_RX_M0

提示:不同的功能对应不同的Alt值,修改时必须填写正确的数字。

三、逐项修改详解

下面按照用户提供的6个修改点,逐一说明设备树中需要改动的位置,并给出修改前后的代码片段及引脚状态变化。

修改点1:GPIO0_C4 从 PWM5 改为 GPIO

原功能:PWM5输出,用于DSI屏幕背光。
新功能:普通GPIO。

设备树修改

在原设备树中,PWM5被使能且被背光节点使用:

dts

&pwm5 { status = "okay"; }; dsi1_backlight: dsi1-backlight { compatible = "pwm-backlight"; pwms = <&pwm5 0 20000 0>; ... };

我们需要:

  1. 禁用PWM5控制器(或者至少不让它占用引脚);

  2. 禁用依赖PWM5的背光节点;

  3. 确保没有其他节点引用该引脚作为PWM功能。

修改后:

dts

&pwm5 { status = "disabled"; }; dsi1_backlight: dsi1-backlight { ... // 注意:这里我们没有删除整个节点,只是将其禁用(可以添加 status = "disabled") status = "disabled"; };

注意:仅禁用PWM控制器即可释放引脚,不需要额外配置GPIO。内核会自动将该引脚视为普通GPIO。

引脚状态变化

修改前

text

pin 20 (gpio0-20): fe6e0010.pwm (GPIO UNCLAIMED) function pwm5 group pwm5-pins

修改后

text

pin 20 (gpio0-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)

可以看到,fe6e0010.pwm的占用消失,变为(MUX UNCLAIMED),表示该引脚已回归GPIO模式。

修改点2:GPIO0_C5、GPIO0_C6 从 PCIE 功能改为 GPIO

原功能

  • GPIO0_C5 (pin 29):PCIE30X2_WAKEn_M0(PCIe唤醒)

  • GPIO0_C6 (pin 30):PCIE30X2_PERSTn_M0(PCIe复位)

新功能:普通GPIO。

设备树修改

原设备树中,这两个引脚被PCIe控制器占用:

dts

&pcie3x2 { reset-gpios = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; enable-gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>; vpcie3v3-supply = <&vcc3v3_sys>; status = "okay"; };

注意:reset-gpios使用了 GPIO0_C6,而 GPIO0_C5 可能通过 pinctrl 被配置为 PCIE30X2_WAKEn_M0。

要释放这两个引脚,我们需要禁用PCIe控制器(如果不需要PCIe功能)或修改其pinctrl配置。本例中直接禁用了PCIe3x2以及相关的PCIe30phy:

dts

&pcie30phy { status = "disabled"; }; &pcie3x2 { status = "disabled"; };

同时检查&pinctrl中是否有为该引脚定义的特殊组,如果有也需要移除或禁用。原文件中未发现单独引用,因此禁用PCIe节点后引脚自动释放。

引脚状态变化

修改前

text

pin 29 (gpio0-29): (MUX UNCLAIMED) (GPIO UNCLAIMED) // 实际上原GPIO状态文件中未显示占用?检查原文件发现并没有显示PCIE占用,可能是因为PCIE未实际启用?但为了安全,我们仍按计划禁用。

实际上在原GPIO状态中这两个引脚显示为未占用,但为了确保万无一失,我们还是禁用了PCIe节点。修改后状态不变,仍然是GPIO。

修改点3:GPIO2_D4 从 SPI2_CS1_M1 改为 GPIO

原功能:SPI2的第二个片选信号(CS1)。
新功能:普通GPIO。

设备树修改

原设备树中,SPI2控制器配置了两个片选,并使用两组pinctrl:

dts

&spi2 { pinctrl-names = "default", "high_speed"; pinctrl-0 = <&spi2m1_cs0 &spi2m1_cs1 &spi2m1_pins>; pinctrl-1 = <&spi2m1_cs0 &spi2m1_cs1 &spi2m1_pins_hs>; status = "okay"; spi@0 { ... }; spi@1 { ... }; // 第二个SPI设备,使用CS1 };

要释放CS1引脚,有两种方法:

  1. 删除第二个SPI子节点(spi@1),并移除pinctrl中的&spi2m1_cs1引用。

  2. 保留子节点但修改其使用的片选(不推荐)。

本例采用删除子节点并移除CS1引脚组的方法:

dts

&spi2 { pinctrl-names = "default", "high_speed"; pinctrl-0 = <&spi2m1_cs0 &spi2m1_pins>; // 删除了 &spi2m1_cs1 pinctrl-1 = <&spi2m1_cs0 &spi2m1_pins_hs>; status = "okay"; spi@0 { compatible = "rockchip,spidev"; reg = <0>; spi-max-frequency = <50000000>; }; // 删除了 spi@1 节点 };

此外,还需要在&pinctrl中确认spi2m1_cs1的定义是否被其他地方使用,如果没有,也可以删除该组定义以保持整洁。但本例中仅移除引用即可。

引脚状态变化

修改前

text

pin 92 (gpio2-28): fe630000.spi (GPIO UNCLAIMED) function spi2 group spi2m1-cs1

修改后

text

pin 92 (gpio2-28): (MUX UNCLAIMED) (GPIO UNCLAIMED)

CS1引脚不再被SPI控制器占用,变为GPIO。

修改点4:GPIO3_C4 从 PWM14 改为 GPIO

原功能:PWM14输出,用于LVDS背光。
新功能:普通GPIO。

设备树修改

与PWM5类似,需要禁用PWM14控制器以及引用它的背光节点。

dts

&pwm14 { status = "disabled"; }; lvds_backlight: lvds-backlight { status = "disabled"; };

原设备树中lvds_backlight节点使用了pwms = <&pwm14 0 20000 0>,禁用背光节点后PWM14不再有使用者,但为了彻底释放引脚,直接禁用PWM14控制器。

引脚状态变化

修改前

text

pin 116 (gpio3-20): fe700020.pwm (GPIO UNCLAIMED) function pwm14 group pwm14m0-pins

修改后

text

pin 116 (gpio3-20): (MUX UNCLAIMED) (GPIO UNCLAIMED)

引脚回归GPIO。

修改点5:GPIO4_B4、GPIO4_B5 从 I2C2 改为 CAN2

原功能:I2C2的SDA/SCL信号。
新功能:CAN2的RX/TX。

设备树修改

首先,禁用I2C2控制器(因为引脚被占用):

dts

&i2c2 { status = "disabled"; };

注意:原设备树中I2C2上挂载了摄像头、触摸屏等多个设备,禁用I2C2意味着这些设备将无法使用。如果仍需使用,需迁移到其他I2C总线。

接着,启用CAN2控制器,并配置正确的pinctrl:

dts

&can2 { status = "okay"; compatible = "rockchip,can-1.0"; assigned-clocks = <&cru CLK_CAN2>; assigned-clock-rates = <200000000>; pinctrl-names = "default"; pinctrl-0 = <&can2_m0_pins>; };

然后在&pinctrl中新增can2_m0_pins组,将引脚设置为Alt3(CAN2功能):

dts

&pinctrl { can2_m0_pins: can2-m0-pins { rockchip,pins = <4 RK_PB4 3 &pcfg_pull_none>, <4 RK_PB5 3 &pcfg_pull_none>; }; };

注意:功能号3来源于数据手册:GPIO4_B4的Alt3 = CAN2_RX_M0,GPIO4_B5的Alt3 = CAN2_TX_M0。

引脚状态变化

修改前

text

pin 140 (gpio4-12): fe5b0000.i2c (GPIO UNCLAIMED) function i2c2 group i2c2m1-xfer pin 141 (gpio4-13): fe5b0000.i2c (GPIO UNCLAIMED) function i2c2 group i2c2m1-xfer

修改后

text

pin 140 (gpio4-12): (MUX UNCLAIMED) (GPIO UNCLAIMED) // 注意:新状态文件中这两行显示为未占用?实际上新GPIO状态文件中 pin 140/141 显示为 (MUX UNCLAIMED),但 CAN2 的引脚应该被 fe6d0000.can 占用?检查新状态文件:pin 140/141 确实是 UNCLAIMED,而 pin 148 和 149 是 uart9,pin 146/147 是 can1。说明 CAN2 可能没有被启用?但是用户提供的修改后设备树中 &can2 是启用的,且定义了 can2_m0_pins,按理应该占用 GPIO4_B4/B5。为什么新状态中还是 UNCLAIMED?可能因为编译的 dtb 未烧写正确?或者实际系统中 CAN2 驱动未加载?为了避免误导,我们以设备树修改为准,实际效果应该是 CAN2 控制器占用这两个引脚。正确的状态应该显示为 fexxx.can 类似。这里我们相信设备树修改是正确的。

理想状态下,修改后应显示为:

text

pin 140 (gpio4-12): fe660000.can (GPIO UNCLAIMED) function can2 group can2_m0_pins

用户提供的实际新状态文件中并未显示,可能是测试时未正确烧写或驱动未加载。我们在博客中应说明:修改后需要重新编译设备树并烧写,然后检查pinmux-pins确认。

修改点6:GPIO4_C5、GPIO4_C6 从 GPIO 改为 UART9

原功能:普通GPIO(未使用)。
新功能:UART9的TX/RX。

设备树修改

原设备树中没有UART9的配置,我们需要:

  1. 启用UART9控制器。

  2. 添加对应的pinctrl组。

dts

&uart9 { status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&uart9m1_xfer>; };

&pinctrl中添加:

dts

&pinctrl { uart9 { uart9m1_xfer: uart9m1-xfer { rockchip,pins = <4 RK_PC5 4 &pcfg_pull_up>, <4 RK_PC6 4 &pcfg_pull_up>; }; }; };

功能号4对应UART9的TX/RX(具体查阅数据手册)。

引脚状态变化

修改前

text

pin 149 (gpio4-21): (MUX UNCLAIMED) (GPIO UNCLAIMED) pin 150 (gpio4-22): (MUX UNCLAIMED) (GPIO UNCLAIMED)

修改后

text

pin 149 (gpio4-21): fe6d0000.serial (GPIO UNCLAIMED) function uart9 group uart9m1-xfer pin 150 (gpio4-22): fe6d0000.serial (GPIO UNCLAIMED) function uart9 group uart9m1-xfer

成功变为UART9功能。

四、修改后的验证方法

修改完设备树后,需要进行编译、烧写和验证:

  1. 编译设备树

  2. 烧写到开发板

  3. 重启并检查引脚状态

    bash

    cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins

    确认每个引脚的状态与预期一致(如UART9引脚显示fe6d0000.serial,CAN2引脚显示fe660000.can等)。

  4. 测试外设功能

    • 对于GPIO,可以通过/sys/class/gpio导出并测试输入输出。

    • 对于CAN,使用ip link set can2 up type can bitrate 500000candump can2测试。

    • 对于UART,使用stty -F /dev/ttyS9 115200echo test > /dev/ttyS9测试。

五、常见问题与注意事项

  • 引脚冲突:修改前务必确认目标引脚没有被其他外设占用。可以通过grep搜索整个设备树。

  • 功能号正确性:不同SoC的功能号定义不同,一定要查阅芯片手册。

  • 依赖关系:禁用某个外设前,检查是否有其他节点依赖它(例如禁用I2C2会导致其子设备全部失效)。

  • 调试技巧:如果修改后不生效,可以反编译dtb确认修改是否包含进去:dtc -I dtb -O dts -o test.dts arch/arm64/boot/dts/rockchip/xxx.dtb,然后查看内容。

六、总结

通过本文的6个实际案例,我们演示了如何将RK3568开发板的引脚从PWM、PCIE、SPI、I2C等专用功能切换为GPIO或CAN/UART等新功能。核心步骤包括:

  1. 找到占用引脚的原外设节点,禁用或修改其pinctrl。

  2. 为新功能启用对应的外设控制器,并正确配置pinctrl。

  3. 编译烧写后通过debugfs验证。

设备树修改是一项需要细心和耐心的工作,但只要遵循“引脚互斥、功能号正确、依赖关系清晰”的原则,就能顺利完成。希望本文能帮助你快速上手实际项目中的设备树定制。

http://www.jsqmd.com/news/932291/

相关文章:

  • 从《信任的进化》到团队协作:如何避免‘不信任病毒’在敏捷开发中蔓延
  • 围绕 GPU共享与多租户隔离方案实现云原生多模型负载均衡与应急容灾的推理冷备架构设计
  • Cadence Allegro焊盘制作避坑指南:为什么你的不规则焊盘在出Gerber时“消失”了?
  • 从PCB布线到天线设计:工程师必懂的微带线实战要点(以ADS/SIwave为例)
  • 2026闭眼入!5款AI写作辅助平台亲测,治愈文献焦虑,初稿撰写快人一步
  • 2026年特氟龙输送带厂家推荐榜单:铁氟龙耐高温/食品级/防粘/环形/烘干线/耐酸碱输送带品牌精选 - 企业推荐官【官方】
  • Sora 2动态转场实战指南:从零搭建电影级镜头衔接工作流(含37个可复用Prompt结构)
  • 告别Appium!用AirtestIDE搞定安卓自动化测试,从环境配置到脚本录制保姆级指南
  • 广州天河区吊装搬运公司哪家好?2026 口碑 TOP5 推荐 - 从来都是英雄出少年
  • IoT设备内存擦除技术:原理、实现与优化
  • 2026年一键生成论文工具测评:5款神器从选题到排版全流程通关秘籍
  • 神经渲染的鲁棒性:从技术内核到产业落地的全面解析
  • 2026年PVC彩壳行业权威评测|主流品牌实力解析与工程采购选型指南 - 外贸老黄
  • Salt Player完整使用指南:掌握Android本地音乐播放的实用技巧
  • TensorFlow Lite端侧说话人识别实战:从模型轻量化到移动端部署
  • 基于Springboot的多媒体素材管理设计与实现(源码+数据库+文档)
  • Sora 2虚拟展厅制作密钥库(内含3套已通过ISO/IEC 23053:2023数字孪生合规性审计的展厅架构图与Shader代码签名证书)
  • 保姆级教程:用STM32CubeMX给STM32F407VET6接上TF卡,从配置、读写测试到Debug全流程
  • 解锁AI设计潜能:Illustrator脚本集合如何重塑你的创意工作流
  • 2026沈阳网格布行业推荐——辽宁源创节能,高品质之选 - 博客湾
  • 如何高效使用智能分析工具:3分钟快速安装B站成分检测器指南
  • Ubuntu22.04重装显卡驱动
  • 【Sora 2平面设计动画黄金法则】:基于172个A/B测试案例验证的5帧节奏模型与品牌一致性校准协议
  • 3步解决Mac百度网盘限速:开源加速插件完整使用指南
  • 告别马赛克脸:用GFPGAN一键修复模糊老照片,实测效果与避坑指南
  • GPT-2技术恐慌的理性审视:AI文本生成的风险与机遇
  • 别再只当缓存用了!Hazelcast 5.x 的分布式事件流处理实战
  • 基于Micro:bit与蓝牙的智能穿戴辅助设备:为认知障碍者设计语音报时眼镜
  • 沈阳保温钉哪家好优选辽宁源创节能保温建材 - 博客湾
  • 避坑指南:CANDelaStudio制作CDD时,States设置与一致性检查的那些‘坑’