嵌入式驱动学习第七周——GPIO子系统

前言

   GPIO子系统是用来统一便捷地访问实现输入输出中断等效果。

   嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!

目录

  • 前言
  • GPIO子系统介绍
  • 设备树格式
  • API函数
  • pinctrl和gpio子系统示例
    • 设备树部分
    • 平台驱动框架
    • probe和remove函数实现
    • open,write等函数
  • 参考资料

GPIO子系统介绍

   之前介绍过pinctrl子系统是用来控制IO的复用功能以及一些电气属性的,那么配置完成之后,如果是GPIO的话就需要发挥功能,这些功能就包括输出、输入、触发中断

   gpio子系统顾名思义就是用于初始化GPIO并提供相应的API函数,用于设置GPIO为输入输出、读取GPIO的值。其目的是方便驱动开发者使用gpio,驱动开发者在设备树中添加gpio相关信息,然后就可以在驱动程序中使用gpio子系统提供的API函数来操作GPIO,Linux内核向驱动开发者屏蔽掉了GPIO的设置过程。

设备树格式

   查看原理图,发现LED是低电平触发,连接的GPIO是GPIO_3GPIO1_IO3。因此在GPIO子系统中,我们需要将GPIO1_IO3设置为低电平触发。

在这里插入图片描述

   在设备节点下,添加GPIO子系统,根据上面的原理图,我们设置GPIO1组的3口为低电平触发

gpioled {#address-cells = <1>;#size-cells = <1>;compatible = "atkmini-gpioled";pinctrl-names = "default";pinctrl-0 = <&pinctrl_led>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;		// GPIO子系统status = "okay";
};

   其中必须指定&gpio1,其他可以不作要求。

   接下来打开imx6ul.dtsi文件,查看gpio1:

gpio1: gpio@0209c000 {compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";reg = <0x0209c000 0x4000>;interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;
};

   上面代码中,gpio@0209c000表示gpio1的基地址,#gpio-cells 为 2,表示一共有两个 cell。第一个 cell 为 GPIO 编号,比如“&gpio1 3”就表示GPIO1_IO03。第二个 cell 表示 GPIO 极性 , 如果为0(GPIO_ACTIVE_HIGH) 的话表示高电平有效 , 如果为1(GPIO_ACTIVE_LOW)的话表示低电平有效。

API函数

/** @description  : 获取GPIO编号* @param-np     : 指定设备节点* @param-proname: GPIO属性名,与设备树中对应的属性名对应* @param-index	 : 引脚索引* @return       : 成功的话获取GPIO编号,失败的话返回负数*/
static inline int of_get_named_gpio(struct device_node *np, const char * proname, int index)
/** @description: GPIO申请函数* @param-gpio : 要申请的GPIO编号,该值是函数of_get_named_gpio的返回值* @param-label: 引脚名字,相当于为申请得到的引脚取了别名* @return     : 成功的话返回0,失败的话返回负数*/
static inline int gpio_request(unsigned gpio, const char *label)
/** @description: 释放GPIO* @param-gpio : 要释放的GPIO编号*/
static inline void gpio_free(unsigned gpio);
/** @description: GPIO输出设置函数* @param-gpio : 要设置的GPIO编号* @param-value: 输出值,1,表示高电平,0,表示低电平* @return     : 成功的话返回0,失败的话返回负数*/
static inline int gpio_direction_output(unsigned gpio , int value)
/** @description: GPIO输入设置函数* @param-gpio : 要设置的GPIO编号* @return     : 成功的话返回0,失败的话返回负数*/
static inline int gpio_direction_input(unsigned gpio)
/** @description: 获取GPIO引脚值* @param-gpio : 要设置的GPIO编号* @return     : 成功的话返回得到的引脚状态,失败的话返回负数*/
static inline int gpio_direction_input(unsigned gpio)
/** @description: 设置GPIO输出值* @param-gpio : 要设置的GPIO编号* @param-value: 设置的输出值,1为输出高电平,0为输出低电平* @return     : 成功的话返回0,失败的话返回负数*/
static inline int gpio_direction_output(unsigned gpio, int value)

pinctrl和gpio子系统示例

设备树部分

   在根目录下创建gpioled的子节点,其中compatible命名为"atkmini-gpioled"

gpioled {#address-cells = <1>;#size-cells = <1>;compatible = "atkmini-gpioled";pinctrl-names = "default";pinctrl-0 = <&pinctrl_led>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;status = "okay";
};

   同时在其中使用pinctrl子系统和gpio子系统,pinctrl子系统的节点命名为pinctrl_led,具体如下所示。同时使用gpio子系统规定GPIO的状态,前面的硬件图可以看到,LED是GPIO1_IO3,并且是低电平点亮,因此设置为GPIO_ACTIVE_LOW

   接下来看pinctrl子系统中设置的节点,需要在&iomuxc中添加,因为配置复用和电器属性是iomuxc寄存器

&iomuxc {...pinctrl_led: ledgrp {fsl,pins = <MX6UL_PAD_GPIO1_IO03__GPIO1_IO03	0x10B0>;};...
}

平台驱动框架

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define LEDDEV_CNT      1
#define LEDDEV_NAME     "dtsplatled"
#define LEDOFF          0
#define LEDON           1struct leddev_dev {dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node *nd;int led0;
};struct leddev_dev leddev;static const struct of_device_id led_of_match[] = {{.compatible = "atkmini-gpioled"},				// 与设备树中的节点对应{}
};static struct platform_driver led_driver = {.driver   = {.name = "imx6ul-led",.of_match_table = led_of_match,},.probe    = led_probe,.remove   = led_remove,
};// 驱动入口函数,注册platform
static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}// 驱动出口函数,释放platform
static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);
}module_init(leddriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wp");

probe和remove函数实现

    probe函数中,使用of_find_node_by_path函数找到并获取gpioled在设备树中的设备节点。之后使用of_get_named_gpio函数获取GPIO号,读取成功则返回读取得到的GPIO号。同时用gpio_direction_output函数设置gpio为输出模式,默认输出高电平。

static int led_probe(struct platform_device *dev)
{printk("led driver and device was matched!\r\n");if (leddev.major) {leddev.devid = MKDEV(leddev.major, 0);register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);} else {alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);leddev.major = MAJOR(leddev.devid);leddev.minor = MINOR(leddev.minor);}cdev_init(&leddev.cdev, &led_fops);cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);if (IS_ERR(leddev.class)) {return PTR_ERR(leddev.class);}leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);if (IS_ERR(leddev.device)) {return PTR_ERR(leddev.device);}leddev.nd = of_find_node_by_path("/gpioled");if (leddev.nd == NULL) {printk("gpioled node not find!\r\n");return -EINVAL;}leddev.led0 = of_get_named_gpio(leddev.nd, "led-gpio", 0);			// 获取GPIO的IO标号if (leddev.led0 < 0) {printk("can't get led-gpio\r\n");return -EINVAL;}gpio_request(leddev.led0, "led0");									// 注册IO口gpio_direction_output(leddev.led0, 1);								// 设置GPIO输出默认为1						return 0;
}static int led_remove(struct platform_device *dev)
{gpio_free(leddev.led0);										// 释放GPIO				cdev_del(&leddev.cdev);unregister_chrdev_region(leddev.devid, LEDDEV_CNT);device_destroy(leddev.class, leddev.devid);class_destroy(leddev.class);return 0;
}

open,write等函数

    首先写一个led状态翻转函数,用gpio_set_value函数设置led的输出逻辑值

void led0_switch(u8 sta)
{if (sta == LEDON)gpio_set_value(leddev.led0, 0);				// 设置gpio,第二个参数是逻辑值,0表示关,1表示开else if (sta == LEDOFF)gpio_set_value(leddev.led0, 1);
}

    然后定义open,write函数,write函数中是从用户态读取数据,然后按照当前状态翻转LED状态。

static int led_open(struct inode *inode, struct file *filp)
{filp->private_data = &leddev;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[2];unsigned char ledstat;retvalue = copy_from_user(databuf, buf, cnt);if (retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];if (ledstat == LEDON) {led0_switch(LEDON);} else if (ledstat == LEDOFF) {led0_switch(LEDOFF);}return 0;
}static struct file_operations led_fops = {.owner = THIS_MODULE,.open  = led_open,.write = led_write,
};

