天天看點

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;
}
           

繼續閱讀