【驱动篇】龙芯LS2K0300之按键驱动

实验过程

实验目的: 在龙芯开发板上面验证GPIO按键的输入过程

① 根据原理图连接按键板

② 将4个i2c引脚的功能复用为GPIO

③ 注册input设备驱动,绑定中断处理函数,使用定时器消抖

原理图

4个按键引脚:CPU_I2C0_SCL -> GPIO48, CPU_I2C0_SDA -> GPIO49, CPU_I2C1_SCL -> GPIO50, CPU_I2C1_SDA -> GPIO51

在这里插入图片描述

实物连接图:按顺序连接好按键板上面的K1、K2、K3、K4、GND

在这里插入图片描述

设备树

还是把i2c1和i2c2部分代码注释掉,需要把它们当作4个GPIO来使用

在这里插入图片描述

驱动程序

GPIO、中断和KEY的对应关系表

GPIO中断KEY引脚
482616
492718
502815
512917

定义相关按键设备结构体

#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/input.h>#define KEY_INPUT	"key_input"
#define KEY_NUM	4struct my_key_dev{struct input_dev *idev;struct timer_list timer;int key[KEY_NUM];int irq[KEY_NUM];	int index;	
};struct my_key_dev key_dev;	

GPIO按键初始化

static int __init gpio_key_init(void)
{int ret = 0;int i = 0;// timertimer_setup(&key_dev.timer, key_timer_function, 0);for(i = 0; i < KEY_NUM; i++) {// gpio 48 49 50 51key_dev.key[i] = 48 + i;// requestret = gpio_request(key_dev.key[i], "LED-GPIO");if (ret) {printk(KERN_ERR "key_dev: Failed to request led-gpio\n");return ret;}// inputret = gpio_direction_input(key_dev.key[i]);if(ret < 0) {printk("can't set gpio!\r\n");}// irqkey_dev.irq[i] = gpio_to_irq(key_dev.key[i]); printk("key%d -> irq : %d\n", key_dev.key[i], key_dev.irq[i]);if(i == 0) {ret = request_irq(key_dev.irq[i], key_interrupt0, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key0_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}else if(i == 1) {ret = request_irq(key_dev.irq[i], key_interrupt1, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key1_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}else if(i == 2) {ret = request_irq(key_dev.irq[i], key_interrupt2, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key2_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}else if(i == 3) {ret = request_irq(key_dev.irq[i], key_interrupt3, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key3_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}}// input devkey_dev.idev = input_allocate_device();key_dev.idev->name = KEY_INPUT;key_dev.idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);input_set_capability(key_dev.idev, EV_KEY, KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN);ret = input_register_device(key_dev.idev);if (ret) {printk("register input device failed!\r\n");goto free_gpio;}return ret;free_gpio:for(i = 0; i < KEY_NUM; i++) {free_irq(key_dev.irq[i],NULL);gpio_free(key_dev.key[i]);}del_timer_sync(&key_dev.timer);return -EIO;
}

中断处理

static irqreturn_t key_interrupt0(int irq, void *dev_id)
{// printk("key_interrupt0 irq %d \n", irq);if(irq == key_dev.irq[0]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 0;}return IRQ_HANDLED;
}static irqreturn_t key_interrupt1(int irq, void *dev_id)
{// printk("key_interrupt1 irq %d \n", irq);if(irq == key_dev.irq[1]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 1;}return IRQ_HANDLED;
}static irqreturn_t key_interrupt2(int irq, void *dev_id)
{// printk("key_interrupt2 irq %d \n", irq);if(irq == key_dev.irq[2]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 2;}return IRQ_HANDLED;
}static irqreturn_t key_interrupt3(int irq, void *dev_id)
{// printk("key_interrupt3 irq %d \n", irq);if(irq == key_dev.irq[3]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 3;}return IRQ_HANDLED;
}

定时器消抖

int key_array[] = {KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN};static void key_timer_function(struct timer_list *arg)
{int val = gpio_get_value(key_dev.key[key_dev.index]);printk("key_timer_function %d -> %d\n", key_dev.key[key_dev.index], val);// if(val == 0) {input_report_key(key_dev.idev, key_array[key_dev.index], !val);input_sync(key_dev.idev);// input_report_key(key_dev.idev, key_array[key_dev.index], 0);// input_sync(key_dev.idev);// printk("key %d press %d\n", key_dev.key[key_dev.index], key_array[key_dev.index]);// }
}

