linxu驱动入门基础课一(GPIO控制LED灯)基于RK3568

news2024/9/29 7:19:04

虽然GPIO控制LED 是最简单的linux驱动,但是是初学者入门必须跨过的门槛,里面很多基础知识点,有GPIO的控制原理,字符设备驱动,设备树,gpio和pinctrl子系统,内核模块原理等等,这些知识点非常重要,都是linux驱动入门的基础。

下面我们就可以一步步来写一个GPIO控制LED的驱动。

在RK3568平台上从零开始编写LED驱动,可以按照以下步骤进行:

1.原理图

led灯利用I2C3_SDA_MO引脚即GPIO1_A0

LED灯正极接GPIO1_A0,GPIO1_A0高电平点亮LED灯,低电平熄灭LED灯。

2.编写驱动代码

  • 创建一个新的驱动文件在kernel/drivers/char/下面,led_gpio.c
#include <linux/init.h>
#include <linux/of.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/uaccess.h>

char kbuf[1] ;
dev_t devno;
int major = 0;
int led_gpio;

int gpio_led_open(struct inode *inode, struct file *file)/* 对应的是应用程序的open*/
{
	printk("gpio led open !\\n");
	return 0;
}
int gpio_led_release(struct inode *inode, struct file *file) /* 对应的是应用程序的close*/
{
	printk("gpio led close !\\n");
	return 0;
}

ssize_t gpio_led_write(struct file *file, const char __user *buf,size_t size,loff_t *pos)
{
	int ret = 0;
	if(size > sizeof(kbuf))
		size = sizeof(kbuf);
	ret = copy_from_user(kbuf,buf,size);

	gpio_set_value(led_gpio,kbuf[0]);
	printk("[led-gpio] write %d !\\n",kbuf[0]);
	return size;
}

ssize_t gpio_led_read(struct file *file,  char __user *buf,size_t size,loff_t *pos)
{
	int ret = 0;
	if(size > sizeof(kbuf))
		size = sizeof(kbuf);
	ret = copy_to_user(buf,kbuf,size);
	printk("[led-gpio] read %d !\\n",kbuf);
	return size;
}
int gpio_led_init(void)
{
	return 0;
}

int gpio_led_on(int ledno)
{
	
	return 0;
}

int gpio_led_off(int ledno)
{

	return 0;
}

#define LED_OFF 0
#define LED_ON 1

long gpio_led_ioctl(struct file *file, unsigned int cmd, unsigned long ledno)
{
	printk("cmd = %d data = %ld\\n", cmd, ledno);
	switch(cmd){
		case LED_OFF:
			gpio_led_off(ledno);
			break;
		case LED_ON:
			gpio_led_on(ledno);
			break;
	    default:
			printk("Invalid cmd\\n");
			break;
	}

	return ledno;
}

struct cdev led_cdev;
struct file_operations fops = {
	.open = gpio_led_open,
	.release = gpio_led_release,
	.unlocked_ioctl = gpio_led_ioctl,
	.write = gpio_led_write,
	.read = gpio_led_read,
};

struct class * pcls;
struct device * pled_dev;

struct device_node *test_device_node;
struct property *test_node_property;

int gpio_led_probe(struct platform_device *pdev) 	/*match成功会调用 到*/
{
	int i = 0;
	int ret;
	printk("gpio led driver probe\\n");	
	
	/*1- 字符设备初始化*/
	major = register_chrdev(0, "gpio-led", &fops);//cat /proc/devices
	devno = MKDEV(major, 0);
	printk("[led-gpio]major from register chrdev:%d\\n", major);

	/*2- 自动创建设备节点 /dev/gpio-led-auto*/
	pcls = class_create(THIS_MODULE, "led-cls");
	pled_dev = device_create(pcls, NULL, devno, NULL, "gpio-led-platform");

	/*3 -0 led硬件初始化*/
	gpio_led_init();
	
	test_device_node = of_find_node_by_path("/led-gpio");
	if (test_device_node == NULL)
	{	
		printk("[led-gpio]of_find_node_by_path is error \\n");
		return -1;
	}

	led_gpio = of_get_named_gpio(test_device_node, "gpios", 0);
	if (led_gpio < 0)
	{
		printk("[led-gpio]of_get_named_gpio is error \\n");
		return -1;
	}

	printk("[led_gpio] is %d \\n", led_gpio);

	ret = gpio_request(led_gpio, "led-gpio");
	if (ret < 0)
	{
		printk("[led-gpio]gpio_request is error \\n");
		return -1;
	}
       ret = 	gpio_direction_output(led_gpio, 1);
       if(ret < 0){

	      printk("[led-gpio] output error\\n");
	      return -1;
       }
	gpio_set_value(led_gpio,1);

	return 0;
}

int gpio_led_remove(struct platform_device *pdev)/*unmatch 时会调用*/
{
	printk("[led-gpio]gpio led driver remove\\n");
	unregister_chrdev(major, "gpio-led");

	device_destroy(pcls, devno);
	class_destroy(pcls);

	return 0;
}
int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
{
	printk("[led-gpio]gpio led driver suspend\\n");	

		
	return 0;
}
int gpio_led_resume(struct platform_device *pdev)
{
	printk("[led-gpio]gpio led driver resume\\n");

	return 0;
}
struct of_device_id led_tbl[]={
		{.compatible = "led-gpio",},
};

