转自:http://user.qzone.qq.com/39458645/infocenter#!app=2&via=QZ.HashRefresh&pos=1331913255
一、 关于外部中断的一些基础知识
1、S3C6410共有127个外部中断,其外接I/O引脚及分组如下:
外部中断组0 EINT0 GPN0---GPN15 GPL8---GPL14 GPM0---GPM4
外部中断组1 EINT1 GPA0---GPA7 GPB0---GPB6
外部中断组2 EINT2 GPC0---GPC7
外部中断组3 EINT3 GPD0---GPD5
外部中断组4 EINT4 GPF0---GPF14
外部中断组5 EINT5 GPG0---GPG7
外部中断组6 EINT6 GPH0---GPH9
外部中断组7 EINT7 GPO0---GPO15
外部中断组8 EINT8 GPP0---GPP14
外部中断组9 EINT9 GPQ0---GPQ9
以上127个引脚每个引脚都可以产生一个外部中断
2、127个外部中断在VIC里的中断号
NO. 中断源 说明 GROUP
0 INT_EINT0 外部中断组0引脚号0-3 VIC0
1 INT_EINT1 外部中断组0引脚号4-11 VIC0
32 INT_EINT2 外部中断组0引脚号12-19 VIC1
33 INT_EINT3 外部中断组0引脚号20-27 VIC1
53 INT_EINT4 外部中断组1-9 VIC1
以上属于外部中断组0的27个中断占用了VIC里的4个中断号,外部中断组1-9只占用了1个中断号
二、 外部中断响应流程
外部中断从外设到CPU的具体流程如下:
外设àGPIOàVICàARM1117
那么我们编写关于中断的程序流程也应该是这个过程:
配置外设à配置GPIOà配置VICà配置ARM协处理器等
三、 配置过程
1、配置GPIO
GPxCON:配置相应的I/O口为中断模式
EINTxCONx
外部中断屏蔽EINTxMASK: 屏蔽某个外部中断,0=发生中断 1=不发生中断 默认是全屏蔽的。
外部中断悬挂寄存器EINTxPEND: 中断标志位
过滤控制寄存器EINTxFLTCONx: 设置滤波方式, 延迟滤波或数字滤波
2、VIC配置
A、在协处理器中开启VIC,在协处理器里设置VE位。
B、关中断,清矢量地址寄存器并配置中断类型
VICxINTENCLEAR 写1 DISABLE
VICxINTSELECT 0=IRQ 1=FIQ
VICxADDRESS 矢量地址寄存器清零
C、配置中断函数入口地址
VICxVECTADDR[x]
D、使能中断
VICxINTENABLE 1=ENABLE写0无效,DISABLE只能通过VICxINTENCLEAR写1更改
E、总中断使能 CPSR Bit 8位I置1 ENABLE
完整的代码如下,其于RVDS2.2环境,AXD调试
startup.s
-----------------------------------------------------------------------------------------------------------------------
INCLUDE s3c6410.inc
;----------------------------------------------------------------
IMPORT main ;C Entry Point for Steppingstone Loader
;----------------------------------------------------------------
EXPORT ENTRY
AREA Init,CODE,READONLY
;----------------------------------------------------------------
ENTRY
b ResetHandler
b .
b .
b .
b .
b .
b .
ResetHandler
;----------------------------------------
; Disable WatchDog Timer
;----------------------------------------
ldr r0,=WTCON
ldr r1,=0x00
str r1,[r0]
;----------------------------------------
; Enable VIC
;----------------------------------------
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1<<24) ;Enable VE bit
mcr p15,0,r0,c1,c0,0
;SetBit C1 Register VE位(BIT24)则中断向量地址由VIC决定
;ClrBit C1 Register VE位(BIT24)则中断向量地址是固定地址
; 总中断ENABLE
mrs r0,cpsr
bic r0,r0,#0x80
msr cpsr_c,r0
;DEBUG
mrs r0,cpsr
b main
END -----------------------------------------------------------------------------------------------------------------------
main.c
void main(void)
{
Led_Init();
INTC_Init();
Key_IO_Init();
Key_Int_Config();
while(1);
}
-----------------------------------------------------------------------------------------------------------------------
led.c
#include "s3c6410_addr.h"
void Led_Init(void)
{
// GPK4 5 6 7 接LED,I/O设置为输出
rGPKCON0 = (rGPKCON0 & (~(0xFFFF << 16))) | (0x1111 << 16);
// GPK4 5 6 7 设置为上拉
rGPKPUD = (rGPKPUD & (~(0xFF << 8))) | (0xAA << 8);
// 初始化时LED OFF
rGPKDAT |= 0x00F0;
}
#include "s3c6410_addr.h"
#include "interrupt.h"
void Key_ISR(void) __irq;
void Key_IO_Init(void)
{
// GPN0 1 2 3 接按键K1 K2 K3 K4 配置按键为中断E_INT
rGPNCON = rGPNCON & 0xFFFFFFAA;
rGPNDAT = rGPNDAT | 0x000F;
}
// KEY Interrupt configuration
void Key_Int_Config(void)
{
// Configurate the Key I/O for Interrupt Mode 0x10
rGPNCON = rGPNCON & 0xFFFFFF00 | 0x00AA;
// Configurate the EINT0 EINT1 EINT2 EINT3 Trigger of Flowing Type 01x
rEINT0CON0 = (rEINT0CON0 & 0xFFFFFF22);
// Disable Interrupt MASK EINT0 ENIT1 EINT2 EINT3
rEINT0MASK &= 0xFFFFFFF0;
//Clear EINT Flag
rEINT0PEND |= 0x0000000F;
// Select External Interrupt Mode IRQ
rVIC0INTSELECT = 0x0;
rVIC1INTSELECT = 0x0;
// Set the Entry Address of External Interrupt Group 0 ISR
VIC0VECTADDR[0] = (unsigned int)Key_ISR;
// Enable the External Interrupt Group 0
rVIC0INTENABLE |= 0x01;
}
void Key_ISR(void) __irq
{
int temp;
// KEY 1
if(rEINT0PEND & 0x01)
{
temp = ~(rGPKDAT & (0x01 << 4));
rGPKDAT = rGPKDAT & ~(0x01 << 4) | temp;
// Clear Interrupt Pend
rEINT0PEND |= 0x01;
}
// KEY2
if(rEINT0PEND & 0x02)
{
temp = ~(rGPKDAT & (0x01 << 5));
rGPKDAT = rGPKDAT & ~(0x01 << 5) | temp;
// Clear Interrupt Pend
rEINT0PEND |= 0x02;
}
// KEY3
if(rEINT0PEND & 0x04)
{
temp = ~(rGPKDAT & (0x01 << 6));
rGPKDAT = rGPKDAT & ~(0x01 << 6) | temp;
// Clear Interrupt Pend
rEINT0PEND |= 0x04;
}
// KEY4
if(rEINT0PEND & 0x08)
{
temp = ~(rGPKDAT & (0x01 << 7));
rGPKDAT = rGPKDAT & ~(0x01 << 7) | temp;
// Clear Interrupt Pend
rEINT0PEND |= 0x08;
}
rVIC0ADDR = 0x00000000;
}
-----------------------------------------------------------------------------------------------------------------------
interrupt.c
#include "s3c6410_addr.h"
#include "interrupt.h"
void INTC_Init(void)
{
// Disable All Interrupt
rVIC0INTENCLEAR = 0xFFFFFFFF;
rVIC1INTENCLEAR = 0xFFFFFFFF;
// Clear VECT Address
rVIC0ADDR = 0x0;
rVIC1ADDR = 0x0;
}