前言
本文主要描述如何在Keil自带的S3C2440.s文件中添加中断配置及中断地址映射,从而可以在中断产生时跳转到用户代码中的中断服务函数。目前在TQ2440开发板是实测可用。
工程源代码下载
本文所有代码都是截取代码,“…”代表其还有上下文。可根据代码中上下文的残缺部分找到该代码添加的位置。
一,添加中断相关寄存器地址符号映射
因为原始S3C2440.s文件中不含中断相关寄存器的地址,所以需要在开头添加:
...
; * RAM_INTVEC: when set the startup code copies exception vectors
; * from execution address to on-chip RAM.
; */
;=================
; INTERRUPT
;=================
SRCPND EQU 0x4a000000 ;Interrupt request status
INTMOD EQU 0x4a000004 ;Interrupt mode control
INTMSK EQU 0x4a000008 ;Interrupt mask control
PRIORITY EQU 0x4a00000c ;IRQ priority control <-- May 06, 2002 SOP
INTPND EQU 0x4a000010 ;Interrupt request status
INTOFFSET EQU 0x4a000014 ;Interruot request source offset
SUSSRCPND EQU 0x4a000018 ;Sub source pending
INTSUBMSK EQU 0x4a00001c ;Interrupt sub mask
_ISR_STARTADDRESS EQU 0x33ffff00
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
...123456789101112131415161718192021222324252627
二,添加中断向量偏移表
在文件末尾添加中断向量表,对应2440addr.h文件中相应的中断向量地址,起始地址参见_ISR_STARTADDRESS。
...
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDIF
ALIGN
AREA RamData, DATA, READWRITE
^ _ISR_STARTADDRESS ; _ISR_STARTADDRESS=0x33FF_FF00
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePabort # 4
HandleDabort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4
;Do not use the label 'IntVectorTable',
;The value of IntVectorTable is different with the address you think it may be.
;IntVectorTable
;@0x33FF_FF20
HandleEINT0 # 4
HandleEINT1 # 4
HandleEINT2 # 4
HandleEINT3 # 4
HandleEINT4_7 # 4
HandleEINT8_23 # 4
HandleCAM # 4 ; Added for 2440.
HandleBATFLT # 4
HandleTICK # 4
HandleWDT # 4
HandleTIMER0 # 4
HandleTIMER1 # 4
HandleTIMER2 # 4
HandleTIMER3 # 4
HandleTIMER4 # 4
HandleUART2 # 4
;@0x33FF_FF60
HandleLCD # 4
HandleDMA0 # 4
HandleDMA1 # 4
HandleDMA2 # 4
HandleDMA3 # 4
HandleMMC # 4
HandleSPI0 # 4
HandleUART1 # 4
HandleNFCON # 4 ; Added for 2440.
HandleUSBD # 4
HandleUSBH # 4
HandleIIC # 4
HandleUART0 # 4
HandleSPI1 # 4
HandleRTC # 4
HandleADC # 4
;@0x33FF_FFA0
END
三,添加程序__ENTRY入口点
定义程序入口点的位置,在ram调试状态下,就是0x30000000对应的Reset Handler的跳转代码。
...
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
EXPORT __ENTRY
__ENTRY
Vectors LDR PC, Reset_Addr
LDR PC, Undef_Addr
LDR PC, SWI_Addr
LDR PC, PAbt_Addr
...
四,修改添加中断现场保护及跳转代码
除了IRQ中断以外的所有中断的现场保护及跳转代码,因为这些中断在向量表都只有一种状态,所以不需要偏移。这里是宏定义的实际代码,宏定义的调用见五,修改添加IRQ中断现场保护及跳转代码中的代码。
...
GPJCON_Val EQU 0x00000000
GPJUP_Val EQU 0x00000000
;// I/O Setup‘
MACRO
$HandlerLabel HANDLER $HandleLabel
$HandlerLabel
sub sp,sp,#4 ;decrement sp(to store jump address)
stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
ldr r0,=$HandleLabel;load the address of HandleXXX to r0
ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
MEND
;----------------------- CODE --------------------------------------------------
PRESERVE8
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
..
五,修改添加IRQ中断现场保护及跳转代码
IRQ中断的现场保护及跳转代码。IRQ中断有很多可能,比如按键的外部中断,串口中断,IIC中断。。。等,需要根据实际中断标志指示跳转到对应的服务函数,所以需要一套独立的中断处理代码。此处代码来自《mini2440—–keil for ARM之中断一》。
...
ELSE
IRQ_Addr DCD IRQ_Handler
ENDIF
FIQ_Addr DCD FIQ_Handler
;Undef_Handler B Undef_Handler
;IF :DEF:__RTX
;ELSE
;SWI_Handler B SWI_Handler
;ENDIF
;PAbt_Handler B PAbt_Handler
;DAbt_Handler B DAbt_Handler
;IRQ_Handler PROC
;EXPORT IRQ_Handler [WEAK]
;B .
;ENDP
;FIQ_Handler B FIQ_Handler
FIQ_Handler HANDLER HandleFIQ
HandlerIRQ HANDLER HandleIRQ
Undef_Handler HANDLER HandleUndef
SWI_Handler HANDLER HandleSWI
DAbt_Handler HANDLER HandleDabort
PAbt_Handler HANDLER HandlePabort
;呵呵,来了来了.好戏来了,这一段程序就是用来进行第二次查表的过程了.
;如果说第一次查表是由硬件来完成的,那这一次查表就是由软件来实现的了.
;为什么要查两次表??
;没有办法,ARM把所有的中断都归纳成一个IRQ中断异常和一个FIRQ中断异常
;第一次查表主要是查出是什么异常,可我们总要知道是这个中断异常中的什么中断呀!
;没办法了,再查一次表呗!
;===================================================================================
;外部中断号判断,通过中断服务程序入口地址存储器的地址偏移确定
;PC=[HandleEINT0+[INTOFFSET]]
;IsrIRQ
IRQ_Handler
sub sp,sp,#4 ;给PC寄存器保留 reserved for PC
stmfd sp!,{r8-r9} ;把r8-r9压入栈
ldr r9,=INTOFFSET ;把INTOFFSET的地址装入r9 INTOFFSET是一个内部的寄存器,存着中断的偏移
ldr r9,[r9] ;I_ISR
ldr r8,=HandleEINT0 ;这就是我们第二个中断向量表的入口的,先装入r8
;===================================================================================
;哈哈,这查表方法够好了吧,r8(入口)+index*4(别望了一条指令是4 bytes的喔),
;这不就是我们要找的那一项了吗.找到了表项,下一步做什么?肯定先装入了!
;==================================================================================
add r8,r8,r9,lsl #2 ;地址对齐,因为每个中断向量占4个字节,即isr = IvectTable + Offeset * 4
ldr r8,[r8] ;装入中断服务程序的入口
str r8,[sp,#8] ;把入口也入栈,准备用旧招
ldmfd sp!,{r8-r9,pc} ;施招,弹出栈,哈哈,顺便把r8弹出到PC了,跳转成功!
; Reset Handler
EXPORT Reset_Handler
...
六,屏蔽USER模式,开启SVC模式,打开IRQ中断
因为在ram调试时,code地址是从0x30000000开始,而IRQ中断跳转会直接调到0x00000018,然而我们期望跳到0x30000018(这个才是真正的IRQ入口),所以需要用mmu做一个0x00000018到0x30000018的映射(这个在TQ2440工程中的mmu初始化代码中完成)。但是mmu调用cp15协处理器的汇编代码在USER模式下会出问题?!目前只能先用SVC模式。此外,Keil自带的S3C2440.s文件默认是关闭SVC模式的IRQ中断,需要修改代码开启。
...
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
;MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MSR CPSR_c, #Mode_SVC:OR:F_Bit
上一篇:学习笔记 --- S3C2440 DMA操作原理
下一篇:mini2440---keil for ARM下的调试与下载环境的搭建
推荐阅读最新更新时间:2024-11-13 07:20
设计资源 培训 开发板 精华推荐
- 智能管家&蓝牙功放
- MD1715DB2,基于 MD1715 + TC8020 高速 ±100V 3.2A 脉冲发生器的演示板
- LT3756EUD 94% 效率 30W 白光 LED 前照灯驱动器的典型应用电路
- DER-30 - 3.3W 非隔离反激式转换器
- #第四届立创大赛#基于大功率H桥设计的智能急速冷暖杯
- 使用 Microchip Technology 的 MIC4600YML 的参考设计
- MC34932SEK,双通道5A油门控制
- 使用 ROHM Semiconductor 的 BD5250 的参考设计
- 使用 MagnaChip Semiconductor 的 MAP9010QNRH 的参考设计
- DC2248A-B,用于 LTC6951-1 5 输出整数 N PLL 的演示板,具有集成 VCO,输出范围为 2.1MHz 至 2.7GHz