【genius_platform软件平台开发】第七十讲:linux系统驱动开发之-中断号、中断向量和中断处理函数

本文主要是介绍【genius_platform软件平台开发】第七十讲:linux系统驱动开发之-中断号、中断向量和中断处理函数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

1. 概述

  • 假如存在这样一个需求:应用程序需要监控某个硬件GPIO口的电平状态,当发生变化时,应用程序就做出相应的动作。利用之前已经介绍的知识,是可以完成这个需求的。比如:在驱动程序中不停的读取GPIO口的状态,一旦发生变化,就把新的电平状态通过信号发送到应用层。这样的方式称作:轮询
  • 轮询方式的缺点显而易见:轮询的时间间隔应该是多少毫秒(or 微秒),才比较合适呢?
    轮询太慢:可能会丢失信号;轮询太快:消耗 CPU 资源!
    因此,在实际的产品中,用中断触发的方式才是更切合实际的选择!
    本文所有的描述和测试,都是在 x86 平台上完成的;

2. 中断分类

  • Linux 的版本在持续更新,对中断的处理方式也在不停的发生变化。下面几张图,是以前在学习时画的思维导图。这几张图比较清晰地描述了在Linux操作系统中,关于中断的一些基本概念。
    在这里插入图片描述

  • 这张图的结构还是比较清晰的,基本上概括了Linux系统中的中断分类。
    另外,在很多关于中断的书籍中,大部分都是从基础的 PIC(可编程中断控制器)开始讲解的。

3. 中断号和中断向量

  • 中断号与中断控制器(PIC/APIC)相关
  • 中断向量与CPU相关
    在这里插入图片描述

4. 中断处理

  • 中断服务程序,就是针对每一个中断如何进行处理。如果您了解Linux中断的相关内容,一定会看到这样的描述:中断处理分为上半部分和下半部分。
    在这里插入图片描述

