Rk3568驱动开发_GPIO点亮LED_12

需求:

用配置寄存器方式控制点灯非常原始,现在采用更方便的Linux提供的pctrl和gpio子系统编写字符驱动

1.设备树配置:
在这里插入图片描述
现将开发板中呼吸灯关闭掉防止占用到我需要使用的引脚

在这里插入图片描述

	/* Narnat 2025-5-29 RK3568 GPIO 无需设置pinctrl*/gpioled{compatible = "atkrk3568-gpio-led";led-gpio = <&gpio0 RK_PC0 GPIO_ACTIVE_HIGH>;status = "okay";};

下图为设备树中GPIO0的地址
在这里插入图片描述

在设备树根节点下添加gpioled节点,标明引脚,配置完设备树后将kernel单独编译,将生成的boot.img烧到设备中可以看到如下节点:
在这里插入图片描述
可以用cat读取相关信息

2.驱动编写:

驱动中需要读取上述gpioled设备节点找到对应的引脚,向内核申请这个引脚的使用权gpio_request(gpioled.led_gpio, “LED-GPIO”);这样能防止多个驱动程序抢夺一个引脚问题,申请使用权成功后就能使用Linux自带的GPIO函数了ret = gpio_direction_output(gpioled.led_gpio, 0);然后就是在/dev目录下创建设备节点了,创建设备节点分为:创建设备号、初始化并添加字符驱动、创建类、创建设备