驱动模块卸载函数:回收相关的设备资源,如GPIO、中断、定时器等

static void __exit gpio_key_exit(void)
{int i;for(i = 0; i < KEY_NUM; i++) {free_irq(key_dev.irq[i],NULL);gpio_free(key_dev.key[i]);}del_timer_sync(&key_dev.timer);input_unregister_device(key_dev.idev);	
}

整合代码

#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/input.h>#define KEY_INPUT	"key_input"
#define KEY_NUM	4struct my_key_dev{struct input_dev *idev;struct timer_list timer;int key[KEY_NUM];int irq[KEY_NUM];	int index;	
};struct my_key_dev key_dev;	int key_array[] = {KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN};static void key_timer_function(struct timer_list *arg)
{int val = gpio_get_value(key_dev.key[key_dev.index]);printk("key_timer_function %d -> %d\n", key_dev.key[key_dev.index], val);// if(val == 0) {input_report_key(key_dev.idev, key_array[key_dev.index], !val);input_sync(key_dev.idev);// input_report_key(key_dev.idev, key_array[key_dev.index], 0);// input_sync(key_dev.idev);// printk("key %d press %d\n", key_dev.key[key_dev.index], key_array[key_dev.index]);// }
}static irqreturn_t key_interrupt0(int irq, void *dev_id)
{// printk("key_interrupt0 irq %d \n", irq);if(irq == key_dev.irq[0]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 0;}return IRQ_HANDLED;
}static irqreturn_t key_interrupt1(int irq, void *dev_id)
{// printk("key_interrupt1 irq %d \n", irq);if(irq == key_dev.irq[1]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 1;}return IRQ_HANDLED;
}static irqreturn_t key_interrupt2(int irq, void *dev_id)
{// printk("key_interrupt2 irq %d \n", irq);if(irq == key_dev.irq[2]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 2;}return IRQ_HANDLED;
}static irqreturn_t key_interrupt3(int irq, void *dev_id)
{// printk("key_interrupt3 irq %d \n", irq);if(irq == key_dev.irq[3]) {mod_timer(&key_dev.timer, jiffies + msecs_to_jiffies(15));key_dev.index = 3;}return IRQ_HANDLED;
}static int __init gpio_key_init(void)
{int ret = 0;int i = 0;// timertimer_setup(&key_dev.timer, key_timer_function, 0);for(i = 0; i < KEY_NUM; i++) {// gpio 48 49 50 51key_dev.key[i] = 48 + i;// requestret = gpio_request(key_dev.key[i], "LED-GPIO");if (ret) {printk(KERN_ERR "key_dev: Failed to request led-gpio\n");return ret;}// inputret = gpio_direction_input(key_dev.key[i]);if(ret < 0) {printk("can't set gpio!\r\n");}// irqkey_dev.irq[i] = gpio_to_irq(key_dev.key[i]); printk("key%d -> irq : %d\n", key_dev.key[i], key_dev.irq[i]);if(i == 0) {ret = request_irq(key_dev.irq[i], key_interrupt0, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key0_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}else if(i == 1) {ret = request_irq(key_dev.irq[i], key_interrupt1, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key1_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}else if(i == 2) {ret = request_irq(key_dev.irq[i], key_interrupt2, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key2_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}else if(i == 3) {ret = request_irq(key_dev.irq[i], key_interrupt3, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "Key3_IRQ", NULL);if (ret) {gpio_free(key_dev.key[i]);return ret;}}}// input devkey_dev.idev = input_allocate_device();key_dev.idev->name = KEY_INPUT;key_dev.idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);input_set_capability(key_dev.idev, EV_KEY, KEY_LEFT | KEY_RIGHT | KEY_UP | KEY_DOWN);ret = input_register_device(key_dev.idev);if (ret) {printk("register input device failed!\r\n");goto free_gpio;}return ret;free_gpio:for(i = 0; i < KEY_NUM; i++) {free_irq(key_dev.irq[i],NULL);gpio_free(key_dev.key[i]);}del_timer_sync(&key_dev.timer);return -EIO;
}static void __exit gpio_key_exit(void)
{int i;for(i = 0; i < KEY_NUM; i++) {free_irq(key_dev.irq[i],NULL);gpio_free(key_dev.key[i]);}del_timer_sync(&key_dev.timer);input_unregister_device(key_dev.idev);	
}module_init(gpio_key_init);
module_exit(gpio_key_exit);
MODULE_LICENSE("GPL");