参考资料

[1] 【正点原子】I.MX6U嵌入式Linux驱区动开发指南 第四十五章
[2] 【Linux驱动开发】011 gpio子系统
[3] pinctrl子系统和gpio子系统-led实验

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

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

相关文章

spring boot整合Redis监听数据变化

一、前言 Redis提供了数据变化的通知事件&#xff0c;可以实时监测key和value的变化&#xff0c;客户端可以通过订阅相关的channel来接收这些通知事件&#xff0c;然后做相应的自定义处理&#xff0c;详细的介绍可以参考官方文档Redis keyspace notifications | Docs 使用Red…

httpsok-快速申请谷歌SSL免费证书

&#x1f525;httpsok-快速申请谷歌SSL免费证书 使用场景&#xff1a; 部署CDN证书、OSS云存储证书证书类型&#xff1a; 单域名 多域名 通配符域名 混合域名证书厂商&#xff1a; ZeroSSL Lets Encrypt Google证书加密类型&#xff1a; ECC、 RSA 一、证书管理 进入 证书管…

【数学建模】2024Mathorcup数学建模C题完整思路与代码论文解析

2024Mathorcup数学应用挑战赛C题|图神经网络的预测模型ARIMA时间序列预测模型人员排班混合整数规划模型|完整代码和论文全解全析 我们已经完成了2024Mathorcup数学建模挑战赛C题的40页完整论文和代码&#xff0c;相关内容可见文末&#xff0c;部分图片如下&#xff1a; 问题分…

[蓝桥杯] 岛屿个数(C语言)

提示&#xff1a; 橙色字体为需要注意部分&#xff0c;红色字体为难点部分&#xff0c;会在文章“重难点解答”部分精讲。 题目链接 蓝桥杯2023年第十四届省赛真题-岛屿个数 - C语言网 题目理解 这道题让我们求岛屿个数&#xff0c;那么我们就应该先弄懂&#xff0c;对于一…

Qt5 编译oracle数据库

库文件 1、Qt源码目录&#xff1a;D:\Qt5\5.15.2\Src\qtbase\src\plugins\sqldrivers\oci 2、oracle客户端SDK: https://www.oracle.com/database/technologies/instant-client/winx64-64-downloads.html 下载各版本中的如下压缩包&#xff0c;一定要版本相同的 将两个压缩包…

【简单讲解如何安装与配置Composer】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Rust语言入门第四篇-变量与可变性以及隐藏(Shadowing)

文章目录 Rust语言入门第四篇-变量与可变性以及隐藏&#xff08;Shadowing&#xff09;概要let 关键字自动判断变量类型隐藏&#xff08;Shadowing&#xff09;let关键字支持的数据类型let 关键字声明的变量类型转换 Rust语言入门第四篇-变量与可变性以及隐藏&#xff08;Shado…

机器学习和深度学习 -- 李宏毅(笔记与个人理解)Day 13

Day13 Error surface is rugged…… Tips for training :Adaptive Learning Rate critical point is not the difficult Root mean Square --used in Adagrad 这里为啥是前面的g的和而不是直接只除以当前呢? 这种方法的目的是防止学习率在训练过程中快速衰减。如果只用当前的…

02_JavaWeb中的Tomcat(详解)

文章目录 Tomcat1, 概述1.1 安装1.2 目录结构1.3 启动/停止 2, 资源部署2.1 直接部署: 主要和重要的方式2.2 虚拟映射: 重要2.2.1 方式一:2.2.1 方式二: 2.3 原理解析 3, Tomcat组件3.1 Connector3.2 Engine3.2.1 Host3.2.1.1 Context 4, 其它: 重要4.1 设置 Tomcat 1, 概述 w…

Android网络抓包--Charles

一、Android抓包方式 对Https降级进行抓包&#xff0c;降级成Http使用抓包工具对Https进行抓包 二、常用的抓包工具 wireshark&#xff1a;侧重于TCP、UDP传输层&#xff0c;HTTP/HTTPS也能抓包&#xff0c;但不能解密HTTPS报文。比较复杂fiddler&#xff1a;支持HTTP/HTTPS…