驱动代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define GPIOLED_CNT    1   // 设备号数目
#define GPIOLED_NAME   "gpioled" // 名字
#define LEDOFF         0 // 关灯
#define LEDON          1 // 开灯struct gpioled_dev{  // 设备结构体dev_t devid;       // 设备号int major;         // 主设备号int minor;         // 次设备号struct cdev cdev;  // 字符设备struct class* class; // 类struct device_node* nd; // 设备节点struct device* device; // 设备int led_gpio;  // led所使用的编号
};struct gpioled_dev gpioled; // led设备static int led_open(struct inode* inode, struct file* filp){filp->private_data = &gpioled; // 设置私有数据return 0;
}static ssize_t led_read(struct file* filp, char __user* buf, size_t cnt, loff_t* offt){return 0;
}static ssize_t led_write(struct file* filp, const char __user* buf, size_t cnt, loff_t* offt){int retvalue;unsigned char databuf[1];unsigned char ledstat;struct gpioled_dev* dev = filp->private_data;retvalue = copy_from_user(databuf, buf, cnt);if(retvalue < 0){printk("kernel write failed \r\n");return -1;}ledstat = databuf[0];if(ledstat == LEDON){gpio_set_value(dev->led_gpio, 1); // 打开LED}else if(ledstat == LEDOFF){gpio_set_value(dev->led_gpio, 0); // 关灯}return 0;
}static int led_release(struct inode* inode, struct file* filp){return 0;
}static struct file_operations gpioled_fops = { // 设备操作函数.owner = THIS_MODULE,.open = led_open,.read = led_read,.write = led_write,.release =  led_release,
};static int __init led_init(void){int ret = 0;const char* str;/* 设置LED所使用的GPIO */// 1.获取设备节点gpioled.nd = of_find_node_by_path("/gpioled");if(gpioled.nd == NULL){printk("gpioled node not find \r\n");return -1;}// 2.读取status属性ret = of_property_read_string(gpioled.nd, "status", &str);if(ret < 0){printk("read status error \r\n");return -1;}if(strcmp(str, "okay")){printk("status is not okay \r\n");return -1;}// 3.读取compatible属性值ret = of_property_read_string(gpioled.nd, "compatible", &str);if(ret < 0){printk("read compatible error \r\n");return -1;}if(strcmp(str, "atkrk3568-gpio-led")){printk("compatible is not atkrk3568-gpio-led \r\n");return -1;}//4.获取设备树中的gpio属性,得到LED所使用的LED编号gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); // 0取第一个if(gpioled.led_gpio < 0){printk("cant get led-gpio \r\n");return -1;}printk("led-gpio num = %d \r\n", gpioled.led_gpio);//5.向gpio子系统申请使用GPIO 当前驱动独自占有此驱动ret = gpio_request(gpioled.led_gpio, "LED-GPIO");if(ret){printk("request led-gpio failed \r\n");return -1;}//6.设置GPIO为输出,并且输出低电平,关闭LED灯ret = gpio_direction_output(gpioled.led_gpio, 0);if(ret < 0){printk("cant set gpio \r\n");return -1;}/* 注册字符设备驱动 */// 1.创建设备号if(gpioled.major){gpioled.devid = MKDEV(gpioled.major, 0);ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME); // 注册字符设备号if(ret < 0){gpio_free(gpioled.led_gpio);printk("cant register %s char driver ret = %d \r\n", GPIOLED_NAME, ret);return -1;}}else{ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);  // 申请设备号if(ret < 0){gpio_free(gpioled.led_gpio);printk("cant alloc_chrdev_region %s, ret = %d \r\n", GPIOLED_NAME, ret);return -1;}gpioled.major = MAJOR(gpioled.devid);gpioled.minor = MINOR(gpioled.devid); // 获取主次设备号}printk("%s gpioled major = %d, minnor=%d \r\n", GPIOLED_NAME, gpioled.major, gpioled.minor);// 2.初始化字符驱动gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev, &gpioled_fops);// 3.添加一个字符驱动cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);if(ret < 0){  // 添加失败unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); // 注销掉设备号gpio_free(gpioled.led_gpio);return -1;}// 4.创建类gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if(IS_ERR(gpioled.class)){ // 创建类失败cdev_del(&gpioled.cdev); // 删掉字符驱动unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); // 注销掉设备号gpio_free(gpioled.led_gpio);return -1;}// 5.创建设备gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);if(IS_ERR(gpioled.device)){ // 设备创建失败class_destroy(gpioled.class); // 删掉类cdev_del(&gpioled.cdev); // 删掉字符驱动unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); // 注销掉设备号gpio_free(gpioled.led_gpio);return -1;}return 0;
}static void __exit led_exit(void){device_destroy(gpioled.class, gpioled.devid); // 注销设备class_destroy(gpioled.class); // 删掉类cdev_del(&gpioled.cdev); // 删掉字符驱动unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); // 注销掉设备号gpio_free(gpioled.led_gpio);
}module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Narnat");

在这里插入图片描述

应用层代码:略

开灯关灯命令:

在这里插入图片描述
效果图:略

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

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

相关文章

阿里云ACP云计算备考笔记 (3)——云存储RDS

目录 第一章 云存储概览 1、云存储通用知识 ① 发展历史 ② 云存储的优势 2、云存储分类 3、文件存储业务场景 第二章 块存储 1、块存储分类 2、云盘的优势 3、创建云盘 4、管理数据盘 ① 格式化数据盘 ② 挂载数据盘 ③ 通过 API 挂载云盘 5、管理系统盘 ① 更…

亚矩阵云手机实测体验:稳定流畅背后的技术逻辑​

最近在测试一款云手机服务时&#xff0c;发现亚矩阵的表现出乎意料地稳定。作为一个经常需要多设备协作的开发者&#xff0c;我对云手机的性能、延迟和稳定性要求比较高。经过一段时间的体验&#xff0c;分享一下真实感受&#xff0c;避免大家踩坑。 ​​1. 云手机能解决什么问…

STM32H562----------ADC外设详解

1、ADC 简介 STM32H5xx 系列有 2 个 ADC,都可以独立工作,其中 ADC1 和 ADC2 还可以组成双模式(提高采样率)。每个 ADC 最多可以有 20 个复用通道。这些 ADC 外设与 AHB 总线相连。 STM32H5xx 的 ADC 模块主要有如下几个特性: 1、可配置 12 位、10 位、8 位、6 位分辨率,…

【Android】双指旋转手势

一&#xff0c;概述 本文参考android.view.ScaleGestureDetector&#xff0c;对双指旋转手势做了一层封装&#xff0c;采用了向量计算法简单实现&#xff0c;笔者在此分享下。 二&#xff0c;实例 如下&#xff0c;使用RotateGestureDetector即可委托&#xff0c;实现旋转手…

B站的视频怎么下载下来——Best Video下载器

B站&#xff08;哔哩哔哩&#xff09;作为国内最受欢迎的视频平台之一&#xff0c;聚集了无数优质内容&#xff1a;动漫番剧、游戏实况、学习课程、纪录片、Vlog、鬼畜剪辑……总有那么些视频让人想反复观看、离线观看&#xff0c;甚至剪辑创作。 但你是否遇到过这样的烦恼&am…

基于SFC的windows系统损坏修复程序

前言 在平时使用Windows操作系统时会遇到很多因为系统文件损坏而出现的错误 例如:系统应用无法打开 系统窗口(例如开始菜单)无法使用 电脑蓝屏或者卡死 是如果想要修复很多人只能想到重装系统。但其实Windows有一个内置的系统文件检查器可以修复此类错误。 原理 SFC命令…

智绅科技 —— 智慧养老 + 数字健康,构筑银发时代安全防护网

在老龄化率突破 21.3% 的当下&#xff0c;智绅科技以 "科技适老" 为核心理念&#xff0c;构建 "监测 - 预警 - 干预 - 照护" 的智慧养老闭环。 其自主研发的七彩喜智慧康养平台&#xff0c;通过物联网、AI 和边缘计算技术&#xff0c;实现对老年人健康与安…

用函数实现模块化程序设计(适合考研、专升本)

函数 定义&#xff1a;本质上是一段可以被连续调用、功能相对独立的程序段 c语言是通过“函数”实现模块化的。根据分类标准不同函数分为以下几类。 用户角度&#xff1a;库函数、自定义函数 函数形式&#xff1a;有参函数、无参函数 作用域&#xff1a;外部函数、内部函数 …

OpenCV 滑动条调整图像亮度

一、知识点 1、int createTrackbar(const String & trackbarname, const String & winname, int * value, int count, TrackbarCallback onChange 0, void * userdata 0); (1)、创建一个滑动条并将其附在指定窗口上。 (2)、参数说明: trackbarname: 创建的…

vcs仿真产生fsdb波形的两种方式

目录 方法一&#xff1a; 使用verilog自带的系统函数 方法二&#xff1a; 使用UCLI command 2.1 需要了解什么是vcs的ucli&#xff0c;怎么使用ucli&#xff1f; 2.2 使用ucli dump波形的方法 使用vcs仿真产生fsdb波形有两种方式&#xff0c;本文参考《vcs user guide 20…

【前端】每日一道面试题6:解释Promise.any和Promise.allSettled的使用场景及区别。

Promise.any() 和 Promise.allSettled() 是 JavaScript 中用于处理异步操作的两种不同策略的 Promise 组合器&#xff0c;它们的核心区别在于逻辑目标与结果处理方式&#xff1a; 1. Promise.any() 使用场景&#xff1a; 需要获取 首个成功结果&#xff08;类似竞速成功优先&…

数据链路层__

文章目录 数据链路层基本概念&#xff08;1&#xff09;链路管理&#xff1a;面向连接的服务&#xff08;2&#xff09;帧同步&#xff1a;成帧1、字符计数法2、字符填充法&#xff08;带填充的首尾界符法&#xff09;3、带填充的首位标志法4、物理层编码违例法 &#xff08;3&…

coze智能体后端接入问题:

是否一定要按照coze官方API文档格式调用&#xff1f; 不一定&#xff1a;以下面代码为例(给了注释) app.route(/compare_models, methods[POST]) def compare_models():print("收到 compare_models 请求&#xff01;") #begin-这一部分代码作用&#xff1a;从前端接…

如何轻松、安全地管理密码(新手指南)

很多人会为所有账户使用相同、易记的密码&#xff0c;而且常常多年不换。虽然这样方便记忆&#xff0c;但安全性非常低。 您可能听说过一些大型网站的信息泄露事件&#xff0c;同样的风险也可能存在于您的WordPress网站中。如果有不法分子获取了访问权限&#xff0c;您的网站和…

宝塔think PHP8 安装使用FFmpeg 视频上传

宝塔think PHP8 安装使用FFmpeg 一、 安装think PHP8二、安装 FFmpeg1&#xff0c;登录到宝塔面板。2&#xff0c;进入“软件商店”。3&#xff0c;搜索“FFmpeg”。4&#xff0c;选择版本点击安装。5&#xff0c;检查 FFmpeg 是否安装成功6&#xff0c; 在 ThinkPHP 8 中使用 …

Android 轻松实现 增强版灵活的 滑动式表格视图

表格视图组件&#xff0c;支持&#xff1a; 1. 无标题模式&#xff1a;只有数据行也可以正常滑动 2. 两种滑动模式&#xff1a;固定第一列 或 全部滑动 3. 全面的样式自定义能力 4. 智能列宽计算 1. 无标题模式支持 设置无标题&#xff1a;调用 setHeaderData(null) 或 …

【Python进阶】元类编程

目录 &#x1f31f; 前言&#x1f3d7;️ 技术背景与价值&#x1fa79; 当前技术痛点&#x1f6e0;️ 解决方案概述&#x1f465; 目标读者说明 &#x1f9e0; 一、技术原理剖析&#x1f4ca; 核心概念图解&#x1f4a1; 核心作用讲解&#x1f527; 关键技术模块说明⚖️ 技术选…

DeepSeek模型性能优化:从推理加速到资源调度的全栈实践

引言 在生产环境中部署DeepSeek模型时,性能优化直接关系到服务质量和运营成本。本文将深入探讨从芯片级优化到分布式调度的全栈性能提升方案,涵盖计算图优化、内存管理、批处理策略等关键技术,并分享在千万级QPS场景下的实战经验,帮助工程团队突破性能瓶颈,实现成本与效能…

Ctrl+R 运行xxx.exe,发现有如下问题.

CtrlR 运行xxx.exe,发现有如下问题. (1)找不到Qt5Core.all,Qt5Cored.dll,Qt5Gui.dll,Qt5Guid.dll,Qt5Widgets.all,Qt5Widgetsd.dll? (2)之后找不到libwinpthread-1.dll 从这个目录拷贝相应的库到运行xx.exe目录下 方法二:将库路径添加到系统PATH环境变量里: 在Path中添加路…

硅基计划2.0 学习总结 陆 抽象类与接口

文章目录 一、抽象类1. 定义2. 示例代码3. 特性 二、接口初识1. 定义2. 命名与语法3. 示例代码4. 常见特性5. 多接口实现6. 接口的继承 三、Object类初识1. equals方法2. hascode方法 一、抽象类 1. 定义 请你假设这样一个场景&#xff0c;我们定义一个人的类&#xff0c;这个…