×
嵌入式 > 嵌入式开发 > 详情

GNU ARM汇编(五)中断汇编之嵌套中断处理

发布时间:2020-09-23 发布时间:
|
在上篇《GNU ARM汇编--(四)中断汇编之非嵌套中断处理》中分析了最简单的中断处理的写法,再看TQ2440启动代码中的中断向量表的写法就一目了然了.今天抽时间对嵌套中断处理的学习做下整理.

嵌套中断处理的核心代码如下:

;/*; *  ____________________________________________________________________; * ; *  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 :; * ; *  andrew@sloss.net; * ; * ; */;/*; *; *  Module       : nih9_9.s; *  Descriptions : Nested Interrupt Handler; *  Example      : 9.9; *  OS           : generic; *  Platform     : generic; *  History      :; *; *  31th December 2003; *  - added header; *; */EXPORT nestedInterruptHandlerMaskmd     EQU 0x1f                     ; processor mode maskSVC32md    EQU 0x13                     ; SVC modeI_Bit      EQU 0x80                     ; IRQ bit FRAME_R0   EQU 0x00			FRAME_R1   EQU FRAME_R0+4FRAME_R2   EQU FRAME_R1+4FRAME_R3   EQU FRAME_R2+4FRAME_R4   EQU FRAME_R3+4FRAME_R5   EQU FRAME_R4+4FRAME_R6   EQU FRAME_R5+4FRAME_R7   EQU FRAME_R6+4FRAME_R8   EQU FRAME_R7+4FRAME_R9   EQU FRAME_R8+4FRAME_R10  EQU FRAME_R9+4FRAME_R11  EQU FRAME_R10+4FRAME_R12  EQU FRAME_R11+4FRAME_PSR  EQU FRAME_R12+4FRAME_LR   EQU FRAME_PSR+4FRAME_PC   EQU FRAME_LR+4FRAME_SIZE EQU FRAME_PC+4AREA nih9_9,CODE,readonlynestedInterruptHandler ; instruction       state : comment		SUB     r14,r14,#4                 ; 2 :STMDB   r13!,{r0-r3,r12,r14}       ; 2 : save context; BL      read_RescheduleFlag        ; 3 : more processingCMP     r0,#0                      ; 3 : if processing?LDMNEIA r13!,{r0-r3,r12,pc}^       ; 4 :   then return MRS     r2,SPSR                    ; 5 : copy SPSR_irqMOV     r0,r13                     ; 5 : copy r13_irqADD     r13,r13,#6*4               ; 5 : reset stackMRS     r1,CPSR                    ; 6 : copy CPSRBIC     r1,r1,#Maskmd              ; 6 :ORR     r1,r1,#SVC32md             ; 6 :MSR     CPSR_c,r1                  ; 6 : change SVC modeSUB     r13,r13,#FRAME_SIZE-FRAME_R4 ; 7 : make stack space STMIA   r13,{r4-r11}               ; 7 : save r4-r11LDMIA   r0,{r4-r9}                 ; 7 : r4-r9 IRQ stack BIC     r1,r1,#I_Bit               ; 8 : MSR     CPSR_c,r1                  ; 8 : enable intSTMDB   r13!,{r4-r7}               ; 9 : save r4-r7 SVCSTR     r2,[r13,#FRAME_PSR]        ; 9 : save PSRSTR     r8,[r13,#FRAME_R12]        ; 9 : save r12STR     r9,[r13,#FRAME_PC]         ; 9 : save pc      STR     r14,[r13,#FRAME_LR]        ; 9 : save lr; LDMIA   r13!,{r0-r12,r14}          ; 11 : restore contextMSR     SPSR_cxsf,r14              ; 11 : restore SPSRLDMIA   r13!,{r14,pc}^             ; 11 : returnread_RescheduleFlag; MOV     r0,#0                      ; more processing MOV     pc,r14                     ; returnEND


代码的关键就是在中断后切换到SVC模式下,利用svc mode的stack来实现中断嵌套过程的备份以及恢复操作.从代码中可以看到,从R0到PC都在栈中有备份,这里我们叫栈帧.记得《深入理解计算机系统》一书在讲x86汇编的函数调用时也是栈帧的概念.这点上中断嵌套和函数调用有相似之处.有了这个栈帧,利用压栈出栈操作就一切ok了.

刚看这个代码,对有个地方有疑问,就是觉得中断开早了:

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

觉得开中断的代码应该放在后面,这样才能保证svc mode下的stack frame不会被破坏.但在草稿纸上画一下irq和svc下的stack图,就发现堆栈操作并没有问题.可以假设刚开中断立马就有新的中断了,r4-r7 r8 r9都有在STMIA r13,{r4-r11} 中保存到svc的stack中,LDMIA r0,{r4-r9} 和STMDB r13!,{r4-r7} 保证了最初的r0-r3在栈中,而LDMIA r0,{r4-r9}和STR r8,[r13,#FRAME_R12] 以及STR r9,[r13,#FRAME_PC] 保证了R12和PC,保证正确返回.(这里的r9装的是r14_irq,所以pc就是r14_irq,这样就保证了从中断服务例程中返回).至于STR r14,[r13,#FRAME_LR]中的r14是r14_svc,将其压入svc的stack中,中断例程用bl就不会出现错误了,在最后LDMIA r13!,{r14,pc}^ 中r14得到恢复.而r2保存的是spsr,也就是svc模式的状态,一直不变,不用担心会被覆盖.

最后,再看了一遍图,觉得r10和r11的帧可以省去,因为r4-r9是用来存atpcs的r0-r3,r12,r14,而r10和r11用不到.貌似可以省点空间和时间,具体的待会实验一下.

下面给出实际的嵌套中断处理,利用r10来保存INTOFFSET的值,根据该值来判定是什么中断,从而做不同的处理.具体的效果是:代码会做流水灯的动作,Key1代表INT1,中断处理动作是4个灯全全亮然后全灭,Key4代表代表INT0,中断处理动作是第一个灯和第三个灯亮,然后第二个灯和第四个灯亮.

/*simple interruptioncopyleft@dndxhej@gmail.com*/.equ	Maskmd,	0x1f                     @ processor mode mask.equ	SVC32md,     0x13                     @ SVC mode.equ	I_Bit,       0x80                     @ IRQ bit .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.equ   NOINT, 0xc0.equ	WTCON,	0x53000000.equ 	GPBCON,	0x56000010  	@led.equ	GPBDAT,	0x56000014  	@led.equ   GPBUP,        0x56000018    @led.equ 	GPFCON, 0x56000050  	@interrupt config.equ	EINTMASK, 0x560000a4.equ 	EXTINT0,  0x56000088.equ 	EXTINT1,  0x5600008c.equ 	EXTINT2,  0x56000090.equ	INTMSK,	 0x4A000008.equ   EINTPEND,     0x560000a8.equ   INTSUBMSK,    0X4A00001C.equ   SRCPND,   0X4A000000.equ   INTPND,   0X4A000010.equ	INTOFFSET,	0x4A000014.global _start_start:		b	resetldr     pc, _undefined_instructionldr 	pc, _software_interruptldr	pc, _prefetch_abortldr	pc, _data_abortldr	pc, _not_used@b	irqldr 	pc, _irqldr 	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,0xdeadbeefreset:ldr     r3, =WTCONmov	r4, #0x0                     str	r4, [r3]	@ disable watchdog    ldr	r0, =GPBCONldr	r1, =0x15400str	r1, [r0]ldr	r2, =GPBDATldr	r1, =0x160str	r1, [r2]bl delaymsr cpsr_c, #0xd2 @进入中断模式ldr sp, =0xc00 @中断模式的栈指针定义msr cpsr_c, #0xd3 @进入svc模式ldr sp, =0xfff @设置svc模式的栈指针@--------------------------------------------ldr	r0, =GPBUPldr	r1, =0x03f0  str	r1, [r0]      ldr	r0, =GPFCONldr	r1, =0x2ea@0x2    str	r1, [r0]  ldr	r0, =EXTINT0@ldr	r1, =0x8f888@0x0@0x8f888      @~(7|(7<<4)|(7<<8)|(7<<16))ldr	r1, =0xafaaastr	r1, [r0]  ldr	r0, =EINTPENDldr	r1, =0xf0@0b10000str	r1, [r0]  ldr	r0, =EINTMASKldr	r1, =0x00@0b00000str	r1, [r0]  ldr	r0, =SRCPNDldr	r1, =0xff@0x1@0b11111str	r1, [r0]  ldr	r0, =INTPNDldr	r1, =0xff@0x1@0b11111str	r1, [r0]  ldr	r0, =INTMSKldr	r1, =0xffffff00@0b00000str	r1, [r0]  MRS r1, cpsrBIC r1, r1, #0x80MSR cpsr_c, r1bl     mainirq:sub     r14,r14,#4                 @ 2 :stmdb   sp!,{r0-r3,r12,r14}       @ 2 : save context@ @BL      read_RescheduleFlag        @ 3 : more processing@CMP     r0,#0                      @ 3 : if processing?@LDMNEIA sp!,{r0-r3,r12,pc}^       @ 4 :   then return @@@@@@@@@@@@@@@@ldr r10,=INTOFFSET           @用r10保存中断的offsetldr r10,[r10]ldr r0,=EINTPENDldr r1,=0xf0str r1,[r0] ldr	r0, =SRCPNDldr	r1, =0x3f@0b11111str	r1, [r0]  ldr	r0, =INTPNDldr	r1, =0x3f@0b11111str	r1, [r0]  @@@@@@@@@@@@@@mrs     r2,SPSR                    @ 5 : copy SPSR_irqmov     r0,sp                     @ 5 : copy sp_irqadd     sp,sp,#6*4               @ 5 : reset stackmrs     r1,CPSR                    @ 6 : copy CPSRbic     r1,r1,#Maskmd              @ 6 :orr     r1,r1,#SVC32md             @ 6 :msr     CPSR_c,r1                  @ 6 : change SVC modesub     sp,sp,#FRAME_SIZE-FRAME_R4 @ 7 : make stack space stmia   sp,{r4-r11}               @ 7 : save r4-r11ldmia   r0,{r4-r9}                 @ 7 : r4-r9 IRQ stack bic     r1,r1,#I_Bit               @ 8 : msr     CPSR_c,r1                  @ 8 : enable intstmdb   sp!,{r4-r7}               @ 9 : save r4-r7 SVCstr     r2,[sp,#FRAME_PSR]        @ 9 : save PSRstr     r8,[sp,#FRAME_R12]        @ 9 : save r12str     r9,[sp,#FRAME_PC]         @ 9 : save pc      str     r14,[sp,#FRAME_LR]        @ 9 : save lr@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@cmp	r10,#0x0bleq	blink1cmp	r10,#0x1bleq	blink3@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@LDMIA   sp!,{r0-r12,r14}          @ 11 : restore contextMSR     SPSR_cxsf,r14              @ 11 : restore SPSRLDMIA   sp!,{r14,pc}^             @ 11 : returndelay:ldr r3,=0xffffdelay1:sub r3,r3,#1cmp r3,#0x0bne delay1mov pc,lrblink1:ldr	r0, =GPBDATldr	r1, =0x000str	r1, [r0]ldr r3,=0xffffdelay2:sub r3,r3,#1cmp r3,#0x0bne delay2ldr	r0, =GPBDATldr	r1, =0x1f0str	r1, [r0]ldr r3,=0xffffdelay3:sub r3,r3,#1cmp r3,#0x0bne delay3mov pc,lrblink2:ldr	r0, =GPBDATldr	r1, =0x140str	r1, [r0]ldr r3,=0xffffdelay12:sub r3,r3,#1cmp r3,#0x0bne delay12ldr	r0, =GPBDATldr	r1, =0xa0str	r1, [r0]ldr r3,=0xffffdelay13:sub r3,r3,#1cmp r3,#0x0bne delay13mov pc,lrblink3:ldr	r0, =GPBDATldr	r1, =0x0a0str	r1, [r0]stmfd	sp!,{lr}bl delayldr	r0, =GPBDATldr	r1, =0x140str	r1, [r0]bl delayldmfd	sp!,{lr}mov pc,lrmain:ledloop:ldr r1,=0x1c0str r1,[r2]bl delayldr r1,=0x1a0str r1,[r2]bl delayldr r1,=0x160str r1,[r2]bl delayldr r1,=0x0e0str r1,[r2]bl delayb ledloopundefined_instruction:nopsoftware_interrupt:nopprefetch_abort:	nopdata_abort:nopnot_used:nopfiq:nop

代码比较繁琐,有几点值得注意:在嵌套中断处理中,压栈后先保存INTOFFSET的值,再清中断(SRCPND和INTPND).因为SRCPND和INTPND清除后INTOFFSET就自动清除了,所以要先保存.在中断服务程序中,是可以用bl跳转到各自的中断服务程序的,比如blne blink1和blne blink3,值得对比的blink1和blink3,他们的不同在于blink1自己用代码做了延时,而blink3是调用bl delay做的延时,那么这个时候要注意的就是lr的push和pop操作,不然lr就被覆盖了,程序不能正确返回了.

注意了以上两点,程序上达到了嵌套处理的效果.因为采用的是下降边沿触发,而按键没有防抖处理,有时候单按一个键就有嵌套中断了.最后总结一下这种处理的优缺点:优点是在为一个中断处理服务完成前允许其它中断,以缩短中断延迟;而缺点是不处理中断的优先级,因此低优先级的中断会阻塞高优先级的中断.



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
智能化系统工程设计中的若干技术问题