框图 LPC3250有3个中断控制器,分别是1个主中断控制器(MIC)和2个子中断控制器(SIC1、SIC2)。整个框图以及它们的关系如下图:
![](http://sites.google.com/site/myembededlife/_/rsrc/1234350056591/Home/lpc3250/lpc3250-interrupt/ic.jpg)
寄存器汇总
每个控制器都有自己的一组寄存器,如下表所列:![](http://sites.google.com/site/myembededlife/_/rsrc/1234350342091/Home/lpc3250/lpc3250-interrupt/icr.jpg)
寄存器描述
每个中断控制器的寄存器都包括:中断使能寄存器、中断原始状态寄存器、中断状态寄存器、中断触发极性寄存器、中断触发类型寄存器以及中断类型寄存器。
中断时能寄存器 :禁止或者允许外设的独立中断连接到相应的控制器;
0——禁止,1——使能中断。
中断原始状态寄存器:
读:0,中断源没有产生中断
1,中断源产生了中断
写:0,无任何操作
1,清除边沿触发的中断标志
中断状态寄存器 :反应处于pending状态的中断,0——没有pending,1——处于pending状态
中断触发极性寄存器:中断触发极性选择,0——低电平或者下降沿触发,1——高电平或者上升沿触发
中断类型触发寄存器:中断触发类型选择,0——电平触发,1——边沿触发
中断类型寄存器 :中断类型选择,0——IRQ中断,1——FIQ中断。
这些寄存器在移植代码中分别被表示为:
#define INTC_MASK 0x00
#define INTC_RAW_STAT 0x04
#define INTC_STAT 0x08
#define INTC_POLAR 0x0C
#define INTC_ACT_TYPE 0x10
#define INTC_TYPE 0x14
另外,系统对每个中断控制器的中断源都分配了编号,其中MICR的占用0~31号,SIC1的中断源占用32~63号,SIC2的中断源占用64~95号,所以分别为SIC1和SIC2定义了32以及64的偏移量。
#define INTC_SIC1_OFFS 32
#define INTC_SIC2_OFFS 64
Table 47.Interrupt controller registry summaryAddressRegister nameDescription Reset valueType
主中断控制器相关寄存器
0x4000 8000 MIC_ER Enable Register for the Main Interrupt Controller 0 R/W
0x4000 8004 MIC_RSR Raw Status Register for the Main Interrupt Controller x R/W
0x4000 8008 MIC_SR Status Register for the Main Interrupt Controller 0 RO
0x4000 800C MIC_APR Activation Polarity select Register for the Main Interrupt Controller 0 R/W
0x4000 8010 MIC_ATR Activation Type select Register for the Main Interrupt Controller 0 R/W
0x4000 8014 MIC_ITR Interrupt Type select Register for the Main Interrupt Controller 0 R/W
子中断控制器1相关寄存器
0x4000 C000 SIC1_ER Enable register for Sub Interrupt Controller 1 0 R/W
0x4000 C004 SIC1_RSR Raw Status Register for Sub Interrupt Controller 1 - R/W
0x4000 C008 SIC1_SR Status Register for Sub Interrupt Controller 1 0 RO
0x4000 C00C SIC1_APR Activation Polarity select Register for Sub Interrupt Controller 1 0 R/W
0x4000 C010 SIC1_ATR Activation Type select Register for Sub Interrupt Controller 1 0 R/W
0x4000 C014 SIC1_ITR Interrupt Type select Register for Sub Interrupt Controller 1 0 R/W
子中断控制器2相关寄存器
0x4001 0000 SIC2_ER Enable register for Sub Interrupt Controller 2 0 R/W
0x4001 0004 SIC2_RSR Raw Status Register for Sub Interrupt Controller 2 x R/W
0x4001 0008 SIC2_SR Status Register for Sub Interrupt Controller 2 0 RO
0x4001 000C SIC2_APR Activation Polarity select Register for Sub Interrupt Controller 2 0 R/W
0x4001 0010 SIC2_ATR Activation Type select Register for Sub Interrupt Controller 2 0 R/W
0x4001 0014 SIC2_ITR Interrupt Type select Register for Sub Interrupt Controller 2 0 R/W
头文件irqs.h
#define IRQ_GPIO_00(INTC_SIC2_OFFS + 0)
表示IRQ_GPIO_00在系统中的中断号为64。
LPC3250 irq底层API
详见./arch/arm/mach-lpc32xx/irq-lpc32xx.c文件,其中提供了如下API:
static void lpc32xx_mask_irq(unsigned int irq)
static void lpc32xx_unmask_irq(unsigned int irq)
static void lpc32xx_mask_ack_irq(unsigned int irq)
static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
但是,这些API并不开放给用户使用,而是通过注册irq,为用户提供更高层的API:
static struct irq_chip lpc32xx_irq_chip = {
.ack = lpc32xx_mask_ack_irq,
.mask = lpc32xx_mask_irq,
.unmask = lpc32xx_unmask_irq,
.set_type = lpc32xx_set_irq_type, //设置中断触发类型
};
最终用户使用的设置中断触发类型的API是set_irq_type()函数。
LPC3250的中断类型完整包括:低电平触发、高电平触发,下降沿触发和上升沿触发。Linux系统中,中断触发类型定义在:./include/linux/irq.h文件中:
32 /*
33 * IRQ line status.
34 *
35 * Bits 0-7 are reserved for the IRQF_* bits in linux/interrupt.h
36 *
37 * IRQ types
38 */
39 #define IRQ_TYPE_NONE 0x00000000 /* Default, unspecified type */
40 #define IRQ_TYPE_EDGE_RISING 0x00000001 /* Edge rising type */
41 #define IRQ_TYPE_EDGE_FALLING 0x00000002 /* Edge falling type */
42 #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
43 #define IRQ_TYPE_LEVEL_HIGH 0x00000004 /* Level high type */
44 #define IRQ_TYPE_LEVEL_LOW 0x00000008 /* Level low type */
45 #define IRQ_TYPE_SENSE_MASK 0x0000000f /* Mask of the above */
46 #define IRQ_TYPE_PROBE 0x00000010 /* Probing in progress */
系统已经为各路中断设置了默认值:
/* Set default mappings */
lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, INTC_SIC1_OFFS);
lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, INTC_SIC2_OFFS);
各中断寄存器的默认值如下:
36 /*
37 * Default value represeting the Activation polarity of all internal
38 * interrupt sources
39 */
40 #define MIC_APR_DEFAULT 0x3FF0EFF8
41 #define SIC1_APR_DEFAULT 0xFBD27186
42 #define SIC2_APR_DEFAULT 0x801810C0
43
44 /*
45 * Default value represeting the Activation Type of all internal
46 * interrupt sources. All are level senesitive.
47 */
48 #define MIC_ATR_DEFAULT 0x00000000
49 #define SIC1_ATR_DEFAULT 0x00026000
50 #define SIC2_ATR_DEFAULT 0x00000000
51
在使用中断之前首先检查是否为所需要的中断类型,如果不是,可以直接修改默认值,或者调用系统提供的API进行重新设定。
中断初始化入口
board-smartarm3250.c的机型描述:
MACHINE_START (LPC3XXX, "SmartARM3250 board with the LPC3250 Microcontroller")
/* Maintainer: Kevin Wells, NXP Semiconductors */
.phys_io= UART5_BASE,
.io_pg_offst= ((io_p2v (UART5_BASE))>>18) & 0xfffc,
.boot_params= 0x80000100,
.map_io= lpc32xx_map_io,
.init_irq= lpc32xx_init_irq, //中断初始化入口
.timer= &lpc32xx_timer,
.init_machine= smartarm3250_board_init,
MACHINE_END
lpc32xx_init_irq
lpc32xx_init_irq在irq-lpc32xx.c中实现。
void __init lpc32xx_init_irq(void)
{
unsigned int i, vloc;
/* Setup MIC */
vloc = io_p2v(MIC_BASE);
__raw_writel(0, (vloc + INTC_MASK));
__raw_writel(MIC_APR_DEFAULT, (vloc + INTC_POLAR));
__raw_writel(MIC_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
/* Setup SIC1 */
vloc = io_p2v(SIC1_BASE);
__raw_writel(0, (vloc + INTC_MASK));
__raw_writel(SIC1_APR_DEFAULT, (vloc + INTC_POLAR));
__raw_writel(SIC1_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
/* Setup SIC2 */
vloc = io_p2v(SIC2_BASE);
__raw_writel(0, (vloc + INTC_MASK));
__raw_writel(SIC2_APR_DEFAULT, (vloc + INTC_POLAR));
__raw_writel(SIC2_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
/* Configure supported IRQ's */
for (i = 0; i < NR_IRQS; i++) {
set_irq_flags(i, IRQF_VALID);
set_irq_chip(i, &lpc32xx_irq_chip); //set_irq_chip
}
/* Set default mappings */
lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, INTC_SIC1_OFFS);
lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, INTC_SIC2_OFFS);
/* mask all interrupts except SUBIRQA and SUBFIQ */
__raw_writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) |
(1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ),
(io_p2v(MIC_BASE) + INTC_MASK));
__raw_writel(0, (io_p2v(SIC1_BASE) + INTC_MASK));
__raw_writel(0, (io_p2v(SIC2_BASE) + INTC_MASK));
}
lpc32xx_irq_chip
在lpc32xx_init_irq中调用set_irq_chip,其中一个参数是lpc32xx_irq_chip,在其中实现了mask、unmask、set_type等方法。
static struct irq_chip lpc32xx_irq_chip = {
.ack = lpc32xx_mask_ack_irq,
.mask = lpc32xx_mask_irq,
.unmask = lpc32xx_unmask_irq,
.set_type = lpc32xx_set_irq_type,
};
LPC3250中断处理程序
中断处理完毕,需要清除对应中断的中断标志,然后才能返回。
键盘中断范例:
/* Clear IRQ */
__raw_writel(1, KS_IRQ(kscandat->kscan_base))
对于没有特别中断控制器的中断源,因为没有中断寄存器,则需要直接清除对应MIC或者SIC的对应位,如GPIO作为中断输入,则中断服务程序需要清除SIC的对应位。
现有的范例
./arch/arm/mach-lpc32xx/arch-lpc32xx.c
./drivers/input/keyboard/lpc32xx_keys.c
arch-lpc32xx.c中的代码段:
303 #if defined(CONFIG_KEYBOARD_LPC32XX)
304 static struct resource kscan_resources[] = {
305 [0] = {
306 .start = KSCAN_BASE,
307 .end = KSCAN_BASE + SZ_4K - 1,
308 .flags = IORESOURCE_MEM,
309 },
310 [1] = {
311 .start = IRQ_KEY,
312 .end = IRQ_KEY,
313 .flags = IORESOURCE_IRQ,
314 },
315
316 };
317 static struct platform_device kscan_device = {
318 .name = "lpc32xx_keys",
319 .id = 0,
320 .dev = {
321 .platform_data = &lpc32xx_kscancfg,
322 },
323 .num_resources = ARRAY_SIZE(kscan_resources),
324 .resource = kscan_resources,
325 };
326 #endif
lpc32xx_kscancfg:
90 struct lpc32XX_kscan_cfg lpc32xx_kscancfg = {
91 .matrix_sz = KMATRIX_SIZE,
92 .keymap = lpc32xx_keymaps,
93 /* About a 30Hz scan rate based on a 32KHz clock */
94 .deb_clks = 3,
95 .scan_delay = 34,
96 };