经常看到有人问这样的问题,自己用mini2440开发板调试中断的时候进不去中断,要了解中断,就需要了解中断机制和中断向量表。相信看这篇文章的读者肯定知道什么是中断以及中断机制了,由于中断的编程跟2440的启动方式有关系,因此我们先说下启动方式吧。
S 3C 2440支持两种启动模式:NAND和非NAND(这里是NOR FLASH)具体取决与OM0,OM1两个引脚。同时我们这里再加一种情况,就是程序在SDRAM中运行(或者说用JTAG调试的时候的情况)。我们就从这三种情况来说明中断如何实现。
(1) 当从NAND启动时,CPU会自动从NAND flash中读取前4KB的数据放置在片内SRAM里(S 3C 2440是集成到内部的叫做Steppingstone),同时把这段片内SRAM映射到nGCS0片选的空间(即0x00000000)。CPU是从0x00000000开始执行的,也就是NAND FLASH里面的前4KB内容。由于NAND FLASH的结构决定了NAND FLASH没有地址线,而且存取都是以页来进行的,这就是为什么CPU会自动从NAND FLASH读取前面4KB到内部SRAM里的原因。我们很快会想到一个问题,那就是4KB以后的代码如何执行。这就是程序员需要做的工作了,在前面4KB的代码中,必须含有将以后的主程序代码拷贝到SDRAM中运行,完成拷贝,以及4KB的启动代码后,跳转到SDRAM中执行其余程序。这里我就不详细介绍了,可以查看mini2440例子中的启动代码。
注意:这里必须明确的一点就是NAND地址不是线性的,程序不能直接运行,必须拷贝到线性RAM中。
(2) 当从NOR启动时,NOR FLASH被映射到0x00000000地址(就是nGCS0,这里就不需要片内SRAM来辅助了,所以片内SRAM的起始地址还是0x40000000)。然后CPU从0x00000000开始执行(也就是在Norflash中执行)。这种情况是最简单的,只要将程序的下载地址设置到0x00000000即可。
在实际的开发中,一般可以把bootloader烧入到Norflash,程序运行可以通过串**互,进行一定的操作,比如下载,调试。这样就很可以很方便的调试你的一些代码。Norflash中的Bootloader还可以烧录内核到Norflash等等功能。
(3) 当程序在SDRAM运行,由于SDRAM的地址是0x30000000,因此运行程序需要下载到0x30000000,当程序在内存中运行,由于发生中断时,会跳到0x00000018,因此在SDRAM运行时,要进入中断,有两种方法进行实现:一是MMU配置,使0x30000000映射到0x00000000地址,当中断发生时,跳到0x30000018的地址。二是在0x00000000的内部SDRAM中存中断向量表,或者在0x00000000的NAND FLASH位置放中断向量表。
下面是自己在MMU开启的情况下,中断的应用实例:
文件名:head.s
@*************************************************************************
@ File:head.S
@ 功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,
@ 然后跳到SDRAM继续执行
@*************************************************************************
.global PrintStr @************串口输出字符串函数*******************@
.include "2440addr.inc" @************引用2440头文件************************@
.include "Memcfg.inc"
.equ ISR_BADDR , 0xB3ffff00 @**************中断映射后的地址*****************@
.equ INTOFFSET , 0x 4a 000014 @Interruot r=est source offset
.equ rINTMSK ,0x 4a 000008 @//Interrupt mask control
@频率的设置参数定义
.equ CLKDIV_VAL , 5 @ 0=1:1:1, 1=1:1:2, 2=1:2:2, 3=1:2:4, 4=1:4:4, 5=1:4:8, 6=1:3:3, 7=1:3:6.
.equ M_MDIV , 92 @ Fin=12.0MHz Fout=304.8MHz
.equ M_PDIV , 1 @ 1
.equ M_SDIV , 1 @ 2
.equ U_MDIV , 56 @ Fin=12MHz Fout=48MHz
.equ U_PDIV , 2
.equ U_SDIV , 2
@宏定义 定义HANDLER宏
.macro HANDLER $HandleLabel
sub sp,sp,#4
stmfd sp!,{r0}
ldr r0,=/$HandleLabel
ldr r0,[r0]
str r0,[sp,#4]
ldmfd sp!,{r0,pc}
.endm
@@@@@@****************程序入口********************@@@@@@@@
.code 32
.text
.align 4
.global _start
_start:
b ResetHandle
HandlerUndef:
b HandlerUndef @@@未定义指令中止模式的向量地址
HandlerSWI:
b HandlerSWI @@@管理模式的向量地址,通过SWI指令进入此模式
HandlerPabort:
b HandlerPabort @@@指令预取终止导致的异常的向量地址
HandlerDabort:
b HandlerDabort @@@数据访问终止导致的异常的向量地址
b .
ldr pc, =HandlerIRQ @@@中断模式的向量地址
ldr pc, =HandlerFIQ @@@快中断模式的向量地址
b .
HandlerFIQ: HANDLER HandleFIQ
HandlerIRQ: HANDLER HandleIRQ
@@@@@@@中断二级表,在这里区别是什么中断,然后跳入相应的中断进行处理
ISR_IRQ:
sub lr, lr, #4 @ compute the return address
stmfd sp!,{r0-r12,lr} @ save r8, r9, lr
adr r0,Say_Hello
bl PrintStr
ldr r9,=INTOFFSET
ldr r9,[r9]
@ldr r8,=HandleEINT0
ldr r8,=0xB3ffff20//这里用的是虚拟地址,因为映射后HandleEINT0==0xB3ffff20
add r8,r8,r9,lsl #2
ldr r8,[r8]
mov lr, pc @ the pc is the address ofIRQ_return
mov pc, r8
ldmia sp!, {r0-r12,pc}^ @ restore the r8,r9,pc(lr)
@@@@@@@RESET
ResetHandle:
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
ldr r0,=INTMSK
ldr r1,=0xffffffff @all interrupt disable不使能中断
str r1,[r0]
ldr r0,=SRCPND
str r1,[r0]
ldr r0,=INTPND
str r1,[r0]
ldr r0,=INTSUBMSK
ldr r1,=0x7fff @all sub interrupt disable,
2002/04/10
str r1,[r0]
@@@设置频率
mov r1, #CLK_CTL_BASE
ldr r2, clock_locktime
str r2, [r1, #oLOCKTIME]
mov r1, #CLK_CTL_BASE
ldr r2, clkdivn_value
str r2, [r1, #oCLKDIVN]
mrc p15, 0, r1, c1, c0, 0 @ read ctrl register
orr r1, r1, #0xc0000000 @ Asynchronous
mcr p15, 0, r1, c1, c0, 0 @ write ctrl register
mov r1, #CLK_CTL_BASE
ldr r2, mpll_value @ clock default
str r2, [r1, #oMPLLCON]
@@@@初始化串口
InitUART:
@set GPIO for UART
mov r1, #GPIO_CTL_BASE
add r1, r1, #oGPIO_H
ldr r2, gpio_con_uart
str r2, [r1, #oGPIO_CON]
ldr r2, gpio_up_uart
str r2, [r1, #oGPIO_UP]
ldr r1, SerBase
mov r2, #0x0
str r2, [r1, #oUFCON]
str r2, [r1, #oUMCON]
mov r2, #0x3
str r2, [r1, #oULCON]
ldr r2, =0x245
str r2, [r1, #oUCON]
.equ UART_BRD , ((UART_PCLK / (UART_BAUD_RATE*16)) - 1)
mov r2, #UART_BRD
str r2, [r1, #oUBRDIV]
mov r3, #100
InitUART1:
subs r3, r3, #0x1
bne InitUART1
@@@@@@@@@@@@@@进入中断模式,并设置堆栈指针@@@@@@@@@@
mrs r0,cpsr
orr r1,r0,#0xd2
msr cpsr_c,r1
ldr sp,=3072
msr cpsr_c, #0xdf @进入系统模式
ldr r0,=rINTMSK
mov r1,#0xfffffbff@@@允许中断
str r1,[r0]
ldr sp,=4096
msr cpsr_c, #0x
5f
@设置I-bit=0,开IRQ中断
ldr r0,=0x33ffff18
ldr r1,=ISR_IRQ @ if there isnt "subs pc,lr,#4" at 0x18, 0x
1c
str r1,[r0]
bl memsetup @ 设置存储控制器以使用SDRAM
bl copy_2th_to_sdram @ 将第二部分代码复制到SDRAM
bl create_page_table @ 设置页表
bl mmu_init @ 启动MMU
ldr sp, =0xB2000000 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址)
ldr pc,=0xB0004000 @ 跳到SDRAM中继续执行第二部分代码
halt_loop:
b halt_loop
PrintChar:
mov r1, #UART0_CTL_BASE
PrintChar1:
ldr r2, [r1, #oUTRSTAT]
tst r2, #UTRSTAT_TX_EMPTY
beq PrintChar1
str r0, [r1, #oUTXHL]
mov pc, lr
PrintStr:
stmfd sp!, {r4, lr}
movs r4, r0
ldmeqfd sp!, {r4, pc}
PrintStr1:
ldrb r0, [r4], #1
cmp r0, #0
ldmeqfd sp!, {r4, pc}
bl PrintChar
b PrintStr1
Say_Hello:
.asciz "Welcome To Used TMSG_GUI./r/n"
clock_locktime:
.word vLOCKTIME
mpll_value:
.word (M_MDIV<<12)+(M_PDIV<<4)+(M_SDIV)
clkdivn_value:
.word vCLKDIVN
gpio_con_uart:
.word vGPHCON
gpio_up_uart:
.word vGPHUP
SerBase:
.word UART0_CTL_BASE
@ @@@@@@@@@@@@@@@@@@@@@@@@@@
.equ HandleReset, (ISR_BADDR+4*0)
.equ HandleUndef, (ISR_BADDR+4*1)
.equ HandleSWI, (ISR_BADDR+4*2)
.equ HandlePabort, (ISR_BADDR+4*3)
.equ HandleDabort, (ISR_BADDR+4*4)
.equ HandleReserved, (ISR_BADDR+4*5)
.equ HandleIRQ, (ISR_BADDR+4*6)
.equ HandleFIQ, (ISR_BADDR+4*7)
.equ HandleEINT0, (ISR_BADDR+4*8)
.equ HandleEINT1, (ISR_BADDR+4*9)
.equ HandleEINT2, (ISR_BADDR+4*10)
.equ HandleEINT3, (ISR_BADDR+4*11)
.equ HandleEINT4_7, (ISR_BADDR+4*12)
.equ HandleEINT8_23, (ISR_BADDR+4*13)
.equ HandleRSV6, (ISR_BADDR+4*14)
.equ HandleBATFLT, (ISR_BADDR+4*15)
.equ HandleTICK, (ISR_BADDR+4*16)
.equ HandleWDT, (ISR_BADDR+4*17)
.equ HandleTIMER0, (ISR_BADDR+4*18)
.equ HandleTIMER1, (ISR_BADDR+4*19)
.equ HandleTIMER2, (ISR_BADDR+4*20)
.equ HandleTIMER3, (ISR_BADDR+4*21)
.equ HandleTIMER4, (ISR_BADDR+4*22)
.equ HandleUART2, (ISR_BADDR+4*23)
.equ HandleLCD, (ISR_BADDR+4*24)
.equ HandleDMA0, (ISR_BADDR+4*25)
.equ HandleDMA1, (ISR_BADDR+4*26)
.equ HandleDMA2, (ISR_BADDR+4*27)
.equ HandleDMA3, (ISR_BADDR+4*28)
.equ HandleMMC, (ISR_BADDR+4*29)
.equ HandleSPI0, (ISR_BADDR+4*30)
.equ HandleUART1, (ISR_BADDR+4*31)
.equ HandleRSV24, (ISR_BADDR+4*32)
.equ HandleUSBD, (ISR_BADDR+4*33)
.equ HandleUSBH, (ISR_BADDR+4*34)
.equ HandleIIC, (ISR_BADDR+4*35)
.equ HandleUART0 , (ISR_BADDR+4*36)
.equ HandleSPI1, (ISR_BADDR+4*37)
.equ HandleRTC, (ISR_BADDR+4*38)
.equ HandleADC, (ISR_BADDR+4*39)