Linux系统驱动(十一)GPIO子系统

news2024/9/24 19:13:07

文章目录

  • 一、GPIO子系统
    • (一)框架结构
    • (二)GPIO子系统的API
    • (三)gpio子系统控制LED灯的设备树
      • 1. 画出硬件连接图
      • 2. 找出控制器的设备树
      • 3. 参考内核帮助文档
  • 二、使用GPIO子系统实现流水灯
      • 1. 设备树文件:
      • 2. 驱动文件

一、GPIO子系统

(一)框架结构

在这里插入图片描述

(二)GPIO子系统的API

#include <linux/of_gpio.h>
int of_get_named_gpio(struct device_node *np,const char *propname, int index)
功能:
	获取gpio号
参数:
	 @np:节点的指针
	 @propname:键
	 @index:下标 (键值的第几个数)
返回值:
	成功返回gpio号,失败返回错误码
 
int gpio_request(unsigned gpio, const char *label)
功能:
	申请要使用的GPIO
参数:
    @gpio:gpio号(设备树中获取)
 	@label:名字,也可以写NULL
返回值:
	成功返回0,失败返回错误码

int gpio_direction_input(unsigned gpio)
功能:将gpio的方向设置为输入
参数:
 @gpio:gpio号
返回值:成功返回0,失败返回错误码
        
int gpio_direction_output(unsigned gpio, int value)
功能:将gpio的方向设置为输出
参数:
 @gpio:gpio号
 @value:默认输出电平状态  1高电平  0低电平
返回值:成功返回0,失败返回错误码

int gpio_get_value(unsigned gpio)
功能:获取管脚电平
参数:
   @gpio:gpio号
返回值:返回1高电平 返回0低电平

void gpio_set_value(unsigned int gpio, int value)
功能:设置管脚电平的状态
参数:
 @gpio:gpio号
 @value:输出电平状态  1高电平  0低电平
返回值:无

void gpio_free(unsigned gpio)
功能:释放gpio
参数:
 @gpio:gpio号
返回值:无    

(三)gpio子系统控制LED灯的设备树

1. 画出硬件连接图

在这里插入图片描述

2. 找出控制器的设备树

目录:
linux-5.10.61/arch/arm/boot/dts/stm32mp151.dtsi
在这里插入图片描述

//stm32mp151.dtsi
gpioe: gpio@50006000 {
    gpio-controller; //空属性,标识这个节点是gpio控制器的设备树节点
    #gpio-cells = <2>;       //2.对子节点成员个数修饰
    reg = <0x50006000 0x400>;//控制器的地址,长度
    clocks = <&rcc GPIOE>;   //时钟
    st,bank-name = "GPIOE";  //gpioe
    status = "disabled";     //1.控制器的状态,disabled没有使能,okay使能
};   

3. 参考内核帮助文档

帮助文档路径:
linux-5.10.61/Documentation/devicetree/bindings/gpio
在这里插入图片描述
在gpio目录下对应这不同厂商的帮助文档。
有厂商的帮助文档看厂商的帮助文档,没有就看通用的文档
在这里插入图片描述

myleds{
    led1 = <&gpioe 10 0>; //10gpioe的第10个管脚,0默认状态
    led2 = <&gpiof 10 0>; //10gpiof的第10个管脚,0默认状态
    led3 = <&gpioe 8 0>; //8gpioe的第8个管脚,0默认状态
};

二、使用GPIO子系统实现流水灯

扩展版三个LED:

PE10	---		LED1
PF10	---	 	LED2
PE8		---	 	LED3

主控板三个LED:
在这里插入图片描述

1. 设备树文件:

stm32mp157a-fsmp1a.dts

