分类: 嵌入式
2013-08-28 22:12:17
1:当异常发生时硬件自动处理的事情有:
(1):切换到异常处理模式,比如IRQ。
(2):把当前模式下的cpsr保存到异常模式下的spsr
(3):使用异常模式的R13和R14。
(4):把发生异常模式时的下一条指令保存lr寄存器中。
(5):跳转到异常模式处理的地址。
2:当异常发生时软件需要做的事情:
(1):保护现场,在保护现场前先执行sub lr, lr, #4,因为arm处理器在执行每条指令前先判断当前是否有异常发生,若有则去处理异常,当前指令并没有执行;而当异常发生时,硬件会自动把下一条指令保存到lr中,但是异常处理完返回时是需要去执行发生异常导致没执行的指令,所以lr必须减4;
(2):跳转中断处理入口地址执行。
(3):恢复现场
3:处理异常需要做的一些初始化:
(1):设置源头,触发方式
(2):使能中断
(3):使能总中断
(4):以ok6410开发板的按键中断为例:
1):通过看ok6410的原理图,按键key1~key4接入的GPIO管脚为GPION0~GPION3,所以首先设置GPION0~GPION3的管脚功能EXT_INT。(GPNCON)
2):GPION0~GPION3管脚接电源默认输入高电平,当有按键按下时相当于直接接地即低电平。需要设置触发方式:低电平触发,下降沿触发或是上升沿触发。(EINT0CON)
3):中断过滤功能(EINT0FLTCON0 )这里设置滤波方式,可以去毛刺。
4):使能中断(EINT0MASK ):写零使能中断,写1禁止中断。
5):检查是否发生中断(EINT0PEND ),当被设置为1时表示有bit相对应的中断发生,
写入1清除中断。
6):VIC中断向量:
7):VICXVECTADDR,设置中断处理程序的地址(6410共有64个这样的寄存器)
8):VICXADDRESS,矢量地址寄存器,写入任意数据清除中断
9):VICxINTENABLE,使能GPIO传过来的中断信号。
下面贴上源代码,在ok6410上调试通过:按键按下触发中断,key1对应led1,把led1对应的gpio管脚取反,所以看到的效果是:第一次按下led1被点亮,
第二次按下led1熄灭,第三次按下led1又点亮,第四次按下led1熄灭。总共有4个按键,keyn对应ledn。
.global _start
#define GPMCON 0x7f008820
#define GPMDAT 0x7f008824
#define GPNCON 0x7f008830
#define GPNDAT 0x7f008834
#define EINT0CON 0x7f008900
#define EINT0FLTCON0 0x7f008910
#define EINT0MASK 0x7f008920
#define EINT0PEND 0x7f008924
#define VIC0VECTADDR_0 0x71200100
#define VIC0INTENABLE 0x71200010
#define VIC0ADDRESS 0x71200F00
_start:
stmfd sp!, {r0-r12, lr}
//enable vic port
mrc p15,0,r0,c1,c0,0
orr r0,r0,#(1 << 24)
mcr p15,0,r0,c1,c0,0
@svc -> irq
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0x12
msr cpsr, r0
@set irq stack
mov sp, #0x2000
@irq -> svc
bic r0, r0, #0x1f
orr r0, r0, #0x13
msr cpsr, r0
@enable I(irq)
bic r0, r0, #(1 << 7)
msr cpsr, r0
bl gpio_led_init
bl irq_init
bl vic_init
@return
ldmfd sp!, {r0-r12, pc}
gpio_led_init:
ldr r0, =GPMCON
ldr r1, =0x1111 @output
str r1, [r0]
ldr r0, =GPMDAT
mov r1, #0xf
str r1, [r0] @all led off
mov pc, lr
irq_init:
ldr r0, =GPNCON
ldr r1, =0xaa @gpiopin for EXT_INT fun
str r1, [r0]
ldr r0, =EINT0CON
mov r1, #0x22 @falling trigger
str r1, [r0]
ldr r0, =EINT0FLTCON0
ldr r1, =0xffff @digital filter
str r1, [r0]
ldr r0, =EINT0MASK
ldr r1, [r0]
bic r1, r1, #0xf @enable irq
str r1, [r0]
mov pc, lr
vic_init:
ldr r0, =VIC0VECTADDR_0
ldr r1, =interrupt @irq_isr function
str r1, [r0]
ldr r0, =VIC0INTENABLE
ldr r1, [r0]
orr r1, r1, #0x1 @enable vic0
str r1, [r0]
ldr r0, =VIC0ADDRESS
mov r1, #0 @clean irq
str r1, [r0]
mov pc, lr
interrupt:
sub lr, lr, #4
stmfd sp!, {r0-r12, lr}
bl irq_isr
ldmfd sp!, {r0-r12, pc}^
irq_isr:
ldr r0, =GPMDAT
ldr r1, [r0]
ldr r2, =EINT0PEND @get irq source
ldr r3, [r2]
mov r4, r3
@judge which irq occur
ands r3, r3, #(1 << 0)
bne key1_occur
mov r3, r4
ands r3, r3, #(1 << 1)
bne key2_occur
mov r3, r4
ands r3, r3, #(1 << 2)
bne key3_occur
mov r3, r4
ands r3, r3, #(1 << 3)
bne key4_occur
b isr_out
@irq_isr
key1_occur:
eor r1, r1, #(1 << 0)
str r1, [r0]
b isr_out
key2_occur:
eor r1, r1, #(1 << 1)
str r1, [r0]
b isr_out
key3_occur:
eor r1, r1, #(1 << 2)
str r1, [r0]
b isr_out
key4_occur:
eor r1, r1, #(1 << 3)
str r1, [r0]
b isr_out
isr_out:
ldr r0, =EINT0PEND
ldr r1, [r0]
str r1, [r0] @clean EINT0PEND bit
ldr r0, =VIC0ADDRESS
mov r1, #0 @clean VIC0ADDRESS
str r1, [r0]
mov pc, lr