从设备树到驱动:在RK3566上点亮一个LED的完整实战(GPIO0_B4为例)
2026/5/16 17:14:06 网站建设 项目流程

从设备树到驱动:在RK3566上点亮一个LED的完整实战(GPIO0_B4为例)

当你第一次拿到一块Rockchip RK3566开发板时,最令人兴奋的莫过于让硬件真正"活"起来。而点亮一个LED,就像嵌入式世界的"Hello World",看似简单却蕴含着从硬件连接到软件控制的完整知识链。本文将带你以GPIO0_B4为例,完整走通从设备树配置、驱动编写到内核编译烧录的全流程,过程中你会遇到那些文档里没写的"坑",也会掌握真正实用的调试技巧。

1. 硬件准备与环境搭建

在开始编码之前,我们需要确保硬件连接正确且开发环境就绪。ROC-RK3566-PC开发板上的GPIO0_B4对应物理引脚的位置可能因版本不同有所变化,建议先查阅板子的原理图确认。通常这个引脚会位于扩展接口的某个位置,用一个跳线帽连接LED时,记得串联一个220Ω的限流电阻。

开发环境需要准备:

  • 一台运行Linux的主机(推荐Ubuntu 20.04 LTS)
  • 已安装的RK3566 SDK(包含交叉编译工具链)
  • 串口调试工具(如minicom或picocom)
  • 烧录工具(RKDevTool或upgrade_tool)

提示:在Ubuntu上安装依赖工具链时,经常会遇到库版本冲突问题。建议使用SDK提供的docker环境,避免污染主机系统。

2. 深入理解RK3566的GPIO子系统

Rockchip的GPIO控制器采用bank分组设计,RK3566包含5组GPIO bank(GPIO0-GPIO4),每组又分为A、B、C、D四个子组。GPIO0_B4的命名规则解析如下:

字段含义
GPIO0Bank编号0
B子组编号1
4引脚编号4

计算全局GPIO编号的公式为:

pin = bank * 32 + group * 8 + pin_num

因此GPIO0_B4对应的全局编号为:

0 * 32 + 1 * 8 + 4 = 12

在设备树中,我们既可以使用数字编号&gpio0 12,也可以使用SDK提供的宏定义&gpio0 RK_PB4。后者可读性更好,但需要包含头文件:

#include <dt-bindings/pinctrl/rockchip.h>

3. 设备树节点配置实战

设备树是连接硬件描述与驱动程序的桥梁。我们在rk356x-firefly-demo.dtsi中添加一个gpio_demo节点:

gpio_demo: gpio_demo { status = "okay"; compatible = "firefly,rk356x-gpio"; led-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; };

几个关键点需要注意:

  1. compatible属性必须与驱动中的匹配表一致
  2. GPIO_ACTIVE_HIGH表示高电平点亮LED,如果是低电平有效则使用GPIO_ACTIVE_LOW
  3. 确保该GPIO没有被其他功能复用(检查pinctrl配置)

编译设备树时,经常会遇到语法错误导致编译失败。建议先用dtc工具检查:

dtc -I dts -O dtb -o test.dtb test.dts

4. 编写LED驱动代码

创建一个最简单的字符设备驱动,主要实现以下功能:

#include <linux/module.h> #include <linux/gpio.h> static int led_gpio; static int gpio_demo_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; enum of_gpio_flags flags; led_gpio = of_get_named_gpio_flags(np, "led-gpio", 0, &flags); if (!gpio_is_valid(led_gpio)) { dev_err(&pdev->dev, "invalid GPIO pin\n"); return -EINVAL; } if (gpio_request(led_gpio, "led-gpio")) { dev_err(&pdev->dev, "GPIO request failed\n"); return -EBUSY; } gpio_direction_output(led_gpio, 1); // 初始点亮LED return 0; } static const struct of_device_id gpio_demo_ids[] = { { .compatible = "firefly,rk356x-gpio" }, { } }; MODULE_DEVICE_TABLE(of, gpio_demo_ids); static struct platform_driver gpio_demo_driver = { .driver = { .name = "gpio-demo", .of_match_table = gpio_demo_ids, }, .probe = gpio_demo_probe, }; module_platform_driver(gpio_demo_driver);

驱动开发中最常遇到的三个问题:

  1. GPIO申请失败(可能被其他驱动占用)
  2. 设备树匹配失败(compatible字符串不匹配)
  3. 电平设置无效(检查IO电压域配置)

5. 内核编译与固件烧录

将驱动代码放入SDK的drivers/gpio目录后,需要修改Kconfig和Makefile:

# drivers/gpio/Kconfig config GPIO_FIREFLY_DEMO tristate "Firefly GPIO Demo" default y
# drivers/gpio/Makefile obj-$(CONFIG_GPIO_FIREFLY_DEMO) += gpio-firefly-demo.o

编译完整固件:

./build.sh kernel ./build.sh uboot ./mkfirmware.sh

烧录时常见的坑:

  • 开发板必须进入Loader模式(按住Recovery键上电)
  • 工具版本必须与芯片型号匹配
  • 烧录后务必执行"重启设备"操作

6. 调试与问题排查

当LED没有按预期点亮时,可以按以下步骤排查:

  1. 确认GPIO是否成功申请:
cat /proc/interrupts | grep gpio
  1. 检查GPIO当前状态:
# 导出GPIO echo 12 > /sys/class/gpio/export # 查看方向 cat /sys/class/gpio/gpio12/direction # 手动设置电平 echo 1 > /sys/class/gpio/gpio12/value
  1. 测量物理引脚电压:
  • 高电平应为3.3V左右
  • 低电平应接近0V
  • 如果电压异常,检查IO电源域配置

7. 进阶:添加用户空间控制

为了让应用层能控制LED,我们可以实现一个简单的ioctl接口:

static long gpio_demo_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case LED_ON: gpio_set_value(led_gpio, 1); break; case LED_OFF: gpio_set_value(led_gpio, 0); break; default: return -ENOTTY; } return 0; }

测试时可以用一个简单的Python脚本:

import fcntl fd = open('/dev/gpio_demo', 'r') fcntl.ioctl(fd, LED_ON) # 点亮LED

这个项目虽然简单,但涵盖了嵌入式Linux开发的完整流程。在实际产品开发中,还需要考虑电源管理、异常处理等更多因素。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询