news 2026/7/7 20:36:25

嵌入式Linux GPIO驱动翻车记——设备树里改了一下午

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
嵌入式Linux GPIO驱动翻车记——设备树里改了一下午

"这玩意儿在设备树里配置一下就行了。"——说这话的人,一定没踩过完整一遍坑。

一个月前接了个活,某个ARM板子上要控制一路GPIO输出,高低电平切换,配个LED指示灯。心想多大事儿,不就是设备树里加个节点,写个简单的字符驱动,echo 1 > /sys/class/leds/xxx/brightness 完事。

结果从下午两点折腾到晚上十点。


先看设备树。我用的这个SoC,GPIO控制器注册在pinctrl下面,每个bank有32个pin。按理说加个gpio-leds节点就行:

leds { compatible = "gpio-leds"; status_led { label = "status:green"; gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; };

编译设备树,烧录,重启。ls /sys/class/leds/ 一看,空的。

这就开始折腾了。

第一反应:设备树语法错了?ftdump 看了一下编译后的dtb,节点确实在。但/sys下面没创出来,大概率是驱动没匹配上。查内核配置,CONFIG_LEDS_GPIO没有开。

好家伙,这板子默认核心里没编这个驱动。

于是重新编内核。make menuconfig,Device Drivers → LED Support → LED Support for GPIO connected LEDs,编成模块。

make -j8 zImage modules make modules_install depmod -a reboot

然后 modprobe leds_gpio。再 ls /sys/class/leds/,出来了。

但另一个问题来了:我想在用户态直接操作这个GPIO,不用LED子系统,自己写个驱动来控制时序。有次做PWM模拟的时候,发现LED子系统的brightness有个内部反转逻辑,跟你想的不一样。

所以又写了这么个玩意儿:

#include <linux/module.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/of_gpio.h> #define DEVICE_NAME "mygpio" #define CLASS_NAME "mygpio" static int major; static struct class *mygpio_class = NULL; static int gpio_pin = -1; static ssize_t mygpio_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { char kbuf[4]; unsigned long val; if (count > 3) count = 3; if (copy_from_user(kbuf, buf, count)) return -EFAULT; kbuf[count] = '\0'; if (kstrtoul(kbuf, 10, &val)) return -EINVAL; gpio_set_value(gpio_pin, val ? 1 : 0); return count; }

写的时候注意了,copy_from_user之前得检查buffer长度。之前有内核模块因为没检查直接panic,整个板子重启,别提多尴尬了。

然后就是设备树里要加自己的compatible:

mygpio { compatible = "mygpio,ctrl"; mygpio-gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>; };

驱动里用 of_get_named_gpio 来解析:

static int mygpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; gpio_pin = of_get_named_gpio(np, "mygpio-gpios", 0); if (gpio_pin < 0) { dev_err(dev, "failed to get gpio: %d\n", gpio_pin); return gpio_pin; } if (gpio_request(gpio_pin, "mygpio")) { dev_err(dev, "gpio request failed\n"); return -EBUSY; } gpio_direction_output(gpio_pin, 0); return 0; }

折腾完发现,最坑的其实不是代码本身,是Makefile。内核模块的Makefile有一堆讲究,KERNEL_DIR、交叉编译链、arch、CROSS_COMPILE,但凡有一个少设了,编出来的模块要么insmod报错invalid format,要么符号找不到。

obj-m := mygpio.o KERNEL_DIR := /home/ubuntu/linux-4.19 CROSS_COMPILE := arm-linux-gnueabihf- ARCH := arm all: $(MAKE) -C $(KERNEL_DIR) M=$(PWD) ARCH=$(ARCH) \ CROSS_COMPILE=$(CROSS_COMPILE) modules clean: $(MAKE) -C $(KERNEL_DIR) M=$(PWD) ARCH=$(ARCH) clean

有次CROSS_COMPILE忘了设,编出来x86架构的.ko,insmod的时候提示"wrong ELF class",查了半小时才反应过来——板子是ARM的,我特么编了个x86的模块上去。

最后echo 1 > /dev/mygpio,灯亮了。就一个灯,折腾了一个大半天。

嵌入式Linux就这样——上层看着简单,每层都有坑。设备树、内核配置、驱动框架、Makefile、交叉编译,一条链上任何一个环节断了你都跑不通。下次谁再说"配个GPIO很简单",我建议ta先自己走一遍完整流程。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/7 20:35:04

零代码AI测试实践:用Coze平台构建PRD分析与用例生成智能体

1. 项目概述&#xff1a;当测试遇上AI&#xff0c;一场效率革命正在发生 如果你是一名测试工程师&#xff0c;或者对软件质量保障感兴趣&#xff0c;那么最近一定被“AI测试”这个词刷屏了。从自动化脚本的生成&#xff0c;到测试用例的智能设计&#xff0c;再到缺陷的预测性分…

作者头像 李华
网站建设 2026/7/7 20:33:18

JMeter模拟DoS攻击实战:从性能测试到破坏性测试的进阶指南

1. 项目概述&#xff1a;为什么我们需要模拟DoS攻击&#xff1f;在Web应用开发和运维的日常工作中&#xff0c;我们常常会进行性能测试&#xff0c;比如用JMeter模拟几百上千个并发用户&#xff0c;看看服务器在高负载下的响应时间和吞吐量。但性能测试的终点&#xff0c;往往只…

作者头像 李华
网站建设 2026/7/7 20:32:04

C#与JavaScript RSA加解密实战:跨语言密钥格式转换与安全通信

1. 项目概述如果你正在开发一个需要在前端&#xff08;比如网页或移动端H5&#xff09;和后端&#xff08;比如C#服务&#xff09;之间安全传输数据的应用&#xff0c;比如用户登录密码、支付信息或者一些敏感配置&#xff0c;那么RSA非对称加密算法几乎是你绕不开的一个技术选…

作者头像 李华
网站建设 2026/7/7 20:29:30

UltimMC:专为离线游戏设计的Minecraft启动器完全指南

UltimMC&#xff1a;专为离线游戏设计的Minecraft启动器完全指南 【免费下载链接】Launcher Offline Minecraft launcher. 项目地址: https://gitcode.com/gh_mirrors/lau/Launcher 在当今数字时代&#xff0c;网络连接问题常常成为游戏体验的绊脚石&#xff0c;特别是对…

作者头像 李华
网站建设 2026/7/7 20:26:52

YOLOv8/v11 模型评估:解读 mAP-50 到 mAP-50-95 的 5 个性能维度

YOLOv8/v11模型评估&#xff1a;从mAP-50到mAP-50-95的深度解析与实战指南当你在YOLO训练日志中看到一串以"mAP"开头的指标时&#xff0c;是否曾困惑于这些数字背后的真实含义&#xff1f;为什么同一个模型会有mAP0.5、mAP0.5:0.95、mAP0.75等多个不同版本的评估结果…

作者头像 李华