一、去淘宝买一个led 三色灯配件,三色灯连接GPIO 接口。
连接方式参考下图,red 脚连GPIO17,green 脚连GPIO 18,blue 脚连GPIO19,GND脚连任意的GND
对照图片的引脚进行连接。做完这一步,可以通过以下步骤验证led是否能点亮,以下可以点亮红灯
adb shell chmod 0666 /sys/class/gpio/export //export赋权限0666
adb shell chmod 0666 /sys/class/gpio/unexport //unexport赋权限0666
adb shell echo 17 > /sys/class/gpio/export //通知系统需要导出控制的GPI017
adb shell chmod 0666 /sys/class/gpio/gpio17/direction //给GPIO17的direction属性赋权限0666
adb shell chmod 0666 /sys/class/gpio/gpio17/value //给GPIO17的value属性赋权限0666
adb shell echo out > /sys/class/gpio/gpio17/direction //往GPIO17的direction属性写入out,设置GPIO为输出
adb shell echo 1 > /sys/class/gpio/gpio17/value //往GPIO17的value属性写入1,设置GPIO为高电平
参考链接:https://blog.csdn.net/qq_29848853/article/details/130256038
二、添加驱动程序
1.在内核源码根目录,我的源码目录为kernel,在kernel/common/drivers/char下添加LedDriver目录,并在LedDriver目录下添加文件Kconfig,led_drv.c,Makefile。
Kconfig
# SPDX-License-Identifier: GPL-2.0-only
#
# HELLO_MODULE
#
config LED_DRV
bool "LED support"
default y
led_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/string.h>
#define RED_PIN 17
#define GREEN_PIN 18
#define BLUE_PIN 19
/* 1. 确定主设备号 */
static int major = 0;
static struct class *led_drv_class;
static int on_or_off(const char *buf,char *key){
return NULL != strstr(buf, key) ? 1 : 0;
}
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
char buffer[20];
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
if (size > sizeof(buffer))
return -EINVAL;
if (copy_from_user(buffer, buf, size))
return -EFAULT;
buffer[size] = '\0';
gpio_set_value(RED_PIN, on_or_off(buffer,"red"));
gpio_set_value(GREEN_PIN, on_or_off(buffer,"green"));
gpio_set_value(BLUE_PIN, on_or_off(buffer,"blue"));
return size;
}
static int led_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int led_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
// 2. 定义自己的file_operations结构体 */
static struct file_operations led_drv = {
.owner = THIS_MODULE,
.open = led_drv_open,
.read = led_drv_read,
.write = led_drv_write,
.release = led_drv_close,
};
static int __init rgbled_init(void)
{
int err;
printk(KERN_INFO "RGB LED driver initialized\n");
// 初始化GPIO引脚
gpio_request(RED_PIN, "red");
gpio_request(GREEN_PIN, "green");
gpio_request(BLUE_PIN, "blue");
gpio_direction_output(RED_PIN, 0);
gpio_direction_output(GREEN_PIN, 0);
gpio_direction_output(BLUE_PIN, 0);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
major = register_chrdev(0, "led_drv", &led_drv); /* /dev/led_drv */
//提供设备信息,自动创建设备节点。
led_drv_class = class_create(THIS_MODULE, "led_drv_class");
err=PTR_ERR(led_drv_class);
if (IS_ERR(led_drv_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "led_drv");
return -1;
}
device_create(led_drv_class, NULL, MKDEV(major, 0), NULL, "led_drv"); /* /dev/led_drv */
return 0;
}
static void __exit rgbled_exit(void)
{
// 释放GPIO引脚
gpio_set_value(RED_PIN, 0);
gpio_set_value(GREEN_PIN, 0);
gpio_set_value(BLUE_PIN, 0);
gpio_free(RED_PIN);
gpio_free(GREEN_PIN);
gpio_free(BLUE_PIN);
printk(KERN_INFO "RGB LED driver exited\n");
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
device_destroy(led_drv_class, MKDEV(major, 0));
class_destroy(led_drv_class);
unregister_chrdev(major, "led_drv");
}
module_init(rgbled_init);
module_exit(rgbled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("RGB LED driver for Raspberry Pi 4B");
Makefile
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for led driver
#
obj-$(CONFIG_LED_DRV) += led_drv.o
2.接着加配置
在kernel/common/drivers/char/Kconfig 增加
source "drivers/char/LedDriver/Kconfig"
在kernel/common/drivers/char/Makefile 增加
obj-$(CONFIG_LED_DRV) += LedDriver/
在kernel/common/arch/arm64/defconfig增加
CONFIG_LED_DRV=y
3.重新编译内核build/build.sh
三、编写测试代码led_drv_test.c ,CMakeLists.txt,build_led_test.sh
led_drv_test.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
* ./led_drv_test -w red,blue,green
*/
int main(int argc, char **argv)
{
int fd;
char buf[1024];
int len;
/* 1. 判断参数 */
if (argc < 2)
{
printf("Usage: %s -w <string>\n", argv[0]);
printf(" %s -r\n", argv[0]);
return -1;
}
/* 2. 打开文件 */
fd = open("/dev/led_drv", O_RDWR);
if (fd == -1)
{
printf("can not open file /dev/led_drv\n");
return -1;
}
/* 3. 写文件或读文件 */
if ((0 == strcmp(argv[1], "-w")) && (argc == 3))
{
len = strlen(argv[2]) + 1;
len = len < 1024 ? len : 1024;
write(fd, argv[2], len);
}
close(fd);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(leddrvtest)
add_executable(${PROJECT_NAME} led_drv_test.c)
build_led_test.sh
export ANDROID_NDK=/home/liquanan/Android/Sdk/ndk/25.2.9519653
rm -r build
mkdir build && cd build
# CMake的内置支持
# cmake -DCMAKE_SYSTEM_NAME=Android \
# -DCMAKE_SYSTEM_VERSION=29 \
# -DCMAKE_ANDROID_ARCH_ABI=x86_64 \
# -DANDROID_NDK=$ANDROID_NDK \
# -DCMAKE_ANDROID_STL_TYPE=c++_shared \
# ..
# x86_64 armeabi-v7a
# 工具链文件支持
cmake \
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a \
-DANDROID_PLATFORM=android-29 \
-DANDROID_STL=c++_shared \
..
cmake --build .
执行脚本./build_led_test.sh
会在build目录下生成 leddrvtest 可执行文件
adb push leddrvtest /data/local/tmp
在/data/local/tmp 目录下执行./leddrvtest -w red
可以看到红灯点亮