天天看点

mini2440之中断控制器1.中断的处理过程2.中断控制寄存器3. 使用外部中断控制LED

可以说中断是计算机的灵魂,学习中断、使用中断十分的重要。

1.中断的处理过程

mini2440之中断控制器1.中断的处理过程2.中断控制寄存器3. 使用外部中断控制LED

图一          从图中可以看出有两条路径可以进入中断,当多个中断公用一个入口时需要走第一条路径,在子中断源登记寄存器(SUBSRCPND)登记中断(把相应的位置1),子中断源屏蔽寄存器(SUBMASK)如果置相应位1则屏蔽中断,若置0则能够进入源中断登记寄存器(SRCPND)。一个中断一个入口时走第二条路径。产生中断时要在源中断登记(SRCPND)寄存器把相应位置1,中断屏蔽寄存器(INTMASK)决定中断是否交给仲裁器处理,中断模式寄存器决定产生的中断是IRQ还是FIQ的,如果是RIQ需要交给优先级控制寄存器(PRIORITY)最高优先级的才能在中断登记寄存器(INTPND)登记,处理器响应中断。

2.中断控制寄存器

2.1 中断源登记寄存器(SRCPND)

该寄存器32位每一位对应一个中断源,产生中断时在该寄存器置相应位为1,不论中断是否被屏蔽该位都会被置位,写1清除。

2.2 中断屏蔽寄存器(INTMSK)

该寄存器32位每一位对应一个中断源,置1表示屏蔽,置0表示允许。

2.3 中断模式寄存器(INTMOD)

该寄存器32位每一位对应一个中断源,置1表示FIQ,置0表示IRQ。仅有一个中断源能够在FIR模式下服务。

2.4 中断优先级

2.4.1 仲裁器

mini2440之中断控制器1.中断的处理过程2.中断控制寄存器3. 使用外部中断控制LED

图二

2.4.2 优先级控制器(PRIORITY)

该寄存器32位,[20:7]控制七个优先级仲裁器每两位控制一个仲裁器,[6:0]控制七个仲裁器的模式每一位控制一个仲裁器。

mini2440之中断控制器1.中断的处理过程2.中断控制寄存器3. 使用外部中断控制LED

图三

2.5 中断源登记寄存器(INTPND)

该寄存器32位,每一位对应一个中断源,只能有一位被置1,通过写1清除。

2.6 中断偏移寄存器(INTOFFSET)

该寄存器的值为当前正在服务的中断源的编号。

3. 使用外部中断控制LED

3.1 启动处理器

.text
.global _start
_start:
	b	reset
undef:
	b	undef
swi:
	b	swi
pref:
	b	pref
data:
	b	data
nouser:
	b	nouser

	b	irq
fiq:
	b	fiq

reset:
	ldr	sp,		=4*1024
	bl	close_dog

	msr	cpsr_c, #0xd2 		@进入中断模式
	ldr sp,		=3*1024   	@中断模式下的堆栈

	msr cpsr_c, #0xd3 		@进入管理模式
	ldr sp, 	=4*1024   	@设置管理模式下的堆栈

	bl	init_gpio			@初始化led
	bl  init_irq			@设置中断

	msr	cpsr_c,	#0x53		@打开IRQ

	ldr	lr,	=main_return
	ldr pc,	=main

main_return:
	bl	main_return

irq:
	sub	lr,	lr,	#0x4
	stmdb	sp!,	{r0-r12,lr}		@保护现场,满递减堆栈
	ldr		lr,		=ll				@设置返回地址
	ldr		pc,		=irq_interrupt	@调用中断服务程序
ll:
	ldmia	sp!,	{r0-r12,pc}^	@恢复现场


           

3.2 连接脚本

SECTIONS {
    . = 0x00000000;  
    .text  :  { *(.text) }  
    .data  : ALIGN(4) {*(.data)}  
    .bss   : ALIGN(4) {*(.data)}
} 
           

3.3 Makefile

path=./src/

all: Inte
Inte: start.o main.o
	arm-linux-ld -Tinte.lds $(path)start.o $(path)main.o -o $(path)Inte
	arm-linux-objcopy -O binary $(path)Inte $(path)inte.bin 

start.o: $(path)start.S $(path)main.o
	arm-linux-gcc -c $(path)start.S -o $(path)start.o

main.o: $(path)main.c
	arm-linux-gcc -c $(path)main.c -o $(path)main.o
	
clean:
	rm -f $(path)*.o $(path)Inte $(path)inte.bin
	
           

3.4 C函数

/*
 * mian.cpp
 *
 *  Created on: 2016年12月31日
 *      Author: chy
 */

//led
#define GPBCON  (*(volatile unsigned long *)0x56000010)
#define GPBDAT  (*(volatile unsigned long *)0x56000014)

//key
#define GPGCON  (*(volatile unsigned long *)0x56000060)
#define GPGDAT  (*(volatile unsigned long *)0x56000064)

//interrupt
#define EXTINT1 (*(volatile unsigned long *) 0x5600008c)
#define EINTMASK (*(volatile unsigned long *)0x560000a4)
#define EINTPEND (*(volatile unsigned long *)0x560000a8)
#define INTMSK (*(volatile unsigned long *) 0X4A000008)
#define INTOFFSET (*(volatile unsigned long *)0x4A000014)
#define SRCPND (*(volatile unsigned long *) 0X4A000000)
#define INTPND (*(volatile unsigned long *) 0X4A000010)
volatile char f[3] = {0,0,0};

//看门狗
#define WTCON (*(volatile unsigned long *) 0x53000000)

void close_dog()
{
	WTCON = 0x0;
}

void init_gpio()
{
	//LED
	GPBCON &= (~(0x3 << 10 | 0x3 << 12 | 0x3 << 14));
	GPBCON |= (0x1 << 10 | 0x1 << 12 | 0x1 << 14);
	GPBDAT |=  (0x1 << 5 | 0x1 << 6 | 0x1 << 7);

	//KEY
	GPGCON &= (~(0x3 << 0 | 0x3 << 6 | 0x3 << 10));
	GPGCON |= (0x2 << 0 | 0x2 << 6 | 0x2 << 10);
}

void init_irq()
{
	EXTINT1 |= (0x2 << 0 | 0x2 << 12| 0x2 << 20); //下降沿触发
	EINTMASK &= (~((0x1 << 8) | (0x1 << 11) | (0x1 << 13))); //开外部中断
	INTMSK &= (~(0x1 << 5)); //开中断
}

void irq_interrupt()
{
	unsigned int inte_no =  INTOFFSET; //获取正在执行的中断编号
	unsigned int einte_no = EINTPEND; //获取正在执行的外部中断
			if(einte_no & (0x1 <<8)){
				if(f[0])
					GPBDAT |=  (0x1 << 5);
				else
					GPBDAT &=  ~(0x1 << 5);

				f[0] = !f[0];
			}
			if(einte_no & 0x1 << 11){
				if(f[1])
					GPBDAT |=  (0x1 << 6);
				else
					GPBDAT &=  ~(0x1 << 6);
				f[1] = !f[1];
			}
			if(einte_no & 0x1 << 13){
				if(f[2])
					GPBDAT |=  (0x1 << 7);
				else
					GPBDAT &=  ~(0x1 << 7);
				f[2] = !f[2];
			}


    EINTPEND = (1<<8) | (1<<11) | (1<<13);
	SRCPND |= 0x1 << inte_no; //写1清除标志位
	INTPND |= 0x1 << inte_no; //写1清除标志位
}

int main()
{
	while(1);
	return 0;
}
           

继续阅读