/{
//在根节点中添加以下节点
myleds{
	core_leds{
		led1 = <&gpioz 5 0>;
		led2 = <&gpioz 6 0>;
		led3 = <&gpioz 7 0>;
	};
	expend_leds{
		led1 = <&gpioe 10 0>;
		led2 = <&gpiof 10 0>;
		led3 = <&gpioe 8 0>;
	};
};

2. 驱动文件

mynode.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h> //设备树文件相关头文件
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include "mynode.h"

const char *led[3]={"led1","led2","led3"};
int core_gpiono[3];
int expend_gpiono[3];
struct cdev *led_cdev;
struct class *led_class;
struct device *led_device;

int major = 0; //主设备号
int minor = 0;
dev_t led_dev_num;

int my_led_open(struct inode *inode, struct file *file){
    struct device_node *core_node,*expend_node;
    int i,ret;
    //1. 获取节点
    //core节点
    core_node = of_find_node_by_path("/myleds/core_leds");
    if(NULL == core_node){
        pr_err("of_find_node_by_path error");
        return -EINVAL;
    }
    
    //expend节点
    expend_node = of_find_node_by_path("/myleds/expend_leds");
    if(NULL == expend_node){
        pr_err("of_find_node_by_path error");
        return -EINVAL;
    }

    //2.获取gpio号
    for(i=0;i<3;i++){
        //core
        core_gpiono[i] = of_get_named_gpio(core_node,led[i],0);
        if(core_gpiono[i] < 0){
            pr_err("of_get_named_gpio error");
            return core_gpiono[i];
        }
        //expend
        expend_gpiono[i] = of_get_named_gpio(expend_node,led[i],0);
        if(expend_gpiono[i] < 0){
            pr_err("of_get_named_gpio error");
            return expend_gpiono[i];
        }
    }

    //3. 申请gpio
    for(i=0;i<3;i++){
        ret=gpio_request(core_gpiono[i],NULL);
        if(ret){
            pr_err("gpio_request error");
            for(i--;i>0;i--){
                gpio_free(core_gpiono[i]);
            }
            return ret;
        }
    }
    for(i=0;i<3;i++){
        ret=gpio_request(expend_gpiono[i],NULL);
        if(ret){
            pr_err("gpio_request error");
            for(i--;i>0;i--){
                gpio_free(expend_gpiono[i]);
            }
            for(i=0;i<3;i++){
                gpio_free(core_gpiono[i]);
            }
            return ret;
        }
    }
    //4.设置方向为输出
    for(i=0;i<3;i++){
        ret = gpio_direction_output(core_gpiono[i], 0);
        if (ret) {
            pr_err("gpio_direction_output error\n");
            goto err;
        }
        ret = gpio_direction_output(expend_gpiono[i], 0);
        if (ret) {
            pr_err("gpio_direction_output error\n");
            goto err;
        }
    }
    return 0;
err:
    for(i=0;i<3;i++){
        gpio_free(core_gpiono[i]);
        gpio_free(expend_gpiono[i]);
    }
    return ret;

}
int my_led_close(struct inode *inode, struct file *file){
    return 0;
}
long myled_ioctl(struct file *file, unsigned int cmd, unsigned long arg){
    switch(cmd){
        case LED1_ON:
            gpio_set_value(core_gpiono[0],1);
            break;
        case LED1_OFF:
            gpio_set_value(core_gpiono[0],0);
            break;
        case LED2_ON:
            gpio_set_value(core_gpiono[1],1);
            break;
        case LED2_OFF:
            gpio_set_value(core_gpiono[1],0);
            break;
        case LED3_ON:
            gpio_set_value(core_gpiono[2],1);
            break;
        case LED3_OFF:
            gpio_set_value(core_gpiono[2],0);
            break;
        case LED4_ON:
            gpio_set_value(expend_gpiono[0],1);
            break;
        case LED4_OFF:
            gpio_set_value(expend_gpiono[0],0);
            break;
        case LED5_ON:
            gpio_set_value(expend_gpiono[1],1);
            break;
        case LED5_OFF:
            gpio_set_value(expend_gpiono[1],0);
            break;
        case LED6_ON:
            gpio_set_value(expend_gpiono[2],1);
            break;
        case LED6_OFF:
            gpio_set_value(expend_gpiono[2],0);
            break;
    }
    return 0;
}

const struct file_operations ledfops={
    .open=my_led_open,
    .release=my_led_close,
    .unlocked_ioctl=myled_ioctl,
};

static int __init mynode_init(void){
    //分配对象
    led_cdev = cdev_alloc();
    if(NULL == led_cdev){ //成功返回结构体指针,失败返回NULL
        pr_err("cdv_err error");
        return -ENOMEM;
    }
    //初始化对象:部分成员初始化
    cdev_init(led_cdev,&ledfops);
    //申请设备号:如果major为0,则动态申请,否则就静态指定
    if(major > 0){
        register_chrdev_region(MKDEV(major,minor),1,"mynode");
    }else if(major == 0){
        alloc_chrdev_region(&led_dev_num,0,1,"mynode"); 
        major=MAJOR(led_dev_num);
        minor=MINOR(led_dev_num);
    }
    //注册
    cdev_add(led_cdev,MKDEV(major,minor),1); 
    //自动创建设备节点
    led_class=class_create(THIS_MODULE,"mynode");
    led_device = device_create(led_class,NULL,MKDEV(major,minor),NULL,"mynode");
    
    return 0;
}
static void __exit mynode_exit(void){
    int i;
    for(i=0;i<3;i++){
        gpio_free(core_gpiono[i]);
        gpio_free(expend_gpiono[i]);
    }
    device_destroy(led_class, MKDEV(major, minor));
    class_destroy(led_class);
    cdev_del(led_cdev);
    unregister_chrdev_region(MKDEV(major, minor), 1);
    kfree(led_cdev);
}

module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");

mynode.h

#ifndef __MYNODE_H__
#define __MYNODE_H__

#define LED1_ON _IOW('L',000,int)
#define LED1_OFF _IOW('L',001,int)
#define LED2_ON _IOW('L',010,int)
#define LED2_OFF _IOW('L',011,int)
#define LED3_ON _IOW('L',020,int)
#define LED3_OFF _IOW('L',021,int)
#define LED4_ON _IOW('L',100,int)
#define LED4_OFF _IOW('L',101,int)
#define LED5_ON _IOW('L',110,int)
#define LED5_OFF _IOW('L',111,int)
#define LED6_ON _IOW('L',120,int)
#define LED6_OFF _IOW('L',121,int)

#endif

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

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

相关文章

Win11解压文件Cpu占用率过高?解决方法在此!

在Win11电脑操作中&#xff0c;用户遇到解压文件时CPU占有率过高的问题&#xff0c;不知道要如何操作才能解决该问题&#xff1f;接下来系统之家小编给大家分享几种不同的解决方法&#xff0c;帮助大家轻松解决问题&#xff0c;降低Win11电脑CPU占有率&#xff0c;提升Win11电脑…

记一次框架升级

背景 随着公司业务的不断扩展&#xff0c;新技术的更新换代&#xff0c;企业内部免不了会对软硬件进行升级&#xff0c;淘汰老旧的组件和实现方案&#xff0c;更新一波技术栈。这不&#xff0c;最近我们公司就面临这么一个难题&#xff1a;旧版本的组件上发现漏洞&#xff0c;为…

Fiddler代理后浏览器无法上网啥情况

当使用Fiddler作为代理服务器后&#xff0c;浏览器无法上网的情况通常是由以下几个原因造成的&#xff1a; 代理服务器配置不正确&#xff1a; 确保在浏览器或其他客户端中正确配置了Fiddler作为代理服务器。代理服务器地址应为运行Fiddler的计算机的局域网IP地址&#xff0c;端…

【Canvas与艺术】黄色立体感放射光芒五角星

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>黄色立体感放射光芒五角星</title><style type"text/c…

黄金走势分析及经济前景展望

黄金市场动态 近期&#xff0c;全球经济不确定性加剧&#xff0c;使得黄金市场备受关注。美国国债收益率的上涨进一步支撑了美元&#xff0c;推动黄金价格进入高位震荡阶段。尽管黄金在短期内受到波动的影响&#xff0c;但长期避险资产的吸引力仍不容忽视。 经济数据与黄金走势…

Spring---AOP(面向切面编程)

AOP(Aspect-Oriented Programming: 面向切面编程)&#xff1a;将那些与业务无关&#xff0c;却为业务模块所共调用的逻辑&#xff08;例如事务处理、日志管理、权限控制等&#xff09;封装抽取成一个可重用的模块&#xff0c;这个模块被命名为“切面”&#xff08;Aspect&#…

Promethues Metrics

Metrics Metrics可分为三部分&#xff1a; HELP 描述metric作用TYPE metric类别 TYEP Counter 某个事件发生的次数数字只能增长 Total reuqests Total ExceptionsGauge 描述当前值可以上升或下降 CurrentCPU Utilization Available System Memory Number of concurren…

萌新的Java入门日记19

Vue真恶心&#xff01;&#xff01;&#xff01;呜呜呜 5.配置代理 为了避免因后端服务器迁移造成的麻烦&#xff0c;在 vite.config.js 文件中配置如下代码&#xff1a; export default defineConfig({plugins: [vue()],server:{// 配置vite冷启动项目自动使用浏览器访问首页…

【中项】系统集成项目管理工程师-第10章 项目整合管理-10.6实施整体变更控制

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

4个免费好用的免扣素材神器!png素材根本用不完!

你是否曾为找不到合适的PPT素材而头疼&#xff1f;模糊的图片、带水印的模板&#xff0c;还有那些让人抓狂的素材搜索难题。别急&#xff0c;今天就来给大家安利四款我私藏的PPT素材神器&#xff0c;让你的PPT设计从此变得简单又高效&#xff01; 一、千鹿设计助手 — AI免抠图…

算法力扣刷题记录 七十【70. 爬楼梯及算法性能分析:时间复杂度和空间复杂度】

前言 动态规划章节第二篇。记录 七十【70. 爬楼梯】 一、题目阅读 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xf…

SQL注入sqli-labs-master关卡三

第三关如下&#xff1a; 查看该关卡的代码发现其与关卡一和关卡二的不同之处在于id($id)这里。 那么我们输入?id1或?id2)--都能用来判断是字符型还是数字型注入。 接着输入?id1) order by 3--检查它的列数。检查到4报错&#xff0c;说明只有三列。 输入?id-1) union select…

02_快速启动 Demo 创建 Electron 项目、electron-forge 搭建一个 electron 项目、手动创建electron项目

快速启动 Demo 创建 Electron 项目 一、克隆一个仓库、快速启动一个项目二、electron-forge 搭建一个 electron 项目三、手动搭建一个 electron 项目四、开发工具中配置 Eslint 一、克隆一个仓库、快速启动一个项目 要使用 git 的话首先电脑上面需要安装 git //克隆示例项目的…

Cpp中的this指针--复习记录

1.什么是this指针? 每个类都有一个this指针&#xff0c;我们的非静态成员函数可以通过这个this指针来操作对象的成员属性。this指针存储的就是类的实例的地址&#xff0c;this指针时时刻刻指向的都是这个实例对象本身。 由下图可知: 我在主函数中栈上创建了一个类的实例(由操…

数据规模介绍

batch_size 2 1829*2 3658张图片 FSC147数据集介绍 train 3659 val 1286 test 1190

xxl-job 源码梳理(2)-服务端

目录 1. 控制面的接口2.手动触发任务2. 定时任务的实现 1. 控制面的接口 服务端包含xxl-job的管理端&#xff0c;页面上的接口后端一系列的controller接口 appName是一个核心概念&#xff0c;它是指执行器应用的名称&#xff0c;appName是执行器的唯一标识 页面上的接口&#…

出行365:依托分布式数据库,让出行无忧 | OceanBase案例

*本文首发自“新华社环球”杂志&#xff0c;作者张海鑫 每年的暑期旅游旺季&#xff0c;都会触发一轮轮的文旅消费的热潮&#xff0c;对于互联网出行服务行业而言&#xff0c;这既是一场盛大的狂欢&#xff0c;也是对其综合实力的严峻考验。 然而&#xff0c;自去年暑假起&…

Email发送接口安全性保障策略?如何优化?

Email发送接口的高级功能&#xff1f;怎么有效利用邮件API接口&#xff1f; Email发送接口的安全性对于防止数据泄露、滥发垃圾邮件和恶意攻击至关重要。AokSend将探讨Email发送接口的安全性保障策略&#xff0c;帮助开发者和企业确保其电子邮件通信的安全性和可靠性。 Email…

智能猫砂盆买错有什么危害?深度解析三款热门爆款产品!

作为一名家里还有小猫在等待的上班族&#xff0c;我们经常因为需要加班或频繁出差而忙碌得不可开交&#xff0c;导致我们很容易忽略猫咪的厕所环境和健康安全&#xff0c;每次急匆匆地出门&#xff0c;都发现自己似乎忘了给猫咪及时铲屎。但是大家要知道&#xff0c;不及时清理…

为人处世,“会说话”是一生的修行

职场上&#xff0c;常常存在这样一种现象&#xff1a;“会干活的&#xff0c;不如会说的。” 学会“好好说话”、“说正确的话”“说让人舒服的话”成为一生必须要面对的修行。 01 丰厚的学养&#xff0c;是“会说话”的根基。 同一句话&#xff0c;“会说话”的人&#xf…