linux中断及其底半部-s5p6818开发平台

2023-05-16

中断分为两个部分:中断顶部(top half)和中断底半部(bootom half)
一、中断顶部(top half)
中断上半部需要处理一下三种情况:
1,如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
2,如果一个任务和硬件相关,将其放在中断处理程序中执行。
3,如果一个人物要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中 执行。
4,其他所有任务,考虑放在中断底半部去执行。

一下代码都是基于s5p6818开发平台按键实验

    头文件<linux/interrupt.h>
    //中断请求函数
     int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, \
     const char *name,void *dev);
    功能:向内核请求注册中断
    参数:
            @irq	   		中断号    
            gpio_to_irq() //将GPIO号转化成中断号
            @handler		中断处理函数指针
            //中断处理函数
            typedef irqreturn_t (*irq_handler_t)(int , void *);  函数指针类型
            irqreturn_t    返回值类型是枚举类型
    		IRQ_NONE			没有处理
    		IRQ_HANDLED		已经处理完成
    		irqreturn_t    irq_handler(int  irq,void*args)
    		{
        
   			}
   			
            @flags          中断标志
           	中断的触发方式(中断标志中的一种):
        	IRQF_TRIGGER_RISING      上升沿触发
        	IRQF_TRIGGER_FALLING    下降沿触发
        	IRQF_TRIGGER_HIGH          高电平触发
        	IRQF_TRIGGER_LOW 		低电平触发
        
    		IRQF_DISABLED      屏蔽同级别中断
    		IRQF_SHARED         中断共享
    		
            @name			中断名字
            @dev            私有数据
    返回值:成功返回0,失败返回负数错误码
    
    //中断注销函数
    void free_irq(unsigned int, void *);   //释放/注销中断

下方代码是在s5p6818开发平台上进行的按键中断

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#define GPIOA28 28
#define NAME  "key_gpioa28"

int irqno = 0;
/*中断处理函数*/
irqreturn_t irq_handler(int irqno, void *args)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	return IRQ_HANDLED;    //处理中断后返回的已处理标志
}
int __init key_int_init(void)
{
	int ret = 0;
	irqno = gpio_to_irq(GPIOA28);    //通过gpio号获取中断号
	/*向内核请求注册中断*/
	ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
		NAME, NULL);
	if(ret < 0){
		printk(KERN_ERR "request_irq failed...\n");
		return ret;
	}
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	return 0;
}
void __exit key_int_exit(void)
{
   /*释放中断*/
	free_irq(irqno,NULL);
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}

module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");

二、中断底半部(top half)
【1】软中断
特点:可以被中断(顶半部)打断,不可以被中断底半部打断,不参与进程调度
要求:可以有耗时操作(相对来将) —>>> 可以使用for ,不可以使用延时和睡眠函数

void open_softirq(int nr, void (*action)(struct softirq_action *))
void raise_softirq(unsigned int nr)

【2】tasklet tasklet依赖软中断实现
特点:可以被中断(顶半部)打断,不可以被中断底半部打断,不参与进程调度
要求:可以有耗时操作(相对来将) —>>> 可以使用for ,不可以使用延时和睡眠函数

 数据类型:
    struct tasklet_struct
    {
    	struct tasklet_struct *next;       //内核使用链表方式管理的时候使用的
    	unsigned long state;
    	atomic_t count;
    	void (*func)(unsigned long);   //中断底半部处理函数
    	unsigned long data;		       //用户数据
    };
    void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long),unsigned long data);
    功能:初始化tasklet
    参数:
        @t		tasklet结构体指针
        @func      中断底半部处理函数
        @data      私有数据
    void tasklet_schedule(struct tasklet_struct *t)
    功能:调度tasklet底半部
    参数:
            @t     tasklet结构体指针

实验代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

#define GPIOA28 28
#define NAME  "key_gpioa28"

int irqno = 0;

struct tasklet_struct task;

/*由tasklet实现的中断底半部处理函数*/
void task_func(unsigned long args)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}



/*中断顶半部执行处理函数*/
irqreturn_t irq_handler(int irqno, void *args)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	tasklet_schedule(&task);
	return IRQ_HANDLED;
}


int __init key_int_init(void)
{
	int ret = 0;

	irqno = gpio_to_irq(GPIOA28);
	
	ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
		NAME, NULL);
	if(ret < 0){
		printk(KERN_ERR "request_irq failed...\n");
		return ret;
	}

	tasklet_init(&task,task_func,0);

	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	return 0;
}

void __exit key_int_exit(void)
{
	free_irq(irqno,NULL);
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}

module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");

