在嵌入式Linux下开中断实例解析
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
printk(KERN_INFO"Can't get assigned irq %d,result=%d\n",IRQ_EINT0,result); return result; }
printk(KERN_INFO"embedirq interrupt registered ok!!!\n"); /*将 my_tasklet_handler加入链表*/ tasklet_init(&my_tasklet,my_tasklet_handler,NULL); return 0; } 编写模块退出函数tasklet_exit_module: /*退出模块*/ void embedirq_exit_module(void) { /*清除指定my_tasklet的可调度位*/ tasklet_kill(&my_tasklet); disable_irq(IRQ_EINT0); free_irq(IRQ_EINT0, NULL); printk(KERN_INFO"exit ok\n"); }
这个实例主要参考了邱铁编著的《Linux 应用与开发典型实例精讲》.清华大学出版 社.2010 出版的第 14 章。
简易的硬件电路组成
ARM9嵌入式微处理器S3C2410与按键的接口电路如图所示。从图中可以看出,按键从 S3C2410的端口F的第0引脚引入。S3C2410的端口F引脚信息如表所示表中分别列出了端口F 控制寄存器GPFCON、数据寄存器GPFDAT和上拉电阻使能寄存器GPFUP位信息。
实例结果分析
中断服务函数编写完成后,编译生成 int_bottom_half.ko 文件,并下载文件到指定的嵌 入式设备中, 并以模块的方式将中断服务函数插入 Linux 内核,终端操作与显示如图 14.8 所示。从图中可以看出,中断 EINT0 注册成功。
插入中断服务模块
使用不着 lsmod 命令查看所插入的模块,如图所示,模块 int_bottom_half 已经成功的插 入系统中。
3C2410 按键外中断接口电路
从表可以看出,GPF0引脚与外中断EINT0复用,因此,为了减少系统的开销,可以将按
键服务写成外中断服务的形式。
GPFCON、GPFDAT 和 GPFUP 寄存器信息
寄存器
地址
读/写
描述
复位值
GPFCON
0x56000050
R/W 配置端口 F 的引脚
0x0
GPFDAT
描述 0 :上拉电阻与相应的引脚连接使能 1 :上拉电阻被禁止
接下来编写中断服务模块
建立 int_bottom_half.c 文件,代码如下: 头文件及声明如下: #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h>
国电力出版社.2007 [3]邱铁 编著. ARM 嵌入式系统结构与编程. 清华大学出版社. 2009
#include <linux/signal.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <asm/irq.h> #include <asm/arch/hardware.h> #include <asm/arch/irqs.h> #include <asm/io.h>
/*设置端口F的上接电阻*/ gpfup = ioremap(0x56000058,4); (*(volatile unsigned long *)gpfup) = 0;
enable_irq(IRQ_EINT0); //使能外中断0 /*注册外中断0的中断服务函数*/ result=request_irq(IRQ_EINT0,&embedirq_interrupt,SA_INTERRUPT,"embedirq",NULL); if (result) {
[15:14] [13:12] [11:10] [9:8] [7:6] [5:4] [3:2] [1:0]
位 [7:0]
位 [7:0]
00 = 输入 10 = EINT7 00 = 输入 10 = EINT6 00 = 输入 10 = EINT5 00 = 输入 10 = EINT4 00 = 输入 10 = EINT3 00 = 输入 10 = EINT2 00 = 输入 10 = EINT1 00 = 输入 10 = EINT0
/*清除中断挂起寄存器,使下次中断服务成为可能*/ SRCPND &= (~0x00000001); //bit0
INTPND = INTPND; printk(KERN_INFO"Entered an interrupt! Beginning interrupt service!\n");
/*调度my_tasklet,执行my_tasklet_handler */ tasklet_schedule(&my_tasklet); } 编写模块初始化函数 embedirq_init_module: int embedirq_init_module(void) { static int result; unsigned long gpfup; set_external_irq(IRQ_EINT0, EXT_FALLING_EDGE, GPIO_PULLUP_DIS);
01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留
描述 当端口被配置成输入端口,从外部源来的数据可以被读到相应引脚 当端口被配置成输出端口,写入寄存器的数据可以被送到相应引脚 当端口被配置为功能端口,读取该端口数据为乱码
编写 my_tasklet_handler 函数: void my_tasklet_handler(unsigned long data) {
printk(KERN_INFO"in the botton half!\n"); }
编写中断服务函数 embedirq_interrupt: void embedirq_interrupt(int irq,void *d,struct pt_regs *regs) {
源自文库
MODULE_LICENSE("GPL"); //声明许可证
struct tasklet_struct my_tasklet; void embedirq_interrupt(int,void *,struct pt_regs *); void my_tasklet_handler(unsigned long data); static int __init embedirq_init_module(void); static void __exit embedirq_exit_module(void); module_init(embedirq_init_module); //指定模块初始化函数embedirq_init_module module_exit(embedirq_exit_module); //指定模块退出函数embedirq_exit_module
在嵌入式 Linux 下开中断实例解析
我们都知道键盘等都是采用中断形式的,但是如何用一个极其简单实用的例子给大家作 一下演示是十分重要的。下面我们动手做一个嵌入式 LINUX 中断的实例(包括硬件原理与 开中断的过程)。
中断在嵌入式开发中断应用较多,对于不确定事件使用中断方式进行服务,可以大大的 减少系统的软件开销。下面以运行在 ARM9 嵌入式微处理器 S3C2410 硬件平台上的嵌入式 Linux 为例介绍在嵌入式 Linux 下开中断的方法。
图 14.9 查看系统模块
最后,我们来测试一下,按下中断接口按键,中断服务输出如图所示。
中断服务
从图中显示来看,按下中断按键后,中断服务函数得到了正确的执行,并在中断服务函 数中调度了中断下半部。
参考文献:
[1] 邱铁,于玉龙.Linux 应用与开发典型实例精讲.北京:清华大学出版社.2010 [2]Daniel P. Bovet, Marco Cesati 著 陈莉君, 张琼声, 张宏伟译深入理解 linux 内核. 北京:中
0x56000054
R/W 端口 F 的数据寄存器
未定义
GPFUP
0x56000058
R/W 端口 F 上拉禁止寄存器
0x0
保留
0x5600005C
–
保留
未定义
GPFCON
位
描述
GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0 GPFDAT GPF [7:0]
GPFUP GPF[7:0]
printk(KERN_INFO"embedirq interrupt registered ok!!!\n"); /*将 my_tasklet_handler加入链表*/ tasklet_init(&my_tasklet,my_tasklet_handler,NULL); return 0; } 编写模块退出函数tasklet_exit_module: /*退出模块*/ void embedirq_exit_module(void) { /*清除指定my_tasklet的可调度位*/ tasklet_kill(&my_tasklet); disable_irq(IRQ_EINT0); free_irq(IRQ_EINT0, NULL); printk(KERN_INFO"exit ok\n"); }
这个实例主要参考了邱铁编著的《Linux 应用与开发典型实例精讲》.清华大学出版 社.2010 出版的第 14 章。
简易的硬件电路组成
ARM9嵌入式微处理器S3C2410与按键的接口电路如图所示。从图中可以看出,按键从 S3C2410的端口F的第0引脚引入。S3C2410的端口F引脚信息如表所示表中分别列出了端口F 控制寄存器GPFCON、数据寄存器GPFDAT和上拉电阻使能寄存器GPFUP位信息。
实例结果分析
中断服务函数编写完成后,编译生成 int_bottom_half.ko 文件,并下载文件到指定的嵌 入式设备中, 并以模块的方式将中断服务函数插入 Linux 内核,终端操作与显示如图 14.8 所示。从图中可以看出,中断 EINT0 注册成功。
插入中断服务模块
使用不着 lsmod 命令查看所插入的模块,如图所示,模块 int_bottom_half 已经成功的插 入系统中。
3C2410 按键外中断接口电路
从表可以看出,GPF0引脚与外中断EINT0复用,因此,为了减少系统的开销,可以将按
键服务写成外中断服务的形式。
GPFCON、GPFDAT 和 GPFUP 寄存器信息
寄存器
地址
读/写
描述
复位值
GPFCON
0x56000050
R/W 配置端口 F 的引脚
0x0
GPFDAT
描述 0 :上拉电阻与相应的引脚连接使能 1 :上拉电阻被禁止
接下来编写中断服务模块
建立 int_bottom_half.c 文件,代码如下: 头文件及声明如下: #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h>
国电力出版社.2007 [3]邱铁 编著. ARM 嵌入式系统结构与编程. 清华大学出版社. 2009
#include <linux/signal.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <asm/irq.h> #include <asm/arch/hardware.h> #include <asm/arch/irqs.h> #include <asm/io.h>
/*设置端口F的上接电阻*/ gpfup = ioremap(0x56000058,4); (*(volatile unsigned long *)gpfup) = 0;
enable_irq(IRQ_EINT0); //使能外中断0 /*注册外中断0的中断服务函数*/ result=request_irq(IRQ_EINT0,&embedirq_interrupt,SA_INTERRUPT,"embedirq",NULL); if (result) {
[15:14] [13:12] [11:10] [9:8] [7:6] [5:4] [3:2] [1:0]
位 [7:0]
位 [7:0]
00 = 输入 10 = EINT7 00 = 输入 10 = EINT6 00 = 输入 10 = EINT5 00 = 输入 10 = EINT4 00 = 输入 10 = EINT3 00 = 输入 10 = EINT2 00 = 输入 10 = EINT1 00 = 输入 10 = EINT0
/*清除中断挂起寄存器,使下次中断服务成为可能*/ SRCPND &= (~0x00000001); //bit0
INTPND = INTPND; printk(KERN_INFO"Entered an interrupt! Beginning interrupt service!\n");
/*调度my_tasklet,执行my_tasklet_handler */ tasklet_schedule(&my_tasklet); } 编写模块初始化函数 embedirq_init_module: int embedirq_init_module(void) { static int result; unsigned long gpfup; set_external_irq(IRQ_EINT0, EXT_FALLING_EDGE, GPIO_PULLUP_DIS);
01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留 01 = 输出 11 = 保留
描述 当端口被配置成输入端口,从外部源来的数据可以被读到相应引脚 当端口被配置成输出端口,写入寄存器的数据可以被送到相应引脚 当端口被配置为功能端口,读取该端口数据为乱码
编写 my_tasklet_handler 函数: void my_tasklet_handler(unsigned long data) {
printk(KERN_INFO"in the botton half!\n"); }
编写中断服务函数 embedirq_interrupt: void embedirq_interrupt(int irq,void *d,struct pt_regs *regs) {
源自文库
MODULE_LICENSE("GPL"); //声明许可证
struct tasklet_struct my_tasklet; void embedirq_interrupt(int,void *,struct pt_regs *); void my_tasklet_handler(unsigned long data); static int __init embedirq_init_module(void); static void __exit embedirq_exit_module(void); module_init(embedirq_init_module); //指定模块初始化函数embedirq_init_module module_exit(embedirq_exit_module); //指定模块退出函数embedirq_exit_module
在嵌入式 Linux 下开中断实例解析
我们都知道键盘等都是采用中断形式的,但是如何用一个极其简单实用的例子给大家作 一下演示是十分重要的。下面我们动手做一个嵌入式 LINUX 中断的实例(包括硬件原理与 开中断的过程)。
中断在嵌入式开发中断应用较多,对于不确定事件使用中断方式进行服务,可以大大的 减少系统的软件开销。下面以运行在 ARM9 嵌入式微处理器 S3C2410 硬件平台上的嵌入式 Linux 为例介绍在嵌入式 Linux 下开中断的方法。
图 14.9 查看系统模块
最后,我们来测试一下,按下中断接口按键,中断服务输出如图所示。
中断服务
从图中显示来看,按下中断按键后,中断服务函数得到了正确的执行,并在中断服务函 数中调度了中断下半部。
参考文献:
[1] 邱铁,于玉龙.Linux 应用与开发典型实例精讲.北京:清华大学出版社.2010 [2]Daniel P. Bovet, Marco Cesati 著 陈莉君, 张琼声, 张宏伟译深入理解 linux 内核. 北京:中
0x56000054
R/W 端口 F 的数据寄存器
未定义
GPFUP
0x56000058
R/W 端口 F 上拉禁止寄存器
0x0
保留
0x5600005C
–
保留
未定义
GPFCON
位
描述
GPF7 GPF6 GPF5 GPF4 GPF3 GPF2 GPF1 GPF0 GPFDAT GPF [7:0]
GPFUP GPF[7:0]