struct platform_driver pdrv= {
	.probe = gpio_led_probe,
	.remove = gpio_led_remove,
	.suspend = gpio_led_suspend,
	.resume = gpio_led_resume,
	.driver.name = "gpio-led",
	.driver.of_match_table = led_tbl,
};

static __init int  gpio_led_driver_init(void)
{
	printk(" platform driver module init!\\n");
	platform_driver_register(&pdrv);
	return 0;
}
static __exit void  gpio_led_driver_exit(void)
{
	printk(" platform driver module exit!\\n");	
	platform_driver_unregister(&pdrv);
}

MODULE_LICENSE("GPL");
module_init(gpio_led_driver_init);
module_exit(gpio_led_driver_exit);

修改kernel/drivers/char/Makefile,加入下面一句

obj-y += led-gpio.o

3.设备树配置

  • 在设备树文件中添加LED设备节点。

kernel/arch/arm64/boot/dts/rockchip/rk3568-evb1-ddr4-v10.dtsi

/ {
        model = "Rockchip RK3568 EVB1 DDR4 V10 Board";
        compatible = "rockchip,rk3568-evb1-ddr4-v10", "rockchip,rk3568";

        **led_gpio:led-gpio {
            compatible = "led-gpio";
            gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>;
            pinctrl-names = "default";
            pinctrl-0 = <&led_gpio_ctrl>;
        };**

&pinctrl {

        **led-gpio {
                led_gpio_ctrl: led-gpio-ctrl {
                        rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };**

4.编译驱动

./build.sh kernel

5.烧写镜像

6.编写APP测试

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
  int fd;
  char status;

  if (argc != 3)
  {
    printf("Usage: %s <dev> <on | off>\\n", argv[0]);
    return -1;
  }

  fd = open(argv[1], O_RDWR);
  if (fd == -1)
  {
    printf("can not open file %s\\n", argv[1]);
    return -1;
  }

  if (0 == strcmp(argv[2], "on"))
  {
    status = 1;
    write(fd, &status, 1);
  }
  else
  {
    status = 0;
    write(fd, &status, 1);
  }

  close(fd);

  return 0;
}

编译APP

aarch64-linux-gnu-gcc ledtest.c -o  ledtest

7.测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1908947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

APP明暗主题设置

1.preference.xml 增加一个暗色主题 SwitchPreference 2.每个 Activity 的 setContentView 前面增加 setTheme SharedPreferences sharedPreferences PreferenceManager.getDefaultSharedPreferences(this); if (sharedPreferences.getBoolean("switch_dark_theme"…

Windows下编译OpenSSL静态库

目录 1. 版本与下载地址 2. 下载与安装VS2015 3. 下载与安装Perl 4. 测试ActivePerl是否安装正确 5. 下载OpenSSL 6. 编译32位OpenSSL静态库 6.1 解压openssl-1.0.2l.tar.gz 6.2 打开VS2015 x86本机工具命令提示符 6.3 输入命令进入到openssl的目录中 6.4 执行配置命…

加密与安全_密钥体系的三个核心目标之不可否认性解决方案

文章目录 Pre概述不可否认性数字签名&#xff08;Digital Signature&#xff09;证书是什么证书使用流程 PKICA证书层级多级证书证书链是如何完成认证的&#xff1f; 其他疑问1. Alice能直接获取Bob的公钥&#xff0c;是否还需要证书&#xff1f;2. 为什么即使能直接获取公钥也…

世界人工智能大会 | 江行智能大模型解决方案入选“AI赋能新型工业化创新应用优秀案例”

日前&#xff0c;2024世界人工智能大会暨人工智能全球治理高级别会议在上海启幕。本次大会主题为“以共商促共享&#xff0c;以善治促善智”&#xff0c;汇聚了上千位全球科技、产业界领军人物&#xff0c;共同探讨大模型、数据、新型工业化等人工智能深度发展时代下的热点话题…

CLIP编码器调用时刚开始正常,然后输出全部变为NaN

碰到了这个问题&#xff1a;输入是正常的&#xff0c;输出全是NaN 网上办法不多&#xff0c;找了半天终于看到问题所在&#xff0c;但是没有说在哪里改的&#xff0c;故记录一下。 改一下模型精度就正常了&#xff0c;默认的是fp16&#xff0c;改为fp32即可 具体步骤如下&…

渲染引擎之ECS架构介绍

1.什么是ECS&#xff1f; 我们先简单地介绍一下什么是ECS&#xff1a; E -- Entity 实体&#xff0c;本质上是存放组件的容器C -- Component 组件&#xff0c;引擎所需的所有数据结构S -- System 系统&#xff0c;根据组件数据处理逻辑状态的管理器 ECS全称Entity-Component-…

免费压缩pdf文件大小软件收费吗?pdf如何压缩文件大小?12款压缩应用推荐!

在数字化时代&#xff0c;PDF文件因其跨平台、格式统一的特点而广受欢迎。然而&#xff0c;随着文件内容的增加&#xff0c;PDF文件的大小也逐渐增大&#xff0c;给存储和传输带来了诸多不便。因此&#xff0c;寻找一款合适的PDF压缩软件成为了许多用户的需求。本文将详细介绍1…

阿里开源语音理解和语音生成大模型FunAudioLLM

近年来&#xff0c;人工智能&#xff08;AI&#xff09;的进步极大地改变了人类与机器的互动方式&#xff0c;例如GPT-4o和Gemin-1.5等。这种转变在语音处理领域尤为明显&#xff0c;其中高精度的语音识别、情绪识别和语音生成等能力为更直观、更类人的交互铺平了道路。阿里开源…

# 昇思25天学习打卡营第10天 | 使用静态图加速

昇思25天学习打卡营第10天 | 使用静态图加速 文章目录 昇思25天学习打卡营第10天 | 使用静态图加速动态图的开启方式静态图的开启方式基于全局context的开启方式基于修饰器的开启方式 总结打卡 AI编译框架分为两种运行模式&#xff1a; 动态图模式&#xff1a; 计算图的构建和计…

C语言 | Leetcode C语言题解之第224题基本计算器

题目&#xff1a; 题解&#xff1a; int calculate(char* s) {int n strlen(s);int ops[n], top 0;int sign 1;ops[top] sign;int ret 0;int i 0;while (i < n) {if (s[i] ) {i;} else if (s[i] ) {sign ops[top - 1];i;} else if (s[i] -) {sign -ops[top - 1…

android文本长按复制

android文本长按复制 &#x1f4d6;1. 长按直接复制✅步骤一&#xff1a;定义一个TextView✅步骤二&#xff1a;为TextView注册长按事件✅步骤三&#xff1a;弹出系统复制功能 &#x1f4d6;2. 长按弹框确认复制✅步骤一&#xff1a;定义一个TextView✅步骤二&#xff1a;封装P…

3d模型设计要注意什么?---模大狮模型网

展览3D模型设计作为现代展示和艺术表达的重要手段&#xff0c;不仅仅是简单的视觉元素&#xff0c;更是整个展览体验的核心。在这个领域&#xff0c;设计师需要综合考虑美学、功能性以及技术实现的多重因素。本文将探讨在展览3D模型设计过程中需要注意的关键要点。 一、美学与视…

70.WEB渗透测试-信息收集- WAF、框架组件识别(10)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;69.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;9&#xff09; 关于waf相应的识…

Java并发/多线程CompleteableFuture详解

目录 CompleteableFuture 创建 获得结果的方法 辅助方法 allOf和anyOf的区别 CompletableFuture 里大约有五十种方法&#xff0c;但是可以进行归类: 变换类 thenApply 消费类 thenAccept 执行操作类 thenRun thenApply/thenAccept/thenRun 结合转化类 thenCombine 结…

C++ 类和对象 构造 / 析构函数

一 类的6个默认成员函数&#xff1a; 如果一个类中什么成员都没有&#xff0c;简称为空类。 例&#xff1a; #include <iostream> class Empty {// 空类&#xff0c;什么成员都没有 }; 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&a…

使用预加载库优化 PostgreSQL 函数#postgresql认证

在 POSTGRESQL 中执行函数和过程 为了理解 PostgreSQL 的工作原理&#xff0c;我们首先要看一个简单的函数调用。下一个清单显示了一些简单的PostGIS代码&#xff1a; PgSQL test# timing Timing is on. test# SELECT * FROM hans.points WHERE id 1;id │ …

南大通用数据库-Gbase-8a-学习-44-DDLEVENT恢复

目录 一、环境信息 二、前景提要 1、情况描述 2、3号节点gc_recover日志截图 3、3号节点express日志截图 4、ddlevent截图 5、报错赋权语句分别在1节点和4节点执行 6、gcadmin 三、解决方法 1、描述 2、清理系统user表DDLEVENT 3、拷贝系统user表数据 &#xff08;…

【游戏客户端】大话slg玩法架构(一)滚动基类

【游戏客户端】大话slg玩法架构&#xff08;一&#xff09;滚动基类 大家好&#xff0c;我是Lampard家杰~~ 今天我们兑现诺言&#xff0c;给大家分享SLG玩法的实现j架构&#xff0c;关于SLG玩法的介绍可以参考这篇上一篇文章&#xff1a;【游戏客户端】制作率土之滨Like玩法 PS…

React -- useState状态更新异步特性——导致获取值为旧值的问题

useState状态异步更新 问题导致的原因解决办法进一步分析后续遇到的新问题 问题 const [isSelecting, setIsSelecting] useState(false);useEffect(() > {const handleKeyDown (event) > {if (event.key Escape) {if(isSelectingRef){//.......setIsSelecting(!isSele…

项目机会:4万平:智能仓,AGV,穿梭车,AMR,WMS,提升机,机器人……

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 如下为近期国内智能仓储物流相关项目的公开信息线索&#xff0c;这些项目具体信息会发布到知识星球&#xff0c;请感兴趣的球友先人一步到知识星球【智能仓储物流技术研习社】自行下载…