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

发布者:sjp5035022最新更新时间:2016-05-12 来源: eefocus关键字:GNU  ARM汇编  非嵌套中断处理 手机看文章 扫描二维码
随时随地手机看文章
在写这篇blog之前,不得不感慨一句:纸上得来终觉浅,绝知此事要躬行.作为EE出身的,虽然好久好久没用汇编写单片机的中断了,但自我感觉对中断的理解还是比较深入的,本以为在GNU ARM汇编下搞个中断会很容易,谁知道断断续续花了我几周.完全用汇编写中断和用c中的_irq写中断还是有区别的,谁用谁知道.还是那句话:深入细节是必须的,也是值得的.

        这一篇blog的理论知识主要来源于:《ARM System Developer's Guide》.

        ARM的异常和相应的模式之间的对应关系见下表:


 

当一个异常导致模式的改变时,内核自动地:

1、把cpsr保存到相应模式下的spsr

2、把pc保存到相应模式下的lr

3、设置cpsr为相应异常模式

4、设置pc为相应异常处理程序的入口地址

从异常中断处理程序返回包含下面两个操作:

1、从spsr_mode中恢复内容到cpsr中

2、从lr_mode中恢复内容到pc中,返回到异常中断的指令的下一条政令处执行.

上面刚提到了异常发生时内核的一些动作,那对与IRQ或者FIQ而言,还多一项变化:禁用相关的中断IRQ或FIQ,禁止同类型的其他中断被触发.

 对于最简单的非嵌套中断处理的处理流程如下:


 

下面给出汇编代码:

 

[cpp] view plaincopyprint?
  1. /* 
  2. simple interruption 
  3. copyleft@dndxhej@gmail.com 
  4. */  
  5.   
  6. .equ   NOINT, 0xc0  
  7. .equ    WTCON,  0x53000000  
  8. .equ    GPBCON, 0x56000010      @led  
  9. .equ    GPBDAT, 0x56000014      @led  
  10. .equ   GPBUP,        0x56000018    @led  
  11. .equ    GPFCON, 0x56000050      @interrupt config  
  12. .equ    EINTMASK, 0x560000a4  
  13. .equ    EXTINT0,  0x56000088  
  14. .equ    EXTINT1,  0x5600008c  
  15. .equ    EXTINT2,  0x56000090  
  16. .equ    INTMSK,  0x4A000008  
  17. .equ   EINTPEND,     0x560000a8  
  18.   
  19. .equ   INTSUBMSK,    0X4A00001C  
  20.   
  21. .equ   SRCPND,   0X4A000000  
  22. .equ   INTPND,   0X4A000010  
  23.   
  24. .global _start  
  25. _start:     b   reset  
  26.         ldr     pc, _undefined_instruction  
  27.         ldr     pc, _software_interrupt  
  28.         ldr pc, _prefetch_abort  
  29.         ldr pc, _data_abort  
  30.         ldr pc, _not_used  
  31.         @b  irq  
  32.         ldr     pc, _irq  
  33.         ldr     pc, _fiq  
  34.   
  35.   
  36.   
  37. _undefined_instruction:     .word undefined_instruction  
  38. _software_interrupt:        .word software_interrupt  
  39. _prefetch_abort:        .word prefetch_abort  
  40. _data_abort:            .word data_abort  
  41. _not_used:          .word not_used  
  42. _irq:               .word irq  
  43. _fiq:               .word fiq  
  44.   
  45. .balignl 16,0xdeadbeef  
  46.   
  47. reset:  
  48.   
  49.   
  50.     ldr     r3, =WTCON  
  51.     mov r4, #0x0                       
  52.     str r4, [r3]    @ disable watchdog      
  53.   
  54.     ldr r0, =GPBCON  
  55.     ldr r1, =0x15400  
  56.     str r1, [r0]  
  57.   
  58.     ldr r2, =GPBDAT  
  59.     ldr r1, =0x160  
  60.     str r1, [r2]  
  61.   
  62.     bl delay  
  63.   
  64.   
  65.     msr cpsr_c, #0xd2 @进入中断模式  
  66.     ldr sp, =3072 @中断模式的栈指针定义  
  67.   
  68.     msr cpsr_c, #0xdf @进入系统模式  
  69.     ldr sp, =4096 @设置系统模式的栈指针  
  70.   
  71.   
  72.   
  73.   
  74. @--------------------------------------------  
  75.   
  76.     ldr r0, =GPBUP  
  77.     ldr r1, =0x03f0    
  78.     str r1, [r0]        
  79.      
  80.   
  81.   
  82.     ldr r0, =GPFCON  
  83.     ldr r1, =0x2ea@0x2      
  84.     str r1, [r0]    
  85.   
  86.     ldr r0, =EXTINT0  
  87.     ldr r1, =0x8f888@0x0@0x8f888      @~(7|(7<<4)|(7<<8)|(7<<16))  
  88.     str r1, [r0]    
  89.   
  90.     ldr r0, =EINTPEND  
  91.     ldr r1, =0xf0@0b10000  
  92.     str r1, [r0]    
  93.   
  94.     ldr r0, =EINTMASK  
  95.     ldr r1, =0x00@0b00000  
  96.     str r1, [r0]    
  97.   
  98.   
  99.   
  100.     ldr r0, =SRCPND  
  101.     ldr r1, =0xff@0x1@0b11111  
  102.     str r1, [r0]    
  103.   
  104.     ldr r0, =INTPND  
  105.     ldr r1, =0xff@0x1@0b11111  
  106.     str r1, [r0]    
  107.   
  108.     ldr r0, =INTMSK  
  109.     ldr r1, =0xffffff00@0b00000  
  110.     str r1, [r0]    
  111.   
  112.     MRS r1, cpsr  
  113.     BIC r1, r1, #0x80  
  114.     MSR cpsr_c, r1  
  115.   
  116.   
  117.     bl     main  
  118.   
  119. irq:  
  120.     sub     lr,lr,#4  
  121.     stmfd   sp!,{r0-r12,lr}  
  122.     bl irq_isr  
  123.     ldmfd  sp!,{r0-r12,pc}^   
  124.   
  125.   
  126.   
  127. irq_isr:  
  128.   
  129.   
  130.   
  131.     ldr r2, =GPBDAT  
  132.     ldr r1, =0x0e0  
  133.     str r1, [r2]  
  134.   
  135.   
  136.          ldr r0,=EINTPEND  
  137.          ldr r1,=0xf0  
  138.          str r1,[r0]   
  139.   
  140.     ldr r0, =SRCPND  
  141.     ldr r1, =0x3f@0b11111  
  142.     str r1, [r0]    
  143.   
  144.   
  145.   
  146.     ldr r0, =INTPND  
  147.     ldr r1, =0x3f@0b11111  
  148.     str r1, [r0]    
  149.   
  150.   
  151.   
  152.     mov pc,lr  
  153.   
  154.   
  155. delay:  
  156.       
  157.     ldr r3,=0xffff  
  158.   
  159. delay1:  
  160.     sub r3,r3,#1  
  161.   
  162.     cmp r3,#0x0  
  163.   
  164.     bne delay1  
  165.   
  166.     mov pc,lr  
  167.   
  168.   
  169.   
  170.   
  171. main:  
  172. ledloop:  
  173.   
  174.     ldr r1,=0x1c0  
  175.     str r1,[r2]  
  176.     bl delay  
  177.   
  178.     ldr r1,=0x1a0  
  179.     str r1,[r2]  
  180.     bl delay  
  181.   
  182.     ldr r1,=0x160  
  183.     str r1,[r2]  
  184.     bl delay  
  185.   
  186.     ldr r1,=0x0e0  
  187.     str r1,[r2]  
  188.     bl delay  
  189.   
  190.   
  191.     b ledloop  
  192.   
  193.   
  194.   
  195.   
  196. undefined_instruction:  
  197.             nop  
  198. software_interrupt:  
  199.             nop  
  200. prefetch_abort:   
  201.             nop  
  202. data_abort:  
  203.             nop  
  204. not_used:  
  205.             nop  
  206. fiq:  
  207.             nop  
/*
simple interruption
copyleft@dndxhej@gmail.com
*/

.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

.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
		@b	irq
		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     r3, =WTCON
	mov	r4, #0x0                     
	str	r4, [r3]	@ disable watchdog    

	ldr	r0, =GPBCON
	ldr	r1, =0x15400
	str	r1, [r0]

	ldr	r2, =GPBDAT
	ldr	r1, =0x160
	str	r1, [r2]

	bl delay


    msr cpsr_c, #0xd2 @进入中断模式
    ldr sp, =3072 @中断模式的栈指针定义

    msr cpsr_c, #0xdf @进入系统模式
    ldr sp, =4096 @设置系统模式的栈指针




@--------------------------------------------

	ldr	r0, =GPBUP
	ldr	r1, =0x03f0  
	str	r1, [r0]      
   


	ldr	r0, =GPFCON
	ldr	r1, =0x2ea@0x2    
	str	r1, [r0]  

	ldr	r0, =EXTINT0
	ldr	r1, =0x8f888@0x0@0x8f888      @~(7|(7<<4)|(7<<8)|(7<<16))
	str	r1, [r0]  

	ldr	r0, =EINTPEND
	ldr	r1, =0xf0@0b10000
	str	r1, [r0]  

	ldr	r0, =EINTMASK
	ldr	r1, =0x00@0b00000
	str	r1, [r0]  



	ldr	r0, =SRCPND
	ldr	r1, =0xff@0x1@0b11111
	str	r1, [r0]  

	ldr	r0, =INTPND
	ldr	r1, =0xff@0x1@0b11111
	str	r1, [r0]  

	ldr	r0, =INTMSK
	ldr	r1, =0xffffff00@0b00000
	str	r1, [r0]  

	MRS r1, cpsr
	BIC r1, r1, #0x80
	MSR cpsr_c, r1


	bl     main

irq:
	sub 	lr,lr,#4
	stmfd	sp!,{r0-r12,lr}
	bl irq_isr
	ldmfd  sp!,{r0-r12,pc}^ 



irq_isr:



	ldr	r2, =GPBDAT
	ldr	r1, =0x0e0
	str	r1, [r2]


         ldr r0,=EINTPEND
         ldr r1,=0xf0
         str r1,[r0] 

	ldr	r0, =SRCPND
	ldr	r1, =0x3f@0b11111
	str	r1, [r0]  



	ldr	r0, =INTPND
	ldr	r1, =0x3f@0b11111
	str	r1, [r0]  



	mov pc,lr


delay:
	
	ldr r3,=0xffff

delay1:
	sub r3,r3,#1

	cmp r3,#0x0

	bne delay1

	mov pc,lr




main:
ledloop:

	ldr r1,=0x1c0
	str r1,[r2]
	bl delay

	ldr r1,=0x1a0
	str r1,[r2]
	bl delay

	ldr r1,=0x160
	str r1,[r2]
	bl delay

	ldr r1,=0x0e0
	str r1,[r2]
	bl delay


	b ledloop




undefined_instruction:
			nop
software_interrupt:
			nop
prefetch_abort:	
			nop
data_abort:
			nop
not_used:
			nop
fiq:
			nop

lds文件:

 

 

[cpp] view plaincopyprint?
  1. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")  
  2. OUTPUT_ARCH(arm)  
  3. ENTRY(_start)  
  4.   
  5. SECTIONS{  
  6.     . = 0x00000000;  
  7.     .text : {  
  8.         *(.text)  
  9.         *(.rodata)  
  10.     }  
  11.   
  12.     .data ALIGN(4): {  
  13.         *(.data)  
  14.     }  
  15.   
  16.     .bss ALIGN(4): {  
  17.         *(.bss)  
  18.     }  
  19. }  
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)

SECTIONS{
    . = 0x00000000;
    .text : {
        *(.text)
        *(.rodata)
    }

    .data ALIGN(4): {
        *(.data)
    }

    .bss ALIGN(4): {
        *(.bss)
    }
}

makefile:

 

 

[cpp] view plaincopyprint?
  1. CROSS =  arm-linux-  
  2. CFLAGS = -nostdlib  
  3.   
  4. int.bin: start.S   
  5.     ${CROSS}gcc $(CFLAGS) -c -o start.o start.S  
  6.     ${CROSS}ld -Tint.lds start.o  -o int.elf  
  7. #   ${CROSS}ld -Ttext-segment 0x30000000 start.o  -o int.elf   
  8.     ${CROSS}objcopy -O binary -S int.elf int.bin  
  9. #   rm -f  *.o   
  10.   
  11.   
  12. clean:  
  13.     rm -f *.elf *.o  
  14.     rm -f int.bin  
CROSS =  arm-linux-
CFLAGS = -nostdlib

int.bin: start.S 
	${CROSS}gcc $(CFLAGS) -c -o start.o start.S
	${CROSS}ld -Tint.lds start.o  -o int.elf
#	${CROSS}ld -Ttext-segment 0x30000000 start.o  -o int.elf
	${CROSS}objcopy -O binary -S int.elf int.bin
#	rm -f  *.o


clean:
	rm -f *.elf *.o
	rm -f int.bin

 

该程序实现的流水灯,然后四个按键可以实现外部中断.

代码中值得注意的地方有几点:

1、lds文件中的地址配为0x00000000,因为程序是download到nandflash中运行的.最开始这里写的是0x30000000,那在异常向量表中:

        @b    irq
        ldr     pc, _irq

就出现了一个问题:只能用b irq跳转,无法用ldr pc, _irq跳转.当时就觉得奇怪,找了半天原因.后来才知道b跳转和用ldr伪指令只有区别的:

b是位置无关的,ldr不是位置无关的

b的范围只能是前后16M,总共32M,而ldr是4G

ldr的跳转是根据_irq:                .word irq的值,这个值是链接的时候确定的,也就是与链接地址相关.

所以在lds中链接地址改为0x00000000后,b和ldr都是正确的.

具体可以用dump看一下实际效果:

当lds中是0x30000000时,arm-linux-objdump -d int.elf结果如下:

30000000 <_start>:
30000000:    ea00000e     b    30000040
30000004:    e59ff014     ldr    pc, [pc, #20]    ; 30000020 <_undefined_instruction>
30000008:    e59ff014     ldr    pc, [pc, #20]    ; 30000024 <_software_interrupt>
3000000c:    e59ff014     ldr    pc, [pc, #20]    ; 30000028 <_prefetch_abort>
30000010:    e59ff014     ldr    pc, [pc, #20]    ; 3000002c <_data_abort>
30000014:    e59ff014     ldr    pc, [pc, #20]    ; 30000030 <_not_used>
30000018:    e59ff014     ldr    pc, [pc, #20]    ; 30000034 <_irq>
3000001c:    e59ff014     ldr    pc, [pc, #20]    ; 30000038 <_fiq>

而lds中是0x00000000时,dump的结果如下:

00000000 <_start>:
   0:    ea00000e     b    40
   4:    e59ff014     ldr    pc, [pc, #20]    ; 20 <_undefined_instruction>
   8:    e59ff014     ldr    pc, [pc, #20]    ; 24 <_software_interrupt>
   c:    e59ff014     ldr    pc, [pc, #20]    ; 28 <_prefetch_abort>
  10:    e59ff014     ldr    pc, [pc, #20]    ; 2c <_data_abort>
  14:    e59ff014     ldr    pc, [pc, #20]    ; 30 <_not_used>
  18:    e59ff014     ldr    pc, [pc, #20]    ; 34 <_irq>
  1c:    e59ff014     ldr    pc, [pc, #20]    ; 38 <_fiq>

解决了这第一个问题,总算可以用ldr跳入中断向量了.

2、中断处理程序的写法:

 

[cpp] view plaincopyprint?
  1. irq:  
  2.     sub     lr,lr,#4  
  3.     stmfd   sp!,{r0-r12,lr}  
  4.     bl irq_isr  
  5.     ldmfd  sp!,{r0-r12,pc}^   
irq:
	sub 	lr,lr,#4
	stmfd	sp!,{r0-r12,lr}
	bl irq_isr
	ldmfd  sp!,{r0-r12,pc}^ 

值得注意的是ldmfd  sp!,{r0-r12,pc}^ 会自动的从spsr_irq中恢复到cpsr中.

 

stmfd等价于stmdb,ldmfd等价于ldmia.因为arm使用FD(向低地址整长的满栈),所以堆栈处理都用fd的后缀即可.

3、记得在中断处理程序中清除中断,不然的话会一直响应那个中断.

关键字:GNU  ARM汇编  非嵌套中断处理 引用地址:GNU ARM汇编(四)中断汇编之非嵌套中断处理

上一篇:ARM Linux外部中断处理过程
下一篇:深入理解ARM体系架构S3C6410外部中断控制实例

推荐阅读最新更新时间:2024-03-16 14:53

ARM学习笔记11——GNU ARM汇编程序设计
  GNU ARM汇编程序设计中,每行的语法格式如下:    @comment   如果语句太长,可以将一条语句分几行来书写,在行末用“”表示换行。“”后不能有任何字符,包含空格和制表符(Tab)   参数说明: label:为标号,可选,可以使用字母,数字,下划线;除局部标号外,必须以字母或下划线开头。标号必须以“:”号结尾。标号大小写敏感 instruction | directive | pseudo-instruction:可选项,指令、伪指令、伪操作三者任选其一。注意:ARM指令,伪指令,伪操作,寄存器名称要么大写,要么小写,不可以大小写混合。 @comment:可选项,注释语句,@为注释标示符,
[单片机]
ARM汇编语言中的伪操作(一)
伪操作(derective)是ARM汇编语言程序里的一些特殊的指令助记符,其作用主要是为完成汇编程序做各种准备工作,在源程序运行汇编程序处理,而不是在计算机运行期间有机器执行.也就是说,这些伪操作只是汇编过程中起作用,一旦汇编结束,伪操作的使命也就随之消失. 符号定义( Symbol Definition )伪操作 符号定义伪操作用于定义 ARM 汇编程序中的变量、对变量赋值以及定义寄存器的别名。 包括以下伪操作: 用于声明全局变量 GBLA 、 GBLL 和 GBLS 。 用于声明局部变量 LCLA 、 LCLL 和 LCLS 。 用于对变量赋值 SETA 、 SETL 、 SETS
[单片机]
ARM学习笔记10——GNU ARM命令行工具
一、编译器arm-linux-gcc   1、用arm-linux-gcc编译一个程序,一般它是要经过如下步骤的:     1.1、预处理阶段     编译器把上述代码中stdio.h编译进来,使用GCC的选项-E可以使GCC在预处理结束后停止编译过程,而不继续其他动作了。     1.2、编译阶段     首先检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,arm-linux-gcc把代码翻译成汇编语言。用户可以使用-S选项来进行查看,该选项只编译而不进行汇编,生成汇编代码。     1.3、汇编阶段     把编译阶段生成.s文件转成目标文件,使用者可使用选项-c就
[单片机]
ARM汇编伪指令介绍
在 ARM 汇编语言程序里,有一些特殊指令助记符,这些助记符与指令系统的助记符不同,没有相对应的操作码,通常称这些特殊指令助记符为伪指令,他们所完成的操作称为伪操作。伪指令在源程序中的作用是为完成汇编程序作各种准备工作的,这些伪指令仅在汇编过程中起作用,一旦汇编结束,伪指令的使命就完成。 在 ARM 的汇编程序中,有如下几种伪指令:符号定义伪指令、数据定义伪指令、汇编控制伪指令、宏指令以及其他伪指令。 符号定义( Symbol Definition )伪指令 符号定义伪指令用于定义 ARM 汇编程序中的变量、对变量赋值以及定义寄存器的别名等操作。 常见的符号定义伪指令有如下几种:
[单片机]
ARM之汇编学习---如何编写ARM汇编程序
一.前言 1. 看一个程序: AREA TigerJohn,CODE,READONLY;声明代码段 CODE32 ;声明为32位ARM指令 ENTRY ;声明程序入口 START MOV R0 ,#0 MOV R1 ,#1 ADD R1, R1,R0 B START END 2. 在ARM汇编程序中用“;”号进行注释。 二.汇编语言程序格式 一个完整的ARM汇编由两部分组成:声明,实际代码段两部分组成。 1. 声
[单片机]
ARM汇编进阶
接触嵌入式以来,汇编来来回回学了好几遍,感觉还是有几个地方不清楚,所以在这里做一下总结,基本的非常简单的指令就不多余介绍了,主要分享一些个人觉得虽然微不足道,但是对于理解ARM汇编有帮助的一些知识 在这里一定要说一下,刚开始学的时候步入了一个大坑,我以为我学的是ARM汇编,后来了解到了,原来是GNU汇编,怪不得我有些问题去网上找的时候迷迷糊糊的,直到最近才纠正过来 所以首先就是介绍一下这两种汇编有什么区别 ARM汇编与GNU汇编区别 ARM汇编开发,有两种开发方式,一种是使用ARM汇编,一种是使用ARM GNU汇编。 两种汇编开发,使用的汇编指令是完全一样的。 区别是宏指令,伪指令,伪操作不一样。 有上述区
[单片机]
<font color='red'>ARM汇编</font>进阶
arm汇编指令--STR
STR指令的格式为: STR{条件} 源寄存器, 存储器地址 STR指令用亍从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常 用,丏寻址方式灵活多样,使用方式可参考指令LDR。 指令示例: STR R0, ,#8 ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。 STR R0, ;将R0中的字数据写入以R1+8为地址的存储器中。 str r1, ;将r1寄存器的值,传送到地址值为r0的(存储器)内存中
[单片机]
ARM汇编: ldr与mov 、 b与bl
ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。 比如想把数据从内存中某处读取到寄存器中,只能使用ldr 比如: ldr r0, 0x12345678 就是把0x12345678这个地址中的值存放到r0中。 而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中,这个和x86这种CISC架构的芯片区别最大的地方。 x86中没有ldr这种指令,因为x86的mov指令可以将数据从内存中移动到寄存器中。 另外还有一个就是ldr伪指令,虽然ldr伪指令和ARM的ldr指令很像,但是作用不太一样。ldr伪指令可以在立即数前加上=,以表示把一个地址写到某寄存器中,
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved