间断源依照硬件方位分为外部间断源和内部间断源,外部间断源和内部间断源又包括子外部间断源和子内部间断源,如上图所示(画了一整天)。
1.子内部间断源的发生
以UART0接纳数据发生INT_RXD0间断为例,INT_RXD0发生后进入SUBSRCPND子间断源暂存寄存器,设置INT_RXD0对应的间断位,间断信号经过INTSUBMSK子间断屏蔽寄存器,假如INT_RXD0信号对应位没有被置位(屏蔽掉),间断信号持续向前传递,经过子内部间断源聚合器,将INT_RXD0聚组成对应的间断源信号INT_UART0,设置SRCPND间断源暂存寄存器里INT_UART0位,经过INTMSK间断屏蔽寄存器,假如INT_UART0信号没有被屏蔽掉,间断信号进入INTMOD间断形式寄存器判别是否为快速间断,假如被编程为快速间断,直接打断ARM内核,进入间断处理,假如间断信号为一般间断,进入间断优先级裁定器进入优先级裁定,假如INT_UART0信号为最高优先级或只要INT_UART0间断信号发生,则该间断信号被记录到INTPND最高优先级间断暂存寄存器,一起设置INTOFFSET的值为间断号28,最终将间断信号打断ARM内核进行间断处理。假如一起发生多个间断且INT_UART0不是最高优先级,则该间断信号不会被处理,等最高优先级信号处理完后,再次进行优先级裁定,也便是说间断信号不消失,一向保存在SRCPND里,只到被处理学校。
2.内部间断源的发生
该进程在子内部间断处理进程中现已包括,间断信号发生后直接进入SRCPND里,然后阅历上述子内部间断后期处理进程。
3.子外部间断的发生
外部间断源共有24个,其间EINT0~EINT3为外部间断源,EINT4_7,EINT8_23为复合间断源,他们包括有子外部间断源。
咱们外部硬件直接挂接到I/O Ports(详见S3C2440A硬件手册第9章)上的,咱们要想让外设硬件间断得到处理,要先从EINT0~EINT23里挑选间断信号,咱们以EINT11为例,介绍子外部间断处理进程。
一般CPU内部引出引脚都是复用的,也便是说一根CPU引脚能够有多种功用,能够设置其为输入信号线,输出信号线或间断信号线,要想让硬件发生间断,首要要对能够发生间断的引脚进行编程,设置该引脚为间断信号线。EINT11间断信号对应CPU引脚为GPG3,经过设置GPGCON[7:6] = 0b10,能够设置该引脚为间断信号线。
表3-14 GPGCON寄存器
设置了CPU管脚为间断信号线之后,还要经过设置EXTINT0寄存器来指定间断信号的触发方法:高电平触发,低电平触发,电平上升沿,下除沿,双沿触发。
图3-9电平信号触发示意图
咱们按键按下时让它发生间断,也便是从高电平变为低电平时发生(上节按键间断原理),因而咱们设置EINT11间断信号的触发方法为下降沿触发,EXTINT1[14:12] = 0b01x
表3-15 EXTINT1寄存器
设置完触发方法之后,当外设间断信号线上的电平到达触发条件时,经过外部间断发生器发生间断信号,然后将子外部间断暂存寄存器EINTPND中对应的EINT11方位1,间断信号再进入EINTMSK子外部间断屏蔽寄存器,假如EINT11间断源信号没有被屏蔽,则EINT11间断信号进入子外部间断聚合器,复组成EINT8_23间断信号,然后再阅历与前体面内部间断信号相同的处理机制。
(1)EINTPEND外部间断暂存寄存器
表3-16外部间断暂存寄存器(EINTPEND)
寄存器名 | 地址 | 是否读写 | 描绘 | 复位默认值 |
EINTPEND | 0x560000A8 | R/W | 外部间断信号暂存寄存器 0:没有间断请求信号 1:间断请求信号发生 |
0x0000000 |
EINTPEND | 位 | 描绘 | 初始值 |
EINT23 | [23] | 0 =未发生间断1 =发生间断 | 0 |
… | … | … | … |
EINT4 | [4] | 0 =未发生间断1 =发生间断 | 0 |
保存位 | [3:0] | 无 | 0000 |
(2)EINTMASK外部间断屏蔽寄存器
表3-17外部间断屏蔽寄存器(EINTMASK)
寄存器名 | 地址 | 是否读写 | 描绘 | 复位默认值 |
EINTMASK | 0x560000A4 | R/W | 外部间断信号屏蔽寄存器 0:未屏蔽,间断可用 1:屏蔽间断信号 |
0x000FFFFF |
EINTMASK | 位 | 描绘 | 初始值 |
EINT23 | [23] | 0 =未屏蔽1 =屏蔽间断 | 1 |
… | … | … | … |
EINT4 | [4] | 0 =未屏蔽1 =屏蔽间断 | 1 |
保存位 | [3:0] | 无 | 1111 |
4.外部间断源的发生
外部间断发生进程读者能够依据上面间断图自行剖析。
按键操控LED灯试验
本试验分三个版别,别离针对三种开发板:友善之臂QQ2440,友善之臂MINI2440,天嵌TQ2440。每种开发板对应工程在:“sys_irq_开发板名”目录下。下面试验内容为针对MINI2440开发板。
head.s:
首要完成装置反常向量表,处理复位反常,初始化必要硬件,间断进口处理等功用。
;体系间断试验(MINI2440)
;**********************************************************************
GPBCONEQU0x56000010
GPBDATEQU0x56000014
EXPORT SYS_IRQ
AREASYS_IRQ,CODE,READONLY
ENTRY
;**********************************************************************
;设置间断向量,除Reset和HandleIRQ外,其它反常都没有运用(假如不幸发生了,
;将导致死机)
;**********************************************************************
; 0x00:复位Reset反常
bReset
; 0x04:未定义反常(未处理)
HandleUndef
bHandleUndef
; 0x08:软件间断反常(未处理)
HandleSWI
bHandleSWI
; 0x0c:指令预取反常(未处理)
HandlePrefetchAbt
bHandlePrefetchAbt
; 0x10:数据拜访间断反常(未处理)
HandleDataAbt
bHandleDataAbt
; 0x14:未运用反常(未处理)
HandleNotUsed
bHandleNotUsed
; 0x18:一般间断反常,跳往HandleIRQ
bHandleIRQ
; 0x1c:快速间断反常(未处理)
HandleFIQ
bHandleFIQ
Reset;复位反常处理进口
;封闭看门狗
ldrr0, = 0x53000000
movr1, #0
strr1, [r0]
blinitmem
ldrsp,=0x32000000;设置管理形式栈指针
IMPORT uart_init
bluart_init; UART串口初始化
IMPORT irq_init
blirq_init;体系间断初始化
IMPORT key_init
blkey_init;按键初始化
IMPORT led_init
blled_init; LED灯初始化
msrcpsr_cxsf, #0xd2;切换到间断形式下
ldrsp,=0x31000000;设置间断形式栈指针
msrcpsr_cxsf, #0x13;回来管理形式
ldrlr,=halt_loop;设置管理形式下回来地址
IMPORT main
ldrpc,=main;跳入主函数main里碑文
;***********************************************************************
;间断处理
;***********************************************************************
HandleIRQ
sublr,lr,#4;批改回来地址
stmdbsp!,{r0-r12,lr};保存程序碑文现场
ldrlr,=int_return;设置间断处理程序回来地址
IMPORT handle_irq
ldrpc,=handle_irq;跳入间断处理程序
int_return;间断处理回来标签
ldmiasp!,{r0-r12,pc}^康复程序碑文现场,回来持续碑文
halt_loop
bhalt_loop
initmem
ldrr0, =0x48000000
ldrr1, =0x48000034
;ldrr2, =memdata
adrr2, memdata
initmemloop
ldrr3, [r2], #4
strr3, [r0], #4
teqr0, r1
bneinitmemloop
movpc,lr
memdata
DCD0x22000000;BWSCON
DCD0x00000700;BANKCON0
DCD0x00000700;BANKCON1
DCD0x00000700;BANKCON2
DCD0x00000700;BANKCON3
DCD0x00000700;BANKCON4
DCD0x00000700;BANKCON5
DCD0x00018005;BANKCON6
DCD0x00018005;BANKCON7
DCD0x008e07a3;REFRESH
DCD0x000000b1;BANKSIZE
DCD0x00000030;MRSRB6
DCD0x00000030;MRSRB7
END;代码完毕
该程序首要设置反常向量表,除了Reset反常和间断处理被处理以外,其它反常都未被处理,假如发生时,会发生死循环,Reset反常里首要完成了硬件的根本初始化,如:按键,LED灯等,设置栈指针,用于碑文C程序,最终跳入C程序的main函数。在间断处理反常处理中首要批改回来地址,保存用户碑文现场,跳入到间断处理例程中碑文。
sys_init.c:
硬件初始化文件,晒干包括LED,KEY的初始化函数。
#include “comm_fun.h”
#defineTXD0READY(1<<2)//发送数据状况OK
#defineRXD0READY(1)//接纳数据状况OK
/* UART串口初始化*/
void uart_init()
{
GPHCON |= 0xa0;//GPH2,GPH3 used as TXD0,RXD0
GPHUP= 0x0;//GPH2,GPH3内部上拉
ULCON0= 0x03;//8N1
UCON0= 0x05;//查询方法为轮询或间断;时钟挑选为PCLK
UFCON0 = 0x00;//不运用FIFO
UMCON0 = 0x00;//不运用流控
UBRDIV0 = 12;//波特率为57600,PCLK=12Mhz
}
/* UART串口单个字符打印函数*/
extern void putc(unsigned char c)
{
while( ! (UTRSTAT0 & TXD0READY) );
UTXH0 = c;
}
/* UART串口承受单个字符函数*/
extern unsigned char getc(void)
{
while( ! (UTRSTAT0 & RXD0READY) );
return URXH0;
}
/* UART串口字符串打印函数*/
extern int printk(const char* str)
{
int i = 0;
while( str[i] ){
utc( (unsigned char) str[i++] );
}
return i;
}
/*按键初始化*/
int key_init()
{
//设置K1,K2,K3,K4,K5,K6对应操控寄存器为间断形式
GPGCON = (2<<0) | (2<<6) | (2<<10) | (2<<12) | (2<<14) | (2<<22);
/*
01x falling edge triggered下降沿触发
10x Rising edge triggered上升沿触发
11x Both edge triggered双沿触发
*/
//设置K1,K2,K3,K4,K5按键间断触发方法为上升沿触发
EXTINT1 = (3<<0) | (3<<12) | (3<<20) | (3<<24) | (3<<28);
EXTINT2 = (3<<12);//设置K6按键间断触发方法为上升沿触
printk(“按键初始化OK/r/n”);
return 0;
}
/* Led1~Led4初始化*/
#define LED1(1<<5)//LED1 GPBDAT[5]
#define LED2(1<<6)//LED2 GPBDAT[6]
#define LED3(1<<7)//LED3 GPBDAT[7]
#define LED4(1<<8)//LED4 GPBDAT[8]
/*点亮对应num号led灯*/
extern int led_on(int num)
{
switch(num)
{
case 1:
GPBDAT = GPBDAT & ~LED1; break;
case 2:
GPBDAT = GPBDAT & ~LED2; break;
case 3:
GPBDAT = GPBDAT & ~LED3; break;
case 4:
GPBDAT = GPBDAT & ~LED4; break;
default:
return 0;
}
return num;
}
/*封闭num号led灯*/
extern int led_off(int num)
{
switch(num)
{
case 1:
GPBDAT = GPBDAT | LED1; break;
case 2:
GPBDAT = GPBDAT | LED2; break;
case 3:
GPBDAT = GPBDAT | LED3; break;
case 4:
GPBDAT = GPBDAT | LED4; break;
default:
return 0;
}
return num;
}
/*封闭悉数led灯*/
extern int all_led_off(void)
{
GPBDAT = GPBDAT | LED1 | LED2 | LED3 | LED4;
return 0;
}
/* led灯初始化*/
int led_init(void)
{
GPBCON = 0x15400;//设置GPB7为输出口
all_led_off();
printk(“led初始化OK/r/n”);
return 0;
}
/*间断初始化*/
void irq_init(void)
{
//翻开KEY1~KEY6的屏蔽位
INTMSK &= ~(1<<5);
EINTMASK &= ~((1<<8) | (1<<11) | (1<<13) | (1<<14) | (1<<15) | (1<<19));
printk(“间断初始化OK/r/n”);
}
该文件是相关硬件初始化程序,首要包括了看门狗驱动,按键驱动,体系间断驱动,LED驱动。
handle_irq.c:
间断处理函数,查出间断源,间断处理,铲除间断源。
#include “comm_fun.h”
#define EINT_Key_REQUEST5// Key间断源间断号(6个按键悉数运用外部子间断)
#define K1_EINT_BIT(1<<8)// K1外部子间断位
#define K2_EINT_BIT(1<<11)// K2外部子间断位
#define K3_EINT_BIT(1<<13)// K3外部子间断位
#define K4_EINT_BIT(1<<14)// K4外部子间断位
#define K5_EINT_BIT(1<<15)// K5外部子间断位
#define K6_EINT_BIT(1<<19)// K6外部子间断位
/*体系间断处理函数*/
void handle_irq()
{
unsigned long irqOffSet = INTOFFSET;//获得间断号
all_led_off();//封闭悉数Led灯
if(EINT_Key_REQUEST==irqOffSet){// Key间断发生(6个按键运用一个总间断号)
if(K1_EINT_BIT & EINTPEND){
led_on(1);//点亮Led1
printk(“Key1 pressed/r/n”);
EINTPEND &= K1_EINT_BIT;//铲除外部子间断源
}else if(K2_EINT_BIT & EINTPEND){
led_on(2);//点亮Led2
printk(“Key2 pressed/r/n”);
EINTPEND &= K2_EINT_BIT;//铲除外部子间断源
}else if(K3_EINT_BIT & EINTPEND){
led_on(3);//点亮Led3
printk(“Key3 pressed/r/n”);
EINTPEND &= K3_EINT_BIT;//铲除外部子间断源
}else if(K4_EINT_BIT & EINTPEND){
led_on(4);//点亮Led4
printk(“Key4 pressed/r/n”);
EINTPEND &= K4_EINT_BIT;//铲除外部子间断源
}else if(K5_EINT_BIT & EINTPEND){
all_led_off(1);//平息悉数Led
printk(“Key5 pressed/r/n”);
EINTPEND &= K5_EINT_BIT;//铲除外部子间断源
}else if(K6_EINT_BIT & EINTPEND){
all_led_on();//点亮悉数Led
printk(“Key6 pressed/r/n”);
EINTPEND &= K6_EINT_BIT;//铲除外部子间断源
}
}
SRCPND &= (1<
}
main.c:
包括主函数和延时函数,首要完成字符串的循环打印。
#include “register.h”
#include “comm_fun.h”
/*延时*/
void delay(int msec)
{
int i, j;
for(i = 1000; i > 0; i–)
for(j = msec*10; j > 0; j–)
/* do nothing */;
}
/*主函数*/
int main()
{
while(1)
{
printk(“main函数在运转…/r/n”);
delay(5);//delay
}
return 0;
}