最近在学习 Luckfox Pico Mini 板子的设备树和 LED 驱动开发,记录一下整个探索和实践过程,希望对初学者有参考价值。
1. 理解设备树(DTS)和 LED 驱动
在 Linux 内核中,设备树(Device Tree, DTS)用来描述硬件信息,让内核在启动时能够正确绑定驱动。例如,我们要控制板载 LED,就需要在 DTS 中声明它。
Luckfox Pico Mini 的默认 DTS 文件中包含了 SPI、I2C、UART、PWM 等节点,但没有 LED 节点。
2. LED 节点配置
我们查询到板子上 LED 连接的是 GPIO1_A2,初步配置如下:
/ {
leds {
compatible = "gpio-leds";
user_led {
label = "user-led";
gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
};compatible = "gpio-leds":内核自带 GPIO LED 驱动gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>:使用 GPIO1 组第 2 号引脚,高电平点亮default-state = "off":开机默认灭
注意,GPIO_ACTIVE_HIGH或GPIO_ACTIVE_LOW会影响开关逻辑。如果 LED 实际是高电平点亮,就应该用GPIO_ACTIVE_HIGH。
注释示例
// user led is connected to GPIO1_A2
// led on when gpio1_a2 output high
user_led {
label = "user-led";
gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
default-state = "off";
};3. DTS 修改生效流程
- 修改 DTS 后,必须重新编译内核并打包 boot.img
- 对于 LED 这种内核驱动,只需 重编 boot.img,无需重新烧写 uboot 或 rootfs
- 编译流程(简化):
./build.sh kernel # 编译内核生成 zImage + dtb
./build.sh driver # 编译内核驱动
./build.sh firmware # 打包 boot.img
# 烧写 boot.img 到板子 boot 分区
dd if=output/images/boot.img of=/dev/mtdX bs=512Kupdateimg 是生成整套系统升级包的命令,不必用于单独修改 LED。
4. LED 驱动与 /sys/class/leds 接口
内核将 LED 注册为 /sys/class/leds/user-led:
ls /sys/class/leds/
cat /sys/class/leds/user-led/brightness
cat /sys/class/leds/user-led/max-brightnessbrightness:当前亮度/状态,写 0/1 控制 GPIO LEDmax-brightness:最大亮度,只读,GPIO LED 通常为 1- 对普通 GPIO LED,内核
gpio-leds驱动只是通过gpio_set_value()高低电平开关 LED,并没有 PWM 调光功能
GPIO vs PWM LED
| 类型 | 驱动 | brightness 行为 |
|---|---|---|
| GPIO LED | gpio-leds | 写 0/1 → 高低电平开关 |
| PWM LED | pwm-leds | 写 0~max → 内核 PWM 占空比输出 |
Luckfox Pico Mini 的 GPIO1_A2 也是 PWM0_M0 复用引脚,但我们当前只用作普通 GPIO LED。
5. 用户空间控制脚本
直接操作 /sys/class/leds/.../brightness 确实有点麻烦,于是写了一个简单的 Bash 脚本 ledctl.sh:
#!/bin/bash
LED_PATH="/sys/class/leds/user-led/brightness"
case "$1" in
on)
echo 1 > $LED_PATH
;;
off)
echo 0 > $LED_PATH
;;
blink)
for i in $(seq 1 $2); do
echo 1 > $LED_PATH
sleep 0.5
echo 0 > $LED_PATH
sleep 0.5
done
;;
*)
echo "Usage: $0 on|off|blink N"
;;
esac使用示例:
./ledctl.sh on # 点亮 LED
./ledctl.sh off # 熄灭 LED
./ledctl.sh blink 5 # 闪烁 5 次6. 集成脚本到镜像
为了每次开机都能使用该脚本,需要把它集成到 rootfs:
- 在 Buildroot overlay 中放置脚本,例如:
board/luckfox-pico-mini/rootfs-overlay/usr/bin/ledctl.sh
chmod +x board/luckfox-pico-mini/rootfs-overlay/usr/bin/ledctl.sh- 如果希望开机自动执行,可用
rc.local或 systemd service:
rc.local 示例:
#!/bin/sh
/usr/bin/ledctl.sh off
exit 0systemd service 示例:
[Unit]
Description=User LED Control
[Service]
Type=oneshot
ExecStart=/usr/bin/ledctl.sh off
[Install]
WantedBy=multi-user.target- 编译 rootfs 后,开机即可生效。
7. 总结与学习经验
- 设备树 DTS 是硬件描述和驱动绑定的入口
gpio-leds驱动提供了统一接口/sys/class/leds/.../brightness- 普通 GPIO LED 只能 0/1 开关,高级调光需要 PWM LED 驱动
- 用户空间可以通过脚本操作
/sys/class/leds/.../brightness控制 LED - Buildroot overlay + init 脚本可将自定义工具集成到镜像,实现开机自动控制
通过这次实践,我理解了:
- DTS 的修改方式与位置选择
- LED 驱动的类型差异和
/sys/class/leds接口意义 - 如何在不重建整套镜像的情况下修改 boot.img 生效
- 用户空间控制 LED 的方法及集成方案
下次可以尝试将 GPIO1_A2 改为 PWM LED,实现呼吸灯和亮度渐变。
系列文章
- 使用 Buildroot 交叉编译 Vitetris 到 Luckfox ARM 开发板的完整实践与经验总结
- Luckfox Pico Mini 入门学习笔记:GPIO LED 驱动与设备树实践【当前文章】