Makefile文件

obj-m += key.o 
KDIR:=/home/asensing/loongson/linux-4.19
ARCH=loongarch 
CROSS_COMPILE=loongarch64-linux-gnu-
PWD?=$(shell pwd) 
all:make -C $(KDIR) M=$(PWD) modules 

构建脚本

export PATH=$PATH:/home/asensing/loongson/loongson-gnu-toolchain-8.3-x86_64-loongarch64-linux-gnu-rc1.3-1/bin
make -j8
# loongarch64-linux-gnu-gcc test.c -o test
FILE=$PWD/$(basename $PWD).ko
scp $FILE root@192.168.137.11:/home/root

实验效果

插入驱动后,按下按键立即打印4个按键值

在这里插入图片描述

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

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

相关文章

数据清洗过程

数据清洗是数据预处理的一个重要步骤&#xff0c;它涉及到识别和纠正&#xff08;或删除&#xff09;数据集中的错误、重复、不一致或缺失的信息。 数据清洗方法 根据清洗操作的层次分为基于模式层&#xff08;Schema-Level&#xff09;的方法和基于实例层&#xff08;Instan…

transformer中的build_attention_mask

build_attention_mask 方法的作用是构建一个因果注意力掩码&#xff0c;用于屏蔽 Transformer 模型中的未来位置。 因果注意力掩码的工作原理 因果注意力掩码通过将未来位置的注意力权重设置为负无穷大&#xff0c;从而确保这些位置的注意力得分在 softmax 计算中接近于零。具…

sqlalchemy event监听

在 SQLAlchemy 中&#xff0c;event 系统允许你监听数据库引擎、会话、映射类等对象上的事件&#xff0c;并在这些事件发生时执行自定义的代码。这对于在 SQL 语句执行前后、对象加载、对象刷新等时刻执行特定的逻辑非常有用。 要使用 SQLAlchemy 的 event 系统&#xff0c;你…

爬虫经典案例之爬取豆瓣电影Top250(方法一)

简介&#xff1a;主要使用bs4、request、pandas等模块&#xff0c;实现数据的爬取和存储。 目前存在一点小问题&#xff0c;就是个别电影的导演、演员、上映年份和地区等信息与大部分电影的这些信息的格式有细微差别&#xff0c;导致正则表达式无法正常匹配到个别电影的信息&am…

解析cJSON数组

json串&#xff1a; { "list":[ "hello","world" ] } 代码 &#xff1a; int func(char *sn) { int ret 0; cJSON *root, *list; FILE *fp fopen("a.txt", "r"); if(!fp) { printf("open s…

并发的概念

并发是指在同一时间间隔内同时执行多个任务或处理多个事件的能力或现象。在计算机科学中&#xff0c;特别是在多任务处理系统中&#xff0c;"并发"通常用于描述系统能够在同一时间段内处理多个任务或操作的能力。 并发并不意味着同时执行多个任务&#xff0c;而是通…

艺体培训机构管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;教师管理&#xff0c;学员管理&#xff0c;活动管理&#xff0c;课程管理&#xff0c;选课信息管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;论…

【深度C++】之“类与结构体”

0. 抽象数据类型 类&#xff08;class&#xff09; 和结构体&#xff08;struct&#xff09; 都是C中的自定义数据类型&#xff0c;是使用C实现面向对象编程思想的起点。 类的基本思想是数据抽象&#xff08;data abstraction&#xff09; 和封装&#xff08;encapsulation&a…

【会议征稿,ACM出版】2024年图像处理、智能控制与计算机工程国际学术会议(IPICE 2024,8月9-11)

2024年图像处理、智能控制与计算机工程国际学术会议&#xff08;IPICE 2024&#xff09;将于2024年8月9-11日在中国福州举行。本届会议由阳光学院、福建省空间信息感知与智能处理重点实验室、空间数据挖掘与应用福建省高校工程研究中心联合主办。 会议主要围绕图像处理、智能控…

分布式定时任务系列10:XXL-job源码分析之路由策略

传送门 分布式定时任务系列1&#xff1a;XXL-job安装 分布式定时任务系列2&#xff1a;XXL-job使用 分布式定时任务系列3&#xff1a;任务执行引擎设计 分布式定时任务系列4&#xff1a;任务执行引擎设计续 分布式定时任务系列5&#xff1a;XXL-job中blockingQueue的应用 …

Go语言的诞生背景

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

Linux操作系统处理器调度基本准则和实现

1&#xff0c;基本概念 在多道程序系统中&#xff0c;进程的数量往往多于处理机的个数&#xff0c;进程争用处理机的情况就在所难免。处理机调度是对处理机进行分配&#xff0c;就是从就绪队列中&#xff0c;按照一定的算法&#xff08;公平、低效&#xff09;选择一个进程并将…

mysql学习——SQL中的DDL和DML

SQL中的DDL和DML DDL数据库操作&#xff1a;表操作 DML添加数据修改数据删除数据 学习黑马MySQL课程&#xff0c;记录笔记&#xff0c;用于复习。 DDL DDL&#xff1a;Data Definition Language&#xff0c;数据定义语言&#xff0c;用来定义数据库对象(数据库&#xff0c;表&…

【CSS】简单实用的calc()函数

calc() 是 CSS 中的一个功能&#xff0c;允许你在属性值中进行基础的数学计算。这是非常有用的&#xff0c;特别是当你需要在不同的上下文或视口大小中动态调整尺寸或位置时。 以下是一些 calc() 函数的简单实用示例&#xff1a; 动态宽度&#xff1a; 假设你希望一个元素的…

C语言入门课程学习笔记8:变量的作用域递归函数宏定义交换变量

C语言入门课程学习笔记8 第36课 - 变量的作用域与生命期&#xff08;上&#xff09;第37课 - 变量的作用域与生命期&#xff08;下&#xff09;实验—局部变量的作用域实验-变量的生命期 第38课 - 函数专题练习第39课 - 递归函数简介实验小结 第40课 - C 语言中的宏定义实验小结…

基于Java的学生成绩管理系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Java技术&#xff0c;B/S结构 工具&#xff1a;MyEclipse&#xff0c;MySQL 系统展示 首页 个人中…

基于YOLOv5+pyqt5的跌倒检测系统(含pyqt页面、训练好的模型)

简介 跌倒是老年人和身体不便者常见的意外事故&#xff0c;及时检测和处理跌倒事件对于保障他们的安全至关重要。为了提高对跌倒事件的监控效率&#xff0c;我们开发了一种基于YOLOv5目标检测模型的跌倒检测系统。本报告将详细介绍该系统的实际应用与实现&#xff0c;包括系统…

虚拟机IP地址频繁变化的解决方法

勾八动态分配IP&#xff0c;让我在学习redis集群的时候&#xff0c;配置很多的IP地址&#xff0c;但是由于以下原因导致我IP频繁变动&#xff0c;报错让我烦恼&#xff01;&#xff01;&#xff01;&#xff01; 为什么虚拟机的IP地址会频繁变化&#xff1f; 虚拟机IP地址频繁…

终极解决方案,传统极速方案,下载软件的双雄对决!

在数字资源日益丰富的今天&#xff0c;下载管理器成为了我们日常生活中不可或缺的工具。市场上两款备受欢迎的下载管理软件——Internet Download Manager&#xff08;IDM&#xff09;和迅雷11&#xff0c;它们以各自的特色和优势&#xff0c;满足了不同用户群体的需求。 软件…

Less与Sass的区别

1. 功能和工具&#xff1a; Sass&#xff1a;提供了更多的功能和内置方法&#xff0c;如条件语句、循环、数学函数等。Sass 也支持更复杂的操作和逻辑构建。 Less&#xff1a;功能也很强大&#xff0c;但相比之下&#xff0c;Sass 在功能上更为丰富和成熟。 2、编译环境&…