嵌入式内核及驱动开发之学习笔记(十一) 中断优化处理

ARM cortex-A系列的内核不支持中断嵌套。在内核中断函数中,如果中断处理时间过长,产生中断嵌套,重者系统崩溃,轻者也会影响其他事件处理。这也是中断中不能使用延时函数的原因。

但是有些高实时性设备(比如网卡),就是需要处理大量的业务。为了满足中断处理时间尽量短的原则,我们将一些简单的处理放在中断中实现,这个阶段叫做中断的上半部;其他一些复杂、耗时间的操作丢给内核线程,让内核来调度其执行,这是中断的下半部。

中断事件 -->  跳转中断入口 -->  中断中执行简单处理 -->  并启动内核调度复杂的处理 -->  结束中断

 

处理方式

  1. softirq: 处理比较快,但是内核级别的机制,需要修改整个内核源码,不推荐也不常用
  2. tasklet: 内部实现实际调用了softirq
  3. workqueue: 工作队列

 

tasklet

启动"下半部"实际上就是把结构体描述的对象丢给内核线程的动作。

结构体

struct tasklet_struct
{
	struct tasklet_struct *next;
	unsigned long state;
	atomic_t count;
	void (*func)(unsigned long); // 下半部的实现逻辑
	unsigned long data; // 传递给func
};

1.初始化对象


struct tasklet_struct mytasklet;

tasklet_init(struct tasklet_struct * t, void(* func)(unsigned long), unsigned long data)

 

2.构造"下半部"实现逻辑

void key_tasklet_half_irq(unsigned long data)
{
    //............
    //............
}

 

3."上半部"启动"下半部"

tasklet_schedule(&key_dev->mytasklet);

 

4.(在模块卸载时)注销内核线程中的对象

tasklet_kill(&key_dev->mytasklet);

 

完成的例子(驱动程序)

//key_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>




#include <asm/io.h>
#include <asm/uaccess.h>


irqreturn_t key_irq_handler(int irqno, void *devid);
void key_tasklet_half_irq(struct work_struct *work);

ssize_t key_drv_read (struct file *, char __user *, size_t, loff_t *);
ssize_t key_drv_write (struct file *, const char __user *, size_t, loff_t *);
int key_drv_open (struct inode *, struct file *);
int key_drv_close (struct inode *, struct file *);




#define GPXCON_REG  0x11000C20
#define KEY_ENTER		28


const struct file_operations key_fops = {
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_close,

};

struct key_event{
	int code; // 按键的类型
	int value; // 状态
};


struct key_desc{
	unsigned int dev_major;
	struct class *cls;
	struct device *dev;
	int irqno;
	void *reg_base;
	int key_state; 			//表示是否有数据
	struct key_event event;
	struct tasklet_struct mytasklet;

};
struct key_desc *key_dev;


int get_irqno_from_node(void)
{	
	//从设备树路径,查找节点
	struct device_node *np = of_find_node_by_path("/key_int_node");
	if(np){
		printk("find node ok\n");
	}else{
		printk("find node failed\n");
	}

	int irqno = irq_of_parse_and_map(np, 0);
	printk("irqno = %d\n", irqno);
	
	return irqno;
}


static int __init key_drv_init(void)
{
	int ret;

	//对象实例化
	key_dev = kzalloc(sizeof(struct key_desc),	GFP_KERNEL);

	//申请主设备号
	key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);

	//创建设备结点
	key_dev->cls = class_create(THIS_MODULE, "key_cls");
	key_dev->dev = device_create(key_dev->cls, NULL, 
									MKDEV(key_dev->dev_major,0), NULL, "key0");

	
	//硬件初始化
	key_dev->irqno = get_irqno_from_node();
	ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 
					"key3_eint10", NULL);
	if(ret != 0)
	{
		printk("request_irq error\n");
		return ret;
	}


	key_dev->reg_base  = ioremap(GPXCON_REG, 8);

	//初始化tasklet
	tasklet_init(&key_dev->mytasklet, key_tasklet_half_irq, 45);


	return 0;
}

static void __exit key_drv_exit(void)
{
	tasklet_kill(&key_dev->mytasklet);

	iounmap(key_dev->reg_base);			//去映射
	free_irq(key_dev->irqno, NULL);		//释放中断资源
	device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,0));	//
	class_destroy(key_dev->cls);								//
	unregister_chrdev(key_dev->dev_major, "key_drv");			//注销主设备号
	kfree(key_dev);												//释放结构体内存


}


irqreturn_t key_irq_handler(int irqno, void *devid)
{
	printk("-------%s-------------\n", __FUNCTION__);

	// 启动下半步
	tasklet_schedule(&key_dev->mytasklet);

	return IRQ_HANDLED;

}

void key_tasklet_half_irq(struct work_struct *work)
{
	printk("-------%s-------------\n", __FUNCTION__);
	
	
}


ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
	printk("-------%s-------------\n", __FUNCTION__);
	
	return count;

}

ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	printk("-------%s-------------\n", __FUNCTION__);

	return 0;
}

int key_drv_open(struct inode *inode, struct file *filp)
{
	printk("-------%s-------------\n", __FUNCTION__);

	return 0;
}

int key_drv_close (struct inode *inode, struct file *filp)
{
	printk("-------%s-------------\n", __FUNCTION__);

	return 0;
}




module_init(key_drv_init);
module_exit(key_drv_exit);

MODULE_LICENSE("GPL");

 

演示

 

 

workqueue

结构体描述

struct work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;
};

 

1.初始化对象

struct work_struct mywork;

INIT_WORK(struct work_struct *work, work_func_t func);

 

2.构造"下半部"实现逻辑

void work_irq_half(struct work_struct *work)
{
    //...填入要实现的内容

	
}

 

3."上半部"启动"下半部"

schedule_work(&key_dev->mywork);

 

代码(驱动)

//key_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>




#include <asm/io.h>
#include <asm/uaccess.h>


irqreturn_t key_irq_handler(int irqno, void *devid);
void work_irq_half(struct work_struct *work);

ssize_t key_drv_read (struct file *, char __user *, size_t, loff_t *);
ssize_t key_drv_write (struct file *, const char __user *, size_t, loff_t *);
int key_drv_open (struct inode *, struct file *);
int key_drv_close (struct inode *, struct file *);




#define GPXCON_REG  0x11000C20
#define KEY_ENTER		28


const struct file_operations key_fops = {
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_close,

};

struct key_event{
	int code; // 按键的类型
	int value; // 状态
};


struct key_desc{
	unsigned int dev_major;
	struct class *cls;
	struct device *dev;
	int irqno;
	void *reg_base;
	int key_state; 			//表示是否有数据
	struct key_event event;
	struct work_struct mywork;

};
struct key_desc *key_dev;


int get_irqno_from_node(void)
{	
	//从设备树路径,查找节点
	struct device_node *np = of_find_node_by_path("/key_int_node");
	if(np){
		printk("find node ok\n");
	}else{
		printk("find node failed\n");
	}

	int irqno = irq_of_parse_and_map(np, 0);
	printk("irqno = %d\n", irqno);
	
	return irqno;
}


static int __init key_drv_init(void)
{
	int ret;

	//对象实例化
	key_dev = kzalloc(sizeof(struct key_desc),	GFP_KERNEL);

	//申请主设备号
	key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);

	//创建设备结点
	key_dev->cls = class_create(THIS_MODULE, "key_cls");
	key_dev->dev = device_create(key_dev->cls, NULL, 
									MKDEV(key_dev->dev_major,0), NULL, "key0");

	
	//硬件初始化
	key_dev->irqno = get_irqno_from_node();
	ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, 
					"key3_eint10", NULL);
	if(ret != 0)
	{
		printk("request_irq error\n");
		return ret;
	}


	key_dev->reg_base  = ioremap(GPXCON_REG, 8);

	//初始化work
	INIT_WORK(&key_dev->mywork, work_irq_half);


	return 0;
}

static void __exit key_drv_exit(void)
{

	iounmap(key_dev->reg_base);			//去映射
	free_irq(key_dev->irqno, NULL);		//释放中断资源
	device_destroy(key_dev->cls, MKDEV(key_dev->dev_major,0));	//
	class_destroy(key_dev->cls);								//
	unregister_chrdev(key_dev->dev_major, "key_drv");			//注销主设备号
	kfree(key_dev);												//释放结构体内存


}


irqreturn_t key_irq_handler(int irqno, void *devid)
{
	printk("-------%s-------------\n", __FUNCTION__);

	// 启动下半步
	schedule_work(&key_dev->mywork);

	return IRQ_HANDLED;

}

void work_irq_half(struct work_struct *work)
{
	printk("-------%s-------------\n", __FUNCTION__);
	

}


ssize_t key_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos)
{
	printk("-------%s-------------\n", __FUNCTION__);
	
	return count;

}

ssize_t key_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	printk("-------%s-------------\n", __FUNCTION__);

	return 0;
}

int key_drv_open(struct inode *inode, struct file *filp)
{
	printk("-------%s-------------\n", __FUNCTION__);

	return 0;
}

int key_drv_close (struct inode *inode, struct file *filp)
{
	printk("-------%s-------------\n", __FUNCTION__);

	return 0;
}


module_init(key_drv_init);
module_exit(key_drv_exit);

MODULE_LICENSE("GPL");


 

演示

全部评论

相关推荐

hanliu:1. 排版与格式问题字体与对齐问题:标题和内容的字体大小差异不够明显,无法迅速吸引目光。某些文字看起来有些拥挤(比如校园经历中的“班委成员”部分)。2. 内容逻辑性模块顺序问题:实习经历放在较靠后的位置,实际上这部分内容对应聘来说更重要,建议提前突出。细节表述不够突出:比如教育背景部分的专业课程仅仅列出名字,没有说明自己在这些课程中表现如何或者掌握了什么技能,缺乏量化描述。多余内容:例如“班委成员”和“宣传委员”这类校园经历,叙述过于普通,缺乏和岗位相关的实质性贡献。,建议简写。3. 措辞专业性表达不够精准:例如“协助班长与团支书更好地为同学服务”显得较为笼统,没有实际成果的体现。用词重复:如“学习了焊接”“学习了光检”等重复词语较多,缺乏丰富的动词来展示个人能力(如“负责”“优化”“改进”等)。技能展示不足:虽然列出了UG和CAD证书,但没有明确提到这些技能如何在实际工作中发挥作用。4. 技能匹配度技能深度不足:虽然列出了掌握的软件和技术,但没有描述技能水平(如“熟练掌握”“精通”),也没有具体案例支持这些技能。缺乏岗位导向性:比如针对机械设计与制造方向,实习经历提到了“E6尾灯项目”,但没有详细说明自己在其中的技术贡献,可能会显得经验描述泛泛而谈。5. 自我评价问题表达空泛:如“具有良好的沟通协调能力”“责任心强”之类的描述太常见,没有让人眼前一亮的特点。缺乏成果支持:自我评价中的能力没有用具体项目、经历或成就来验证,可信度较弱。 兄弟加油
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务