GNU ARM汇编--(四)中断汇编之非嵌套中断处理
时间:11-26
来源:互联网
点击:
在写这篇blog之前,不得不感慨一句:纸上得来终觉浅,绝知此事要躬行.作为EE出身的,虽然好久好久没用汇编写单片机的中断了,但自我感觉对中断的理解还是比较深入的,本以为在GNU ARM汇编下搞个中断会很容易,谁知道断断续续花了我几周.完全用汇编写中断和用c中的_irq写中断还是有区别的,谁用谁知道.还是那句话:深入细节是必须的,也是值得的.
这一篇blog的理论知识主要来源于:《ARM System Developers 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 plaincopy
- /*
- simpleinterruption
- copyleft@dndxhej@gmail.com
- */
- .equNOINT,0xc0
- .equWTCON,0x53000000
- .equGPBCON,0x56000010@led
- .equGPBDAT,0x56000014@led
- .equGPBUP,0x56000018@led
- .equGPFCON,0x56000050@interruptconfig
- .equEINTMASK,0x560000a4
- .equEXTINT0,0x56000088
- .equEXTINT1,0x5600008c
- .equEXTINT2,0x56000090
- .equINTMSK,0x4A000008
- .equEINTPEND,0x560000a8
- .equINTSUBMSK,0X4A00001C
- .equSRCPND,0X4A000000
- .equINTPND,0X4A000010
- .global_start
- _start:breset
- ldrpc,_undefined_instruction
- ldrpc,_software_interrupt
- ldrpc,_prefetch_abort
- ldrpc,_data_abort
- ldrpc,_not_used
- @birq
- ldrpc,_irq
- ldrpc,_fiq
- _undefined_instruction:.wordundefined_instruction
- _software_interrupt:.wordsoftware_interrupt
- _prefetch_abort:.wordprefetch_abort
- _data_abort:.worddata_abort
- _not_used:.wordnot_used
- _irq:.wordirq
- _fiq:.wordfiq
- .balignl16,0xdeadbeef
- reset:
- ldrr3,=WTCON
- movr4,#0x0
- strr4,[r3]@disablewatchdog
- ldrr0,=GPBCON
- ldrr1,=0x15400
- strr1,[r0]
- ldrr2,=GPBDAT
- ldrr1,=0x160
- strr1,[r2]
- bldelay
- msrcpsr_c,#0xd2@进入中断模式
- ldrsp,=3072@中断模式的栈指针定义
- msrcpsr_c,#0xdf@进入系统模式
- ldrsp,=4096@设置系统模式的栈指针
- @--------------------------------------------
- ldrr0,=GPBUP
- ldrr1,=0x03f0
- strr1,[r0]
- ldrr0,=GPFCON
- ldrr1,=0x2ea@0x2
- strr1,[r0]
- ldrr0,=EXTINT0
- ldrr1,=0x8f888@0x0@0x8f888@~(7|(7<4)|(7<8)|(7<16))
- strr1,[r0]
- ldrr0,=EINTPEND
- ldrr1,=0xf0@0b10000
- strr1,[r0]
- ldrr0,=EINTMASK
- ldrr1,=0x00@0b00000
- strr1,[r0]
- ldrr0,=SRCPND
- ldrr1,=0xff@0x1@0b11111
- strr1,[r0]
- ldrr0,=INTPND
- ldrr1,=0xff@0x1@0b11111
- strr1,[r0]
- ldrr0,=INTMSK
- ldrr1,=0xffffff00@0b00000
- strr1,[r0]
- MRSr1,cpsr
- BICr1,r1,#0x80
- MSRcpsr_c,r1
- blmain
- irq:
- sublr,lr,#4
- stmfdsp!,{r0-r12,lr}
- blirq_isr
- ldmfdsp!,{r0-r12,pc}^
- irq_isr:
- ldrr2,=GPBDAT
- ldrr1,=0x0e0
- strr1,[r2]
- ldrr0,=EINTPEND
- ldrr1,=0xf0
- strr1,[r0]
- ldrr0,=SRCPND
- ldrr1,=0x3f@0b11111
- strr1,[r0]
- ldrr0,=INTPND
- ldrr1,=0x3f@0b11111
- strr1,[r0]
- movpc,lr
- delay:
- ldrr3,=0xffff
- delay1:
- subr3,r3,#1
- cmpr3,#0x0
- bnedelay1
- movpc,lr
- main:
- ledloop:
- ldrr1,=0x1c0
- strr1,[r2]
- bldelay
- ldrr1,=0x1a0
- strr1,[r2]
- bldelay
- ldrr1,=0x160
- strr1,[r2]
- bldelay
- ldrr1,=0x0e0
- strr1,[r2]
- bldelay
- bledloop
- undefined_instruction:
- nop
- software_interrupt:
- nop
- prefetch_abort:
- nop
- data_abort:
- nop
- not_used:
- nop
- fiq:
- nop
lds文件:
[cpp]view plaincopy
- OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")
- OUTPUT_ARCH(arm)
- ENTRY(_start)
- SECTIONS{
- .=0x00000000;
- .text:{
- *(.text)
- *(.rodata)
- }
- .dataALIGN(4):{
- *(.data)
- }
- .bssALIGN(4):{
- *(.bss)
- }
- }
makefile:
[cpp]view plaincopy
- CROSS=arm-linux-
- CFLAGS=-nostdlib
- int.bin:start.S
- ${CROSS}gcc$(CFLAGS)-c-ostart.ostart.S
- ${CROSS}ld-Tint.ldsstart.o-oint.elf
- #${CROSS}ld-Ttext-segment0x30000000start.o-oint.elf
- ${CROSS}objcopy-Obinary-Sint.elfint.bin
- #rm-f*.o
- clean:
- rm-f*.elf*.o
- rm-fint.bin
该程序实现的流水灯,然后四个按键可以实现外部中断.
代码中值得注意的地方有几点:
1、lds文件中的地址配为0x00000000,因为程序是download到nandflash中运行的.最开始这里写的是0x300
ARM汇编中断汇编中断处 相关文章:
- GNU ARM汇编--(五)中断汇编之嵌套中断处理(11-26)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)