参考书籍:《ARM嵌入式系统开发---软件设计与优化》、《一步步写嵌入式操作系统--ARM编程的方法与实践》
嵌套中断考虑了当前调用中断处理执行过程中又发送中断的情形。使用类似函数递归调用的栈帧概念来将上下文压入堆栈。
具体参考《ARM嵌入式系统开发》第九章9.3.2部分和《一步步》的第五章5.4部分,前者比较通用完整。描速的都是在IRQ模式下不能简单打开中断,而是转换到SVC模式下保存上下文。
下面核心源代码是摘抄于《ARM嵌入式系统开发》的配套源码:
;/*
; * ____________________________________________________________________
; *
; * Copyright (c) 2004, Andrew N. Sloss, Chris Wright and Dominic Symes
; * All rights reserved.
; * ____________________________________________________________________
; *
; * NON-COMMERCIAL USE License
; *
; * Redistribution and use in source and binary forms, with or without
; * modification, are permitted provided that the following conditions
; * are met:
; *
; * 1. For NON-COMMERCIAL USE only.
; *
; * 2. Redistributions of source code must retain the above copyright
; * notice, this list of conditions and the following disclaimer.
; *
; * 3. Redistributions in binary form must reproduce the above
; * copyright notice, this list of conditions and the following
; * disclaimer in the documentation and/or other materials provided
; * with the distribution.
; *
; * 4. All advertising materials mentioning features or use of this
; * software must display the following acknowledgement:
; *
; * This product includes software developed by Andrew N. Sloss,
; * Chris Wright and Dominic Symes.
; *
; * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY
; * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
; * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE
; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
; * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
; * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
; * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
; * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
; * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
; * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
; * OF SUCH DAMAGE.
; *
; * If you have questions about this license or would like a different
; * license please email :
; *
; * [email protected]
; *
; *
; */
;/***********************************************************************
; *
; * Module : nih9_9.s
; * Descriptions : Nested Interrupt Handler
; * Example : 9.9
; * OS : generic
; * Platform : generic
; * History :
; *
; * 31th December 2003
; * - added header
; *
; ***********************************************************************/
EXPORT nestedInterruptHandler
Maskmd EQU 0x1f ; processor mode mask
SVC32md EQU 0x13 ; SVC mode
I_Bit EQU 0x80 ; IRQ bit
FRAME_R0 EQU 0x00
FRAME_R1 EQU FRAME_R0+4
FRAME_R2 EQU FRAME_R1+4
FRAME_R3 EQU FRAME_R2+4
FRAME_R4 EQU FRAME_R3+4
FRAME_R5 EQU FRAME_R4+4
FRAME_R6 EQU FRAME_R5+4
FRAME_R7 EQU FRAME_R6+4
FRAME_R8 EQU FRAME_R7+4
FRAME_R9 EQU FRAME_R8+4
FRAME_R10 EQU FRAME_R9+4
FRAME_R11 EQU FRAME_R10+4
FRAME_R12 EQU FRAME_R11+4
FRAME_PSR EQU FRAME_R12+4
FRAME_LR EQU FRAME_PSR+4
FRAME_PC EQU FRAME_LR+4
FRAME_SIZE EQU FRAME_PC+4
AREA nih9_9,CODE,readonly
nestedInterruptHandler ; instruction state : comment
SUB r14,r14,#4 ; 2 :
STMDB r13!,{r0-r3,r12,r14} ; 2 : save context
;
BL read_RescheduleFlag ; 3 : more processing
CMP r0,#0 ; 3 : if processing?
LDMNEIA r13!,{r0-r3,r12,pc}^ ; 4 : then return
MRS r2,SPSR ; 5 : copy SPSR_irq
MOV r0,r13 ; 5 : copy r13_irq
ADD r13,r13,#6*4 ; 5 : reset stack
MRS r1,CPSR ; 6 : copy CPSR
BIC r1,r1,#Maskmd ; 6 :
ORR r1,r1,#SVC32md ; 6 :
MSR CPSR_c,r1 ; 6 : change SVC mode
SUB r13,r13,#FRAME_SIZE-FRAME_R4 ; 7 : make stack space
STMIA r13,{r4-r11} ; 7 : save r4-r11
LDMIA r0,{r4-r9} ; 7 : r4-r9 IRQ stack
BIC r1,r1,#I_Bit ; 8 :
MSR CPSR_c,r1 ; 8 : enable int
STMDB r13!,{r4-r7} ; 9 : save r4-r7 SVC
STR r2,[r13,#FRAME_PSR] ; 9 : save PSR
STR r8,[r13,#FRAME_R12] ; 9 : save r12
STR r9,[r13,#FRAME_PC] ; 9 : save pc
STR r14,[r13,#FRAME_LR] ; 9 : save lr
;
LDMIA r13!,{r0-r12,r14} ; 11 : restore context
MSR SPSR_cxsf,r14 ; 11 : restore SPSR
LDMIA r13!,{r14,pc}^ ; 11 : return
read_RescheduleFlag
;
MOV r0,#0 ; more processing
MOV pc,r14 ; return
END
1.忘记了r0-r12,cpsr是irq和svc共用的堆栈,r13(sp),r14(lr)和spsr是不相同的。
2.对堆栈向下生长不够深刻,刚开始还记得后来有弄反了,导致理解不了,还一度认为书上有错。
3.对ARM的堆栈操作指令和多寄存器传送指令比较生疏,需要查表对照,一步一步得走
另外我觉得书上描速的完成一个栈帧从高地址往低地址的情况好像反了,感觉应该是lr_irq,r14_svc,spsr_irq,r12-r0的顺序。
下面在mini2440板子上實現嵌套中斷:使用了LED PB8(LED4)和PB7(LED3)低電平亮,外部中斷8和19,對應按鍵是K1和K6.
.equ NOINT, 0xc0
.equ I_Bit, 0x80
.equ SVC_MOD, 0x13
.equ IRQ_MOD, 0x12
.equ WTCON, 0x53000000
.equ GPBCON, 0x56000010
.equ GPBDAT, 0x56000014
.equ GPBUP, 0x56000018
.equ GPGCON, 0x56000060
.equ EINTMASK, 0x560000a4
.equ EXTINT1, 0x5600008c
.equ EXTINT2, 0x56000090
.equ EINTPEND, 0x560000a8
.equ INTMSK, 0x4A000008
.equ SRCPND, 0X4A000000
.equ INTPND, 0X4A000010
.equ SVC_Stack, 4096
.equ IRQ_Stack, 2048
@栈帧定义
.equ FRAME_R0, 0x00
.equ FRAME_R1, FRAME_R0+4
.equ FRAME_R2, FRAME_R1+4
.equ FRAME_R3, FRAME_R2+4
.equ FRAME_R4, FRAME_R3+4
.equ FRAME_R5, FRAME_R4+4
.equ FRAME_R6, FRAME_R5+4
.equ FRAME_R7, FRAME_R6+4
.equ FRAME_R8, FRAME_R7+4
.equ FRAME_R9, FRAME_R8+4
.equ FRAME_R10, FRAME_R9+4
.equ FRAME_R11, FRAME_R10+4
.equ FRAME_R12, FRAME_R11+4
.equ FRAME_PSR, FRAME_R12+4
.equ FRAME_LR, FRAME_PSR+4
.equ FRAME_PC, FRAME_LR+4
.equ FRAME_SIZE, FRAME_PC+4
.text
.code 32
.global _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
.balignl 16,0xdeadbeef
reset:
ldr r0,=WTCON
mov r1,#0x0
str r1,[r0] @关看门狗
msr cpsr_c,#(IRQ_MOD|NOINT)
ldr sp,=IRQ_Stack
msr cpsr_c,#(SVC_MOD|NOINT)
ldr sp,=SVC_Stack
ldr r0,=GPBCON
ldr r1,=0x14000
str r1,[r0] @PB8,7输出
ldr r0,=GPBDAT
mov r1,#0x180
str r1,[r0] @8、7高电平
ldr r0,=GPGCON
ldr r1,=0x800002
str r1,[r0] @使能外部中断8,外部中断19
ldr r0,=EXTINT1
mov r1,#0x03
str r1,[r0] @外部8下降沿触发
ldr r0,=EXTINT2
ldr r1,=0x3000
str r1,[r0] @外部19下降沿触发
ldr r0, =EINTPEND
ldr r1,=0x00fffff0
str r1,[r0]@ 清EINTPEND,写1清零
ldr r0,=EINTMASK
ldr r1,=0xfff7feff
str r1,[r0] @使能外部中断8、19,0为使能
ldr r0, =SRCPND
ldr r1,=0xffffffff
str r1,[r0]@ 清SRCPND,写1清零
ldr r0, =INTPND
ldr r1,=0xffffffff
str r1,[r0]@ 清INTPND,写1清零
ldr r0,=INTMSK
ldr r1,=0xffffffdf
str r1,[r0] @使能外部中断EINT8-23
mrs r1, cpsr
bic r1, r1, #I_Bit
msr cpsr_c, r1 @开全局IRQ中断
loop: b loop
irq_server1:
stmfd sp!,{lr}
ldr r0,=GPBDAT
ldr r1,[r0]
bic r2,r1,#0x100
str r2,[r0]
bl delay1
orr r2,r1,#0x100
str r2,[r0]
@bl delay1
ldmfd sp!,{lr}
mov pc,lr
irq_server2:
stmfd sp!,{lr}
ldr r0,=GPBDAT
ldr r1,[r0]
bic r2,r1,#0x80
str r2,[r0]
bl delay2
orr r2,r1,#0x80
str r2,[r0]
@bl delay2
ldmfd sp!,{lr}
mov pc,lr
delay1:
ldr r12,=0x5ffffff
delay1loop:
sub r12,r12,#1
cmp r12,#0x0
bne delay1loop
mov pc,lr
delay2:
ldr r3,=0x5ffffff
delay2loop:
sub r3,r3,#1
cmp r3,#0x0
bne delay2loop
mov pc,lr
undefined_instruction:
nop
software_interrupt:
nop
prefetch_abort:
nop
data_abort:
nop
not_used:
nop
irq:
sub r14,r14,#4
stmdb r13!,{r0-r3,r12,r14} @ save context
ldr r0, =EINTPEND
ldr r10,[r0]
ldr r11,=0x80100
tst r10,r11 @判断是否为EINT8、19,r10记录哪个外部中断
ldr r0, =EINTPEND
ldr r1,[r0] @ldr r1,=0x100
str r1,[r0] @清EINTPEND
ldr r0, =SRCPND
ldr r1,[r0] @ldr r1,=0x20
str r1,[r0] @清SRCPND
ldr r0, =INTPND
ldr r1,[r0] @ldr r1,=0x20
str r1,[r0] @清INTPND
ldmeqfd r13!,{r0-r3,r12,pc}^
mrs r2,SPSR @ copy SPSR_irq
mov r0,r13 @ copy r13_irq
add r13,r13,#6*4 @ reset stack
msr cpsr_c,#(SVC_MOD|NOINT) @ change SVC mode
sub r13,r13,#FRAME_SIZE-FRAME_R4 @ make stack space
stmia r13,{r4-r11} @ save r4-r11
ldmia r0,{r4-r9} @ r4-r9 IRQ stack
mrs r1, cpsr
bic r1, r1, #I_Bit
msr cpsr_c, r1 @开全局IRQ中断
stmdb r13!,{r4-r7} @ save r4-r7 SVC
str r2,[r13,#FRAME_PSR] @ save PSR
str r8,[r13,#FRAME_R12] @ save r12
str r9,[r13,#FRAME_PC] @ save pc
str r14,[r13,#FRAME_LR] @ save lr
ldr r11,=0x80000
cmp r10,r11
bleq irq_server1
blne irq_server2
ldmia r13!,{r0-r12,r14} @ restore context
msr SPSR_cxsf,r14 @ restore SPSR
ldmia r13!,{r14,pc}^ @ return
fiq:
nop