文献速递:深度学习肝脏肿瘤诊断---基于多相增强 CT 和临床数据的恶性肝肿瘤鉴别诊断深度学习

Title 题目 Deep learning for diferential diagnosisof malignant hepatic tumors based on multi-phase contrast-enhanced CT and clinical data 基于多相增强 CT 和临床数据的恶性肝肿瘤鉴别诊断深度学习 Abstract 摘要 Liver cancer remains the leading cause of can…

云计算:Linux 部署 OVS 集群(控制端)实现OpenFlow

目录 一、实验 1.环境 2.Linux 部署 OVS 集群&#xff08;控制端&#xff09; 3.控制端对接服务端OVS网元 4.服务端OVS添加流表 5.服务端删除OVS 二、问题 1. ODL如何查找已安装插件 2.查看流表显示不全 3.如何删除OVS流表 一、实验 1.环境 (1) 主机 表1 宿主机 主…

什么是NLP?

&#x1f916;NLP是什么&#xff1f;&#x1f916; NLP&#xff08;Natural Language Processing&#xff09;&#xff0c;全称自然语言处理&#xff0c;是人工智能不可或缺的一环&#xff0c;它搭建了人与计算机之间沟通的桥梁&#x1f309;。 &#x1f6e0;️NLP强大功能一…

【自然语言】使用词袋模型,TF-IDF模型和Word2Vec模型进行文本向量化

一、任务目标 python代码写将 HarryPorter 电子书作为语料库&#xff0c;分别使用词袋模型&#xff0c;TF-IDF模型和Word2Vec模型进行文本向量化。 1. 首先将数据预处理&#xff0c;Word2Vec 训练时要求考虑每个单词前后的五个词汇&#xff0c;地址为 作为其上下文 &#xf…

CTFshow电子取证——内存取证1

关于内存与注册表 内存中的注册表项 当Windows操作系统启动时&#xff0c;它会将注册表的部分数据加载到内存中&#xff0c;以便系统和应用程序可以快速地访问这些信息。这些数据在内存中可以更快地被读取和修改&#xff0c;以便系统能够动态地调整其行为和配置。 系统性能和…

Ubuntu (Linux系统) 下载安装 Qt 环境

在官网http://download.qt.io/archive/qt/ 下载安装包&#xff0c;默认linux平台下提供的安装包以run后缀结尾 也可以选择其它地址下载 Qt官网下载地址&#xff1a;https://download.qt.io&#xff1b; 国内镜像下载地址&#xff1a;https://mirrors.cloud.tencent.com/qt/ 。建…

稀碎从零算法笔记Day47-LeetCode:找到冠军 I

或许是昨天的每日一题太难了&#xff0c;今天的简单 题型&#xff1a;数组、矩阵 链接&#xff1a;2923. 找到冠军 I - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 一场比赛中共有 n 支队伍&#xff0c;按从 0 到 n - 1 编号。 给你一个下…

在vue3中实现pptx、word、excel预览

插件推荐 PPTXjs vue-office 代码 <script setup lang"ts" name"home"> import { computed, nextTick, ref, onMounted } from vue; //引入VueOfficeDocx组件 import VueOfficeDocx from vue-office/docx; //引入VueOfficeExcel组件 import VueOf…

对LSTM的通俗易懂理解--可变权重

RNN的问题&#xff1a;长期依赖&#xff0c;即对短期的数据敏感&#xff0c;对比较远的长期数据不敏感&#xff0c;这是因为RNN隐藏状态权重在不同时刻是共享相同的&#xff0c;随着时间步的增加&#xff0c;梯度会指数级地衰减或者增长&#xff0c;导致梯度消失或者爆炸&#…

高质量ChatGPT Prompts 精选

通用超级 Prompt GPT4实用。通用超级 prompt &#xff0c;根据你想要的输出和你的反馈&#xff0c;自动使用相应的专家角色帮你解决问题。如果需要升级ChatGPT Plus&#xff0c;可以参考教程 升级 GPT4.0 保姆教程 您是一位具有多领域专长的专家级ChatGPT提示工程师。在我们…