4.1 上半部

  • 上半部分不能消耗太多的时间,主要处理与硬件相关的重要工作`;其他不重要的工作,都放在下半部分去做。

4.2 下半部

  • 下列图示是针对每一种“下半部分”处理机制的一些特点,注意:有些机制在新版本中已经废弃不用了,了解即可

4.2.1 软中断(soft_irq)

在这里插入图片描述

4.2.2 小任务(tasklet)

在这里插入图片描述

4.2.3 工作队列(work_queue)

在这里插入图片描述

  • 用来完成下半部分工作有好几种机制可以选择,每一种方式都是针对不同的需求场景。在每一种下半部分机制中,Linux都设计了非常方便的接口函数。作为开发者的我们来说,使用这些下半部分的机制很简单,只需要几个函数调用即可。例如:如果使用工作队列来实现下半部分的工作,只需要2步动作

4.3 注册中断函数

  • 中断注册,就是告诉操作系统:我对哪个中断感兴趣。当这些中断发生的时候,请通知我。通知的方式就是:调用一个预先注册好的回调函数。驱动程序可以通过函数 request_irq(),向操作系统注册,并且激活指定的中断线
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *devname, void *dev_id);
参数说明:
irq: 申请的硬件中断号;
handler: 中断处理函数。一旦中断发生,这个函数就被调用;
flags: 中断的属性,例如:IRQF_DISABLED,IRQF_TIMER,IRQF_SHARED;
devname: 中断驱动程序的名称,在 /proc/interrupts 文件中看到对应的内容;
dev_id: 中断程序的唯一标识,比如:在共享中断中,可以用来区分不同的中断处理程序;

驱动程序通过函数 free_irq(),向操作系统注销一个中断处理函数:

void free_irq(unsigned int irq, void *dev_id);
参数说明:
irq: 硬件中断号;
dev_id: 中断程序的唯一标识;
  • 在中断处理函数中,注册函数
INIT_WORK(&mywork, mywork_handler);                                                         
schedule_work(&mywork);

4.4 定义处理函数

static struct work_struct mywork;static void mywork_handler(struct work_struct *work)
{printk("This is myword_handler...\n");
}

4.5 捕获键盘中断

示例代码,捕获键盘的中断,在中断处理函数中,打印出按键的扫描码,如果是 ESC 键被按下,就打印出指定的信息。操作的目录位于:/linux-4.15/drivers 目录下。

$ mkdir my_driver_interrupt
$ touch driver_interrupt.c

4.5.1 driver_interrupt.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>// 中断号
static int irq; // 驱动程序名称 
static char * devname;          // 用来接收加载驱动模块时传入的参数
module_param(irq, int, 0644);
module_param(devname, charp, 0644);// 定义驱动程序的 ID,在中断处理函数中用来判断是否需要处理            
#define MY_DEV_ID           1211// 驱动程序数据结构
struct myirq
{int devid;
};// 保存驱动程序的所有信息
struct myirq mydev  ={ MY_DEV_ID };// 键盘相关的 IO 端口
#define KBD_DATA_REG        0x60  
#define KBD_STATUS_REG      0x64
#define KBD_SCANCODE_MASK   0x7f
#define KBD_STATUS_MASK     0x80// 中断处理函数
static irqreturn_t myirq_handler(int irq, void * dev)
{struct myirq mydev;unsigned char key_code;mydev = *(struct myirq*)dev;    // 检查设备 id,只有当相等的时候才需要处理if (MY_DEV_ID == mydev.devid){// 读取键盘扫描码key_code = inb(KBD_DATA_REG);/* 这里如果放开,每次按键都会打印出很多信息printk("key_code: %x %s\n",key_code & KBD_SCANCODE_MASK,key_code & KBD_STATUS_MASK ? "released" : "pressed");*/// 判断:是否为 ESC 键if (key_code == 0x01){printk("EXC key is pressed! \n");}}   return IRQ_HANDLED;
}// 驱动模块初始化函数
static int __init myirq_init(void)
{printk("myirq_init is called. \n");// 注册中断处理函数if(request_irq(irq, myirq_handler, IRQF_SHARED, devname, &mydev)!=0){printk("register irq[%d] handler failed. \n", irq);return -1;}printk("register irq[%d] handler success. \n", irq);return 0;
}// 驱动模块退出函数
static void __exit myirq_exit(void)
{printk("myirq_exit is called. \n");// 注销中断处理函数free_irq(irq, &mydev);
}MODULE_LICENSE("GPL");
module_init(myirq_init);
module_exit(myirq_exit);
  • 上面的代码,有两个小的知识点。

4.6 加载驱动时传参

示例代码中,在调用 request_irq 时,需要指定中断号和驱动程序的名称。这两个参数是在加载驱动模块的时候,从命令行传入的。在驱动程序中,通过下面两行代码即可实现参数的接收:

module_param(irq, int, 0644);
module_param(devname, charp, 0644);

module_param 是一个宏定义,定义在 include/linux/moduleparam.h 文件中,具体定义如下:

#define module_param(name, type, perm)                module_param_named(name, name, type, perm);

name: 存储参数的变量名;
type: 变量的类型;
perm: 访问参数的权限,表示此参数在sysfs文件系统中所对应的文件节点的属性;

4.8 IO地址

读取 IO 外设的两种不同方式:IO内存和IO端口

4.8.1 IO内存

4.8.1 IO端口

IO 端口有两种编址方式:统一编址和独立编址。

4.8.1.1 统一编址

  • 把主存单元所在的地址空间,划出一部分出来,专门用来把IO外设寄存器的地址映射到这部分划出来的内存地址空间中。统一编址的好处是:读取IO外设的时候,就好像读取普通的内存地址空间中的数据一样。

4.8.1.2 独立编址

  • IO 外设的地址空间,与主存单元的地址空间是两个独立的地址空间,此时,IO地址一般称作: IO端口。我们在读写IO外设的时候,从这些 “IO端口” 中读写就可以了。不同的外设,被分配了不同的 IO 端口号。CPU 提供了一些列函数来读写 IO 端口,例如:
// 读写一个字节
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);// 读写一个字
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);

4.7 编译、验证

编译驱动模块:

$ make
输出文件:driver_interrupt.ko

因为我们捕获的是键盘中断(中断号:1),先看一下在加载驱动模块之前的中断驱动程序 head /proc/interrupts
在这里插入图片描述
可以把 demsg 的输出也清理一下:dmesg -c
执行下面指令来加载驱动模块(传递2个参数)insmod driver_interrupt.ko irq=1 devname=myirq再次执行一下指令 head /proc/interrupts 查看驱动程序:
在这里插入图片描述
中断号 1 的右侧,是不是看到了我们的驱动程序:my_irq再来看一下 dmesg 的输出信息:
在这里插入图片描述
成功注册了中断号1的处理函数!
此时,按几次键盘左上角的 ESC 键,然后再查看 dmesg 的输出信息:

这篇关于【genius_platform软件平台开发】第七十讲:linux系统驱动开发之-中断号、中断向量和中断处理函数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/525040

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof