中断: CPU在执行过程中, 硬件发生状态变化时, 打断CPU程序的执行,先做硬件状态变化时需要处理,再接着执行原程序.
中断其实就是由硬件主动来告诉我们它的状态发生改变了, 而不需要一直轮询硬件状态 .
arm里有异常向量表,当发生中断异常,不是执行0x18就是执行0xffff0018上的代码指令.也就是不管是什么中断,都是由在这地址上的代码来处理.
arm里只有一个中断异常功能,都由SOC里的中断控制器来扩展中断线(用于实现多个硬件的中断功能)和管理中断线的功能.
在手册里的P206. GIC的图表里可以看到, 只有PA组,PG组的IO口有中断功能.
除此之外还有很多控制器的中断号.
内部中断:指SOC里的控制器的中断线只在芯片内部,不会引出芯片外的中断.
外部中断:指SOC里会引出芯片外的中断线, 也就是指有中断功能的GPIO.
内部中断什么情况下中断CPU已经是固定的,但外部中断什么情况下中断CPU是由我们来指定在GPIO什么电平状态下产生中断.
一个GPIO的电平状态: 高电平, 低电平, 上升沿, 下降沿, 双边沿
GPIO_INT --> GIC ---> arm IRQ
////////////////////////////////
在linux内核里已实现好arm的中断异常处理,芯片厂商已驱动好中断控制器,定义好中断号(在arch/arm/mach-sunxi/include/mach/irqs.h).
因我们用最多的是外部中断, 可以根据IO口来获取指定的中断号(gpio_to_irq(int gpio)).
我们只需使用一个函数来请求使用中断即可.
#include <linux/interrupt.h>
int request_irq(unsigned int irq,
irq_handler_t handler,
unsigned long flags, const char * name, void *dev)
//irq为中断号, handler为中断处理函数, flags可设触发方式或中断方式,
name为中断设备名字(cat /proc/interrupts), dev用于中断处理函数执行的参数
//中断处理函数的原形:
irqreturn_t (*irq_handler_t)(int irqno, void *arg);
//irqreturn_t是返回值类型,通常是IRQ_HANDLED表示已处理中断了.
// irqno表示当前发生中断的中断号, arg为request_irq时的dev参数.
//中断触发方式:
#define IRQF_TRIGGER_NONE 0x00000000
#define IRQF_TRIGGER_RISING 0x00000001
#define IRQF_TRIGGER_FALLING 0x00000002
#define IRQF_TRIGGER_HIGH 0x00000004
#define IRQF_TRIGGER_LOW 0x00000008
#define IRQF_DISABLED 0x00000020 //当中断处理函数执行时不会被打断
#define IRQF_SAMPLE_RANDOM 0x00000040 //帮助产生随机数种子
#define IRQF_SHARED 0x00000080 //共享中断,即一个中断号,多个处理函数. 但一般都是一个中断号一个处理函数的.
可通过”cat /proc/interrupts”查看系统里所用的中断信息(如中断触发次数等)
/////////////////////////////////
PA(7)接烟雾传感器.感应到烟雾时输出低电平,正常高电平.
中断的触发方式使用下降沿.
test.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <mach/gpio.h>
#include <linux/gpio.h>
#define DETECT_IO GPIOA(7) //PA(7)
irqreturn_t irq_func(int irqno, void *arg)
{
printk("smoke detected ...\n");
return IRQ_HANDLED;
}
static int __init test_init(void)
{
int ret;
ret = request_irq(gpio_to_irq(DETECT_IO), irq_func, IRQF_TRIGGER_FALLING, "detector", NULL);
return ret;
}
static void __exit test_exit(void)
{
free_irq(gpio_to_irq(DETECT_IO), NULL);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
内核还提供了中断的管理函数, 可用于临时性的关闭或开启中断功能:
void disable_irq(unsigned int irq) //关闭指定中断号的中断功能,调用函数会堵塞直到关闭为止
//注意不可以在中断处理函数里调用此函数
void disable_irq_nosync(unsigned int irq) //关闭指定中断号的中断功能,调用此函数不会堵塞。可在中断处理函数里调用此函数.
void enable_irq(unsigned int irq) //开始指定中断号的中断功能
local_irq_enable(); // cpsr[7] = 0, 恢复arm核心的中断功能;
local_irq_disable(); //关闭arm核心里的中断功能, cpsr[7] = 1
local_irq_save(flags); //备份cpsr寄存器内容到flags变量后, 关闭arm核心里的中断功能
local_irq_restore(flags); //恢复arm核心的中断功能, cpsr = flags
本文深入讲解了ARM架构下的中断处理机制,包括中断的概念、中断在ARM中的实现方式、中断控制器的作用,以及Linux内核中如何管理和使用中断。此外,还通过一个具体的烟雾传感器中断示例介绍了中断请求和处理的具体步骤。
2128

被折叠的 条评论
为什么被折叠?