【3】工作队列
特点:可以被中断(顶半部)打断,也可以被中断底半部打断,也参与进程调度
要求:可以有耗时操作,也可以有涉及进程调度相关函数

	//头文件
	<linux/workqueue.h>

    INIT_WORK(_work, _func)		
    功能:初始化工作
    参数:
        @_work	    struct work_struct 指针
        struct work_struct 
        {
    	atomic_long_t data;
    	work_func_t func;
    	};
    	
        @_func       工作队列底半部处理函数
        /*工作队列实现的底半部处理函数指针*/
    	typedef void (*work_func_t)(struct work_struct *work);
    
    	int schedule_work(struct work_struct *work);
    	功能:工作队列调度工作底半部处理函数
    	参数:
        @work	struct work_struct 指针

   	 	create_workqueue(name)
   	 	功能:创建工作队列
    	参数:
       		 @name    名字
    	返回值:返回struct workqueue_struct结构体指针
        
		int queue_work(struct workqueue_struct *wq, struct work_struct *work);
		功能:将工作添加在工作队列里
		参数:
        	@wq    工作队列结构体
        	@work 工作结构体

第一种方法

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>

#define GPIOA28 28
#define NAME  "key_gpioa28"
int irqno = 0;
struct work_struct work;
struct workqueue_struct *work_queue;

/*由工作队列实现的中断底半部处理函数*/
void work_func(struct work_struct *work)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
/*中断顶半部执行处理函数*/
irqreturn_t irq_handler(int irqno, void *args)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	queue_work(work_queue, &work); //添加工作到工作队列中,等待被调度
	return IRQ_HANDLED;
}
int __init key_int_init(void)
{
	int ret = 0;

	irqno = gpio_to_irq(GPIOA28);
	
	ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
		NAME, NULL);
	if(ret < 0){
		printk(KERN_ERR "request_irq failed...\n");
		return ret;
	}
	/*创建工作队列*/
	work_queue = create_workqueue("key_work_queue");
	/*初始化工作*/
   INIT_WORK(&work,work_func);

	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	return 0;
}
void __exit key_int_exit(void)
{
	free_irq(irqno,NULL);
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}
module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");

第二种方法

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>

#define GPIOA28 28
#define NAME  "key_gpioa28"

int irqno = 0;
struct work_struct work;
struct workqueue_struct *work_queue;

/*由工作队列实现的中断底半部处理函数*/
void work_func(struct work_struct *work)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}

/*中断顶半部执行处理函数*/
irqreturn_t irq_handler(int irqno, void *args)
{
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	queue_work(work_queue, &work);
	return IRQ_HANDLED;
}

int __init key_int_init(void)
{
	int ret = 0;
	irqno = gpio_to_irq(GPIOA28);
	ret = request_irq(irqno,irq_handler,IRQF_TRIGGER_FALLING|IRQF_DISABLED, \
		NAME, NULL);
	if(ret < 0){
		printk(KERN_ERR "request_irq failed...\n");
		return ret;
	}
	work_queue = create_workqueue("key_work_queue");
	INIT_WORK(&work,work_func);

	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
	return 0;
}
void __exit key_int_exit(void)
{
	free_irq(irqno,NULL);
	printk(KERN_INFO "---%s---%s--%d---\n",__FILE__,__func__,__LINE__);
}

module_init(key_int_init);
module_exit(key_int_exit);
MODULE_LICENSE("GPL");

内核提供的延时机制:
1.中断底半部
2.定时器
3.延时函数和睡眠函数(delay.h)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux中断及其底半部-s5p6818开发平台 的相关文章

随机推荐

  • 推荐几个代码自动生成器,神器!!!

    20个代码生成框架 老的代码生成器的地址 xff1a https www cnblogs com skyme archive 2011 12 22 2297592 html 以下是大家推荐的最近很火爆的代码生成器神器 如果有更好的希望大家多
  • linux 安装discuz出现“ mysqli_connect()不支持advice_mysqli_connect ”解决方法

    由于不了解php相关技术 xff0c 所以在安装discuz的时候遇到了很多麻烦 xff0c 记录下 首先 xff0c 我的环境是CentOS6 5 xff0c 在安装discuz的时候需要yum很多东西 yum install php p
  • Ubuntu 22.04 LTS下Miniconda安装+换源(踩坑向)

    1 安装Miniconda 我使用的是Python3 8 xff0c 如果需要去其他对应版本 xff0c 请查看 Miniconda conda documentation 下载 wget https repo anaconda com m
  • FreeBSD修改为国内源

    禁用原来的FreeBSD conf ee etc pkg FreeBSD conf 将 enabled yes 改为 enabled no 保存 ESC 然后 a gt a 即可 创建另外一个 FreeBSD conf mkdir p us
  • 关于51单片机的中断

    1 中断的要求 1 中断源有中断请求 Ask for instructions of the CPU interrupt request source called interrupt source 2 此中断源的中断允许位为1 The i
  • 华为机试_HJ5 进制转换【简单】

    描述 写出一个程序 xff0c 接受一个十六进制的数 xff0c 输出该数值的十进制表示 数据范围 xff1a 保证结果在 1 le n le 2 31 1 1 n 231 1 输入描述 xff1a 输入一个十六进制的数值字符串 输出描述
  • bootstrap实现 — 个人简介

    实现 xff1a bootstrap 效果图 xff1a 源码 xff1a lt DOCTYPE html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt titl
  • 计蒜客--T1079--打表+控制输出

    假设有 N 盏灯 xff08 NN为不大于 5000 的正整数 xff09 xff0c 从 1 到 N 按顺序依次编号 xff0c 初始时全部处于开启状态 xff1b 有 M 个人 xff08 M 为不大于 N的正整数 xff09 也从 1
  • Authentication plugin ‘caching_sha2_password‘ 服务端也无法连接问题彻底解决

    在网上搜索了很多的帖子 xff0c 发现描述的都是外部客户端无法登录到mysql上 xff0c 登录上服务器以后连接更改配置的方式 xff0c 但是 xff01 xff01 xff01 xff01 xff01 我现在是服务器连接也报错啊啊啊
  • Hexo分类及标签显示

    Hexo根目录配置 config yml category map Blogs categories Blogs Tech categories Tech Tools categories Tools Other categories Ot
  • IDEA查看历史记录

    方法一 文件内 Ctrl 43 右键 Local History Show History xff0c 显示当前文件的本地修改历史 方法二 一 xff1a 在文件内 xff0c 按 Ctrl 43 Shift 43 A 弹出全部搜索对话框
  • SpringBoot-JPA整合ShardingShpere自定义分布式主键

    分布式主键简介 在分布式环境下 xff0c 由于分库分表导致数据水平拆分后无法使用单表自增主键 xff0c 因此我们需要一种全局唯一id生成策略作为分布式主键 当前有如下解决方案 UUID xff08 Universally Unique
  • Gitlab的安装与配置

    安装开始时 xff0c 需确认服务器最小配置是2核4G xff0c 因为gitlab软件比较大 1 配置yum源 xff1a vim etc yum repos d gitlab repo gitlab name 61 gitlab ce
  • Error creating bean with name ‘org.springframework.aop.aspectj.AspectJPointcutAdvisor#0

    问题 xff1a nested exception is org springframework beans factory BeanCreationException Error creating bean with name 39 or
  • Vue前端项目开发页面(二)

    前端界面开发 开发工具版本 64 vue cli 4 5 13 新建Login vue登陆页 1 在 vue exemples 项目 xff0c 选中components目录右键 New Vue Component xff0c 名称为 Lo
  • SpringBoot整合WebSocket

    概述 HTTP 协议是一种无状态的 无连接的 单向的应用层协议 它采用了请求 响应模型 通信请求只能由客户端发起 xff0c 服务端对请求做出应答处理 WebSocket和HTTP一样 xff0c 都是一种网络通信协议 比起HTTP只能由客
  • SpringBoot整合MybatisPlus使用IPage实现分页

    概述 MybatisPlus 提供了分页的功能 IPage内部原理是基于拦截器 xff0c 但是这个拦截的是方法以及方法中的参数 xff0c 这个也会判断是否是查询操作 如果是查询操作 xff0c 才会进入分页的处理逻辑 进入分页逻辑处理后
  • SpringBoot统一异常处理

    概述 SpringBoot 提供了 64 ControllerAdvice 64 RestControllerAdvice 注解可以实现统一异常处理 xff0c 只需要在定义异常类加上以上注解即可 自定义异常处理 定义统一异常处理 span
  • 萌新学习算法——并查集基础

    并查集 在算法设计中 xff0c 将一个集合和另外一个集合合并时 xff0c 就会用到并查集 假如不用并查集 xff0c 你可能会用到集合和列表来实现 xff0c 这样会使代码看起来很复杂 xff0c 而且执行效率不高 xff0c 下面用洛
  • linux中断及其底半部-s5p6818开发平台

    中断分为两个部分 xff1a 中断顶部 xff08 top half xff09 和中断底半部 xff08 bootom half xff09 一 中断顶部 xff08 top half xff09 中断上半部需要处理一下三种情况 xff1