【驱动篇】龙芯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,一经查实,立即删除!

相关文章

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

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

【会议征稿,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;表&…

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;满足了不同用户群体的需求。 软件…

uniapp使用伪元素实现气泡

uniapp使用伪元素实现气泡 背景实现思路代码实现尾巴 背景 气泡效果在开发中使用是非常常见的&#xff0c;使用场景有提示框&#xff0c;对话框等等&#xff0c;今天我们使用css来实现气泡效果。老规矩&#xff0c;先看下效果图&#xff1a; 实现思路 其实实现这个气泡框的…

自动驾驶规划中使用 OSQP 进行二次规划 代码原理详细解读

目录 1 问题描述 什么是稀疏矩阵 CSC 形式 QP Path Planning 问题 1. Cost function 1.1 The first term: 1.2 The second term: 1.3 The thrid term: 1.4 The forth term: 对 Qx 矩阵公式的验证 整体 Q 矩阵&#xff08;就是 P 矩阵&#xff0c;二次项的权重矩阵&…

java打印菱形和空心菱形

java打印菱形 菱形分上下两个部分。其中上部分同打印金字塔&#xff1b;下部分循环部分i是递减 &#xff08;ps:菱形层数只能为奇数&#xff09; import java.util.Scanner;public class Lingxing{public static void main(String[] args) {Scanner myScanner new Scanner(S…

Android View点击事件分发原理,源码解读

View点击事件分发原理&#xff0c;源码解读 前言1. 原理总结2.1 时序图总结2.2 流程图总结 2. 源码解读2.1 Activity到ViewGroup2.2 ViewGroup事件中断逆序搜索自己处理点击事件ViewGroup总结 2.3 ViewOnTouchListeneronTouchEvent 3. 附录&#xff1a;时序图uml代码 前言 两年…

Nginx Proxy Manager反向代理Jackett

1 说明 最近折腾nas&#xff0c;发现npm反向代理Jackett后出现无法访问的问题&#xff0c;是因为外网访问jackett (例如https://domain.com:7373/jackett/UI/Dashboard)时&#xff0c;url会被重定向到https://domain.com/jackett/UI/Login?ReturnUrl%2Fjackett%2FUI%2FDashbo…

ubuntu链接mysql

C链接mysql 报错 sudo apt-get update sudo apt-get install libmysqlclient-dev 指令编译 g -o mysql_example mysql_example.cpp -I/usr/include/mysql -lmysqlclient g mysql_test.cpp mysql_config --cflags --libs 安装mysql sudo apt updatesudo apt install mysql-…

Java程序之动物声音“模拟器”

题目&#xff1a; 设计一个“动物模拟器”&#xff0c;希望模拟器可以模拟许多动物的叫声和行为&#xff0c;要求如下&#xff1a; 编写接口Animal&#xff0c;该接口有两个抽象方法cry()和getAnimalName()&#xff0c;即要求实现该接口的各种具体的动物类给出自己的叫声和种类…

尹会生:从零开始部署翻译助手【总结】

安装docker安装dify 工具准备 Docker 简介&#xff1a;可以在不同电脑上运行相同的容器&#xff0c;类似于把软件装在便携箱子里&#xff0c;随身携带。 优点&#xff1a;安装Docker可以简化部署过程&#xff0c;避免安装许多依赖性软件。 网址&#xff1a;https://www.docke…

【TOOL】ceres学习笔记(二) —— 自定义函数练习

文章目录 一、曲线方程1. 问题描述2. 实现方案 一、曲线方程 1. 问题描述 现有数学模型为 f ( x ) A e x B s i n ( x ) C x D f(x)Ae^xBsin(x)Cx^D f(x)AexBsin(x)CxD &#xff0c;但不知道 A A A 、 B B B 、 C C C 、 D D D 各参数系数&#xff0c;实验数据中含有噪声…