ARM汇编嵌套中断处理

参考书籍:《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

将irq和svc两种模式的堆栈图画出来观看的话,理解起来比较直观。因为我是初学,刚开始没能理解其中堆栈操作,原因是:

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

可以看到中斷的嵌套,但是按下K6多次後會有問題,譬如LED4一直暗,或一直亮,再按那兩個中斷按鍵也沒反應。JLink調試發現按一次按鍵,中斷重入好幾次,大概是沒有去抖動導致,連續按久了,堆棧溢出?同時還會跑到“ldr     pc, _undefined_instruction “這一句上,跑飛了?問題的原因還有待確認!

你可能感兴趣的:(MCU)