当前位置: 首页 > news >正文

GPIO子系统

GPIO(通用输入输出,General Purpose Input/Output)子系统

是Linux内核中用于控制和使用GPIO引脚的一组功能。

GPIO引脚是微控制器和计算机系统中用于控制硬件组件的简单接口。

GPIO引脚可以被配置为输入或输出,可以被用来连接按钮、灯、传感器等各种设备。

GPIO子系统的主要功能

输入/输出配置:GPIO引脚可以配置为输入模式(用于读取传感器的状态)或输出模式(用于控制LED、继电器等)。

电平读取和设置:GPIO系统允许驱动程序读取引脚的电平状态(高或低)以及设置引脚的电平。

中断处理:GPIO子系统支持通过中断方式响应引脚状态的变化(如按钮按下),使得系统能及时做出反应。

设备树支持:在多数系统中,GPIO引脚的配置可以通过设备树来描述,便于对硬件的抽象和兼容支持。

1. GPIO引脚请求与释放

int of_get_named_gpio(struct device_node *np, const char *propname, int index);功能:从设备树节点中获取指定索引的GPIO。
参数:
np:设备树节点。
propname:GPIO属性名称。
index:GPIO索引。
返回值:成功返回GPIO号码,失败时返回负的错误码。gpio_request
int gpio_request(unsigned int gpio, const char *label);功能:请求使用一个特定的GPIO引脚。
参数:
gpio:要请求的GPIO引脚号码。
label:用于描述请求使用的GPIO的标签字符串(用于调试和日志记录)。
返回值:成功返回0,失败时返回负的错误码。
gpio_free
void gpio_free(unsigned int gpio);功能:释放先前请求的GPIO引脚,使其可供其他模块使用。
参数:
gpio:要释放的GPIO引脚号码。

2. GPIO引脚设置与读取

gpio_direction_inputint gpio_direction_input(unsigned int gpio);功能:将GPIO引脚配置为输入模式。参数:gpio:要配置的GPIO引脚号码。返回值:成功返回0,失败时返回负的错误码。gpio_direction_outputint gpio_direction_output(unsigned int gpio, int value);功能:将GPIO引脚配置为输出模式,并设置初始电平。参数:gpio:要配置的GPIO引脚号码。value:输出的初始电平(01)。返回值:成功返回0,失败时返回负的错误码。gpio_get_valueint gpio_get_value(unsigned int gpio);功能:读取GPIO引脚的当前电平。参数:gpio:要读取的GPIO引脚号码。返回值:返回引脚的电平状态(01)。gpio_set_valuevoid gpio_set_value(unsigned int gpio, int value);功能:设置GPIO引脚的电平状态。参数:gpio:要设置的GPIO引脚号码。value:要设置的电平状态(01)。
  1. GPIO中断处理
gpio_to_irqint gpio_to_irq(unsigned int gpio);功能:将GPIO引脚转换为IRQ编号,以便为该引脚设置中断。参数:gpio:目标GPIO引脚的号码。返回值:返回对应的IRQ编号,失败时返回负的错误码。request_irqint request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *devname, void *dev_id);功能:请求特定的IRQ,并注册处理程序。参数:irq:IRQ编号。handler:中断处理函数。flags:用于中断处理的标志。devname:与设备相关的名称(用于调试)。dev_id:用于指定设备的ID,回调时将其传入。返回值:成功返回0,失败时返回负的错误码。free_irqvoid free_irq(unsigned int irq, void *dev_id);功能:释放先前请求的IRQ。参数:irq:要释放的IRQ编号。dev_id:与设备相关的ID。
  1. GPIO属性与管理
   of_gpio_getint of_gpio_get(const struct device_node *np, int index);功能:从设备树节点中获取指定索引的GPIO。参数:np:设备树节点。index:GPIO索引。返回值:成功返回GPIO号码,失败时返回负的错误码。gpiochip_addint gpiochip_add(struct gpio_chip *chip);功能:注册一个GPIO控制器。参数:chip:指向GPIO控制器的结构体。返回值:成功返回0,失败时返回负的错误码。

5. 示例代码

myleds{core_leds{led1 = <&gpioz 5 0>;led2 = <&gpioz 6 0>;led3 = <&gpioz 7 0>;};extend_leds{led1 = <&gpioe 10 0>;led2 = <&gpiof 10 0>;led3 = <&gpioe 8 0>;};
};详细解释
myleds:这是设备树中的一个节点,代表一个名为 myleds 的设备或模块。
core_leds 和 extend_leds:这是 myleds 节点的两个子节点,分别描述了核心LED和扩展LED的配置。
led1, led2, led3:这些是子节点中的属性,描述了每个LED对应的GPIO引脚。
&gpioz 5 0&gpioz 是一个引用,指向设备树中定义的 gpioz 节点。5 是GPIO引脚的编号,0 是默认的GPIO配置(通常表示默认配置)。
&gpioe 10 0:类似地,&gpioe 指向 gpioe 节点,10 是GPIO引脚的编号。led1 = <&gpioz 5 0>;这里的 0 是第三个参数,通常用于指示与该GPIO引脚相关的特定配置或属性。虽然具体含义在不同平台和驱动中可能有所不同,但通常来说,第三个参数可以表示以下几种情况之一:1. GPIO配置
在一些架构中,0 可能代表GPIO引脚的特定配置选项。例如:输出默认值:在某些情况下,第三个参数可能表示GPIO引脚的初始电平状态(如0表示低电平,1表示高电平)。
其他配置选项:一些GPIO控制器可能会使用这个参数来表示上拉/下拉配置或其它特定设置。
2. 无特定配置
在某些情况下,0 可能只是为了填充占位符,表示没有特定的配置需求。驱动程序在解析引脚时会忽略这个参数,只关注前面的两个参数。3. 特定于平台
不同的硬件平台和驱动程序可能会对这个参数有不同的解释。为了准确理解该参数的含义,你需要查阅具体硬件平台的数据手册或设备树文档,特别是与GPIO控制相关的部分。

myleds.h

#ifndef __MYLEDS_H__
#define __MYLEDS_H__// 定义ioctl命令,用于控制LED开/关
#define LED_ON _IOW('K',0,int)   // LED打开命令
#define LED_OFF _IOW('K',1,int)  // LED关闭命令// LED状态枚举定义
enum leds_status{OFF, // 关闭状态ON   // 开启状态
};// LED编号枚举定义
enum leds_no{LED1, // 核心LED1LED2, // 核心LED2LED3, // 核心LED3LED4, // 扩展LED4LED5, // 扩展LED5LED6, // 扩展LED6
};#endif

myleds.c

#include "myleds.h"
#include <head.h>
#include <sys/ioctl.h>// LED闪烁函数
int led_set_blink(int fd, int which)
{if (ioctl(fd, LED_ON, &which)) // 发送打开LED的ioctl命令PRINT_ERR("ioctl error"); // 输出错误信息sleep(1); // 延时1秒if (ioctl(fd, LED_OFF, &which)) // 发送关闭LED的ioctl命令PRINT_ERR("ioctl error"); // 输出错误信息sleep(1); // 延时1秒return 0; // 成功
}// 主函数
int main(int argc, const char* argv[])
{int fd;// 打开设备if ((fd = open("/dev/myleds", O_RDWR)) == -1)PRINT_ERR("open error"); // 打开失败,输出错误信息while (1) {led_set_blink(fd, LED5); // 持续闪烁LED5}close(fd); // 关闭设备return 0; // 结束程序
}
#include "myleds.h"
#include <head.h>
#include <sys/ioctl.h>// LED闪烁函数
int led_set_blink(int fd, int which)
{if (ioctl(fd, LED_ON, &which)) // 发送打开LED的ioctl命令PRINT_ERR("ioctl error"); // 输出错误信息sleep(1); // 延时1秒if (ioctl(fd, LED_OFF, &which)) // 发送关闭LED的ioctl命令PRINT_ERR("ioctl error"); // 输出错误信息sleep(1); // 延时1秒return 0; // 成功
}// 主函数
int main(int argc, const char* argv[])
{int fd;// 打开设备if ((fd = open("/dev/myleds", O_RDWR)) == -1)PRINT_ERR("open error"); // 打开失败,输出错误信息while (1) {led_set_blink(fd, LED5); // 持续闪烁LED5}close(fd); // 关闭设备return 0; // 结束程序
}

GPIO子系统是怎么控制硬件的

在Linux设备模型中,每个GPIO引脚被抽象为一个设备。

这些设备通过设备树(Device Tree)进行描述,使得系统能够在引导时识别和配置这些引脚。

设备树包含了引脚的信息,包括引脚的编号、功能、连接的设备等。

  1. GPIO引脚的初始化

    当驱动程序加载时,GPIO子系统会依据设备树的信息进行初始化。引脚的初始化通常包括以下步骤:

    查找设备节点:通过设备树API(如 of_find_node_by_path)查找特定的GPIO设备节点。
    获取GPIO编号:使用API(如 of_get_named_gpio)从设备节点中获取特定引脚的GPIO编号。
    请求GPIO:调用 gpio_request 函数请求使用该GPIO引脚,这样其他驱动就无法使用它。

  2. 配置GPIO方向

    每个GPIO引脚可以配置为输入或输出:

输入模式:使用 gpio_direction_input 设置引脚为输入模式,驱动程序可以读取其电平状态(高或低)。
输出模式:使用 gpio_direction_output 设置引脚为输出模式,驱动程序可以控制引脚的电平输出(高或低)。

  1. 控制GPIO引脚的电平

    设置输出电平:使用 gpio_set_value 函数来设置GPIO引脚的高(1)或低(0)电平。
    读取输入电平:使用 gpio_get_value 函数来读取GPIO引脚的当前电平状态。

  2. 释放GPIO资源
    当驱动程序不再需要使用GPIO引脚时,需要调用 gpio_free 函数来释放该引脚,以便其他驱动可以使用。

  3. 事件驱动
    对于输入模式,GPIO引脚也可以配置为触发中断,当引脚状态发生变化时(例如按钮被按下),系统可以生成一个中断信号,通知相关的驱动程序进行处理。

例如,在一个LED驱动程序中,可能会执行以下操作:使用设备树查找与LED相关的GPIO引脚。
请求该GPIO引脚。
设置引脚为输出模式。
在需要时调用 gpio_set_value 控制LED的开启或关闭。
在模块卸载时释放GPIO引脚。

步骤


1. 定义设备树结构:首先,在设备树文件中定义LED的相关信息,包括GPIO编号。比如,你可能会在设备树的某个节点下定义LED的信息,如下例:myleds {core_leds {led1 = <&gpioz 5 0>;led2 = <&gpioz 6 0>;};extend_leds {led1 = <&gpioe 10 0>;led2 = <&gpiof 10 0>;};
};2. 在驱动程序中包含所需的头文件:确保包含必要的头文件来使用设备树相关的API。#include <linux/of.h>
#include <linux/of_gpio.h>3. 查找设备树节点:使用 of_find_node_by_path 或 of_find_node_by_name 函数来查找设备树中定义的LED节点。4. 获取GPIO编号:使用 of_get_named_gpio 函数从找到的节点中获取与LED相关的GPIO引脚编号。5. 请求GPIO引脚:使用 gpio_request 请求获得的GPIO引脚。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • leetcode49字母异位词分组
  • 一.Oracle每日运维操作
  • 清理C盘缓存,电脑缓存清理怎么一键删除,操作简单的教程
  • Html在线编辑器
  • Markdown formula 公式
  • 【C#生态园】完整解读C#音频处理库:功能、安装配置和使用场景一网打尽
  • 2024短剧系统开发,付费短剧小程序app源码教程,分销功能讲解搭建上线
  • Java项目实战II基于Java+Spring Boot+MySQL的作业管理系统设计与实现(源码+数据库+文档)
  • 配电房监控 配电柜监测系统方案简介@卓振思众
  • unity的学习
  • MyBatis 如何将 Mapper 接口与其 XML 映射文件关联:深入原理与实现
  • 电脑浏览器访问华为路由器报错,无法访问路由器web界面:ERR_SSL_VERSION_OR_CIPHER_MISMATCH 最简单的解决办法!
  • AJAX(一)HTTP协议(请求响应报文),AJAX发送请求,请求问题处理
  • LabVIEW提高开发效率技巧----VI服务器和动态调用
  • 怎么检查cuda是否安装成功(以及查看cuda的安装位置)
  • [译]如何构建服务器端web组件,为何要构建?
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • C++11: atomic 头文件
  • HashMap剖析之内部结构
  • iOS 系统授权开发
  • Java IO学习笔记一
  • Java编程基础24——递归练习
  • Ruby 2.x 源代码分析:扩展 概述
  • spring + angular 实现导出excel
  • Transformer-XL: Unleashing the Potential of Attention Models
  • 大数据与云计算学习:数据分析(二)
  • - 概述 - 《设计模式(极简c++版)》
  • 如何设计一个微型分布式架构?
  • 通过npm或yarn自动生成vue组件
  • 一个完整Java Web项目背后的密码
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • #HarmonyOS:Web组件的使用
  • #php的pecl工具#
  • (4)logging(日志模块)
  • (js)循环条件满足时终止循环
  • (二)延时任务篇——通过redis的key监听,实现延迟任务实战
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (附源码)计算机毕业设计ssm高校《大学语文》课程作业在线管理系统
  • (六)DockerCompose安装与配置
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (原創) 未来三学期想要修的课 (日記)
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net 获取url的方法
  • .NET 快速重构概要1
  • .NET+WPF 桌面快速启动工具 GeekDesk
  • .net6 core Worker Service项目,使用Exchange Web Services (EWS) 分页获取电子邮件收件箱列表,邮件信息字段
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .net连接MySQL的方法
  • .NET委托:一个关于C#的睡前故事
  • .NET中的Event与Delegates,从Publisher到Subscriber的衔接!
  • /*在DataTable中更新、删除数据*/