4. GPIO点灯控制
任务目标
在瑞芯微RK系列平台上,通过内核模块方式控制一个GPIO引脚输出高低电平,驱动LED以1Hz频率闪烁,以此验证GPIO输出功能是否正常。
环境与依赖
- 交叉编译工具链(如aarch64-linux-gnu-gcc)
- RK平台Linux内核源码树(已配置好交叉编译环境)
- 目标板已启动Linux系统,且具备root权限
硬件连接
将LED正极(长脚)通过220Ω限流电阻连接到目标GPIO引脚,LED负极(短脚)接地。本案例以RK3588为例,使用GPIO0_B7(对应引脚编号计算见下文),实际使用时请根据板卡原理图调整。
GPIO编号计算
RK平台GPIO编号公式:bank * 32 + group * 8 + index。其中group对应:A=0, B=1, C=2, D=3。GPIO0_B7即bank=0, group=B(1), index=7,编号为 0*32 + 1*8 + 7 = 15。
内核模块实现
创建 gpio_led.c:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/err.h>
#define LED_GPIO 15 /* GPIO0_B7 */
static struct task_struct *led_thread;
static int led_state;
static int led_blink_thread(void *data)
{
while (!kthread_should_stop()) {
led_state = !led_state;
gpio_set_value(LED_GPIO, led_state);
msleep(500); /* 500ms翻转一次,周期1s */
}
return 0;
}
static int __init led_init(void)
{
int ret;
if (!gpio_is_valid(LED_GPIO)) {
pr_err("Invalid GPIO: %d\n", LED_GPIO);
return -EINVAL;
}
ret = gpio_request(LED_GPIO, "led");
if (ret) {
pr_err("gpio_request failed: %d\n", ret);
return ret;
}
ret = gpio_direction_output(LED_GPIO, 0);
if (ret) {
pr_err("gpio_direction_output failed: %d\n", ret);
gpio_free(LED_GPIO);
return ret;
}
led_state = 0;
led_thread = kthread_run(led_blink_thread, NULL, "led_blink");
if (IS_ERR(led_thread)) {
pr_err("kthread_run failed\n");
gpio_free(LED_GPIO);
return PTR_ERR(led_thread);
}
pr_info("LED module loaded, GPIO %d blinking started\n", LED_GPIO);
return 0;
}
static void __exit led_exit(void)
{
if (led_thread)
kthread_stop(led_thread);
gpio_set_value(LED_GPIO, 0);
gpio_free(LED_GPIO);
pr_info("LED module unloaded\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("RK Dev");
MODULE_DESCRIPTION("RK GPIO LED Blink Driver");
Makefile
obj-m := gpio_led.o
KDIR := /path/to/kernel/source
PWD := $(shell pwd)
CROSS := aarch64-linux-gnu-
all:
$(MAKE) ARCH=arm64 CROSS_COMPILE=$(CROSS) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) ARCH=arm64 CROSS_COMPILE=$(CROSS) -C $(KDIR) M=$(PWD) clean
将 KDIR 替换为实际内核源码路径。
编译与加载
make
adb push gpio_led.ko /data/
adb shell
# 在目标板执行
insmod /data/gpio_led.ko
验证方法
- 加载模块后,观察LED是否以约1Hz频率(每秒亮灭各一次)闪烁。
- 执行
dmesg | tail查看内核日志,应包含LED module loaded信息。 - 使用万用表测量GPIO引脚电压,应观察到0V与3.3V(或板卡IO电平)交替变化。
通过条件:LED持续稳定闪烁,且dmesg无错误信息。
卸载模块
rmmod gpio_led
卸载后LED应熄灭,GPIO被释放。
常见问题
- gpio_request失败:检查该GPIO是否已被其他驱动占用,或编号计算是否正确。
- LED不亮:确认GPIO编号对应实际引脚,检查硬件连接和限流电阻。
- 编译报错:确认内核源码路径正确,且已配置好交叉编译环境。