44B0中断

我想在这里讨论一下有关启动代码中的中断初始化部分,所以无关的部分被删掉了。

GET ..\inc\option.a GET ..\inc\memcfg.a

(省略……)

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't 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 以上是个宏,用于把中断服务程序的首地址装载到pc中,我称它为“加载程序”。 本初始化程序定义了一个数据区(在文件最后),34个字空间,存放相应中断服务程序的首地址。每个字空间都有一个标号,以Handle***命名。 在向量中断模式下使用“加载程序”来执行中断服务程序。

(省略……)

IMPORT Main ; The main entry of mon program

AREA Init,CODE,READONLY

ENTRY b ResetHandler ;for debug b HandlerUndef ;handlerUndef b HandlerSWI ;SWI interrupt handler b HandlerPabort ;handlerPAbort b HandlerDabort ;handlerDAbort b . ;handlerReserved b HandlerIRQ b HandlerFIQ ;***IMPORTANT NOTE*** ;If the H/W vectored interrutp mode is enabled, The above two instructions should ;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller. ; b HandlerIRQ -> subs pc,lr,#4 ; b HandlerIRQ -> subs pc,lr,#4

VECTOR_BRANCH ldr pc,=HandlerEINT0 ; mGA 0x20 H/W interrupt vector table ldr pc,=HandlerEINT1 ; ldr pc,=HandlerEINT2 ; ldr pc,=HandlerEINT3 ; ldr pc,=HandlerEINT4567 ; ldr pc,=HandlerTICK ; mGA 0x34 b . b . ldr pc,=HandlerZDMA0 ; mGB 0x40 ldr pc,=HandlerZDMA1 ; ldr pc,=HandlerBDMA0 ; ldr pc,=HandlerBDMA1 ; ldr pc,=HandlerWDT ; ldr pc,=HandlerUERR01 ; mGB 0x54 b . b . ldr pc,=HandlerTIMER0 ; mGC 0x60 ldr pc,=HandlerTIMER1 ; ldr pc,=HandlerTIMER2 ; ldr pc,=HandlerTIMER3 ; ldr pc,=HandlerTIMER4 ; ldr pc,=HandlerTIMER5 ; mGC 0x74 b . b . ldr pc,=HandlerURXD0 ; mGD 0x80 ldr pc,=HandlerURXD1 ; ldr pc,=HandlerIIC ; ldr pc,=HandlerSIO ; ldr pc,=HandlerUTXD0 ; ldr pc,=HandlerUTXD1 ; mGD 0x94 b . b . ldr pc,=HandlerRTC ; mGKA 0xa0 b . ; b . ; b . ; b . ; b . ; mGKA b . b . ldr pc,=HandlerADC ; mGKB 0xc0 b . ; b . ; b . ; b . ; b . ;mGKB b . b . ;0xe0=EnterPWDN ldr pc,=EnterPWDN

LTORG

下面是每个中断源的“加载程序” HandlerFIQ HANDLER HandleFIQ HandlerIRQ HANDLER HandleIRQ HandlerUndef HANDLER HandleUndef HandlerSWI HANDLER HandleSWI HandlerDabort HANDLER HandleDabort HandlerPabort HANDLER HandlePabort

HandlerADC HANDLER HandleADC HandlerRTC HANDLER HandleRTC HandlerUTXD1 HANDLER HandleUTXD1 HandlerUTXD0 HANDLER HandleUTXD0 HandlerSIO HANDLER HandleSIO HandlerIIC HANDLER HandleIIC HandlerURXD1 HANDLER HandleURXD1 HandlerURXD0 HANDLER HandleURXD0 HandlerTIMER5 HANDLER HandleTIMER5 HandlerTIMER4 HANDLER HandleTIMER4 HandlerTIMER3 HANDLER HandleTIMER3 HandlerTIMER2 HANDLER HandleTIMER2 HandlerTIMER1 HANDLER HandleTIMER1 HandlerTIMER0 HANDLER HandleTIMER0 HandlerUERR01 HANDLER HandleUERR01 HandlerWDT HANDLER HandleWDT HandlerBDMA1 HANDLER HandleBDMA1 HandlerBDMA0 HANDLER HandleBDMA0 HandlerZDMA1 HANDLER HandleZDMA1 HandlerZDMA0 HANDLER HandleZDMA0 HandlerTICK HANDLER HandleTICK HandlerEINT4567 HANDLER HandleEINT4567 HandlerEINT3 HANDLER HandleEINT3 HandlerEINT2 HANDLER HandleEINT2 HandlerEINT1 HANDLER HandleEINT1 HandlerEINT0 HANDLER HandleEINT0

;One of the following two routines can be used for non-vectored interrupt.

下面这段程序的首地址将要被放到HandleIRQ中,在非向量中断模式下发生IRQ中断时,执行此程序来判断中断源以执行相应的中断服务程序。 IsrIRQ ;using I_ISPR register. sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9}

;IMPORTANT CAUTION ;if I_ISPC isn't used properly, I_ISPR can be 0 in this routine.

ldr r9,=I_ISPR ldr r9,[r9] mov r8,#0x00 movs r9,r9,lsr #1 bcs %F1 add r8,r8,#4 b %B0

1 ldr r9,=HandleADC add r9,r9,r8 ldr r9,[r9] str r9,[sp,#8] ldmfd sp!,{r8-r9,pc}

;**************************************************** ;* START * ;**************************************************** ResetHandler

(省略……)

下面就是把IsrIRQ的首地址装载到HandleIRQ的代码 ;**************************************************** ;* Setup IRQ handler * ;**************************************************** ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0]

(省略……)

ALIGN

AREA RamData, DATA, READWRITE

^ (_ISR_STARTADDRESS-0x500)

UserStack # 256 ;c1(c7)ffa00 SVCStack # 256 ;c1(c7)ffb00 UndefStack # 256 ;c1(c7)ffc00 AbortStack # 256 ;c1(c7)ffd00 IRQStack # 256 ;c1(c7)ffe00 FIQStack # 0 ;c1(c7)fff00

^ _ISR_STARTADDRESS HandleReset # 4 HandleUndef # 4 HandleSWI # 4 HandlePabort # 4 HandleDabort # 4 HandleReserved # 4 HandleIRQ # 4 HandleFIQ # 4

;Don't use the label 'IntVectorTable', ;because armasm.exe cann't recognize this label correctly. ;the value is different with an address you think it may be. ;IntVectorTable HandleADC # 4 HandleRTC # 4 HandleUTXD1 # 4 HandleUTXD0 # 4 HandleSIO # 4 HandleIIC # 4 HandleURXD1 # 4 HandleURXD0 # 4 HandleTIMER5 # 4 HandleTIMER4 # 4 HandleTIMER3 # 4 HandleTIMER2 # 4 HandleTIMER1 # 4 HandleTIMER0 # 4 HandleUERR01 # 4 HandleWDT # 4 HandleBDMA1 # 4 HandleBDMA0 # 4 HandleZDMA1 # 4 HandleZDMA0 # 4 HandleTICK # 4 HandleEINT4567 # 4 HandleEINT3 # 4 HandleEINT2 # 4 HandleEINT1 # 4 HandleEINT0 # 4 ;0xc1(c7)fff84

END

本程序的初始化中断部分实现的很巧妙,基于34个字单元将向量中断和非向量中断的实现结合在一起。 向量中断直接使用“加载程序”,把相应的中断服务程序首地址(存放于Handle***)加载到PC。 非向量中断通过执行IsrIRQ判断中断源,并同时计算出相应Handle***的地址,再将此地址的内容加载到PC。

我有两个问题: 问题一,非向量中断有个缺点,它始终从优先级最低的中断源开始识别,且是通过过分析I_ISPR寄存器的每一位来识别,但是尽管有多个中断同时发生,I_ISPR只有一位置1。如此一来,频繁发生低优先级中断是否会屏蔽其他中断? 我有过一次试验,设置两个中断INT_TICK和INT_TIMER5,两个中断服务程序都使用串口打印一串字符。当TIMER5以频率为1KHz(每毫秒一次)中断时,TICK中断服务程序毫无反应。

问题二,本代码中有这样一段 b HandlerIRQ b HandlerFIQ ;***IMPORTANT NOTE*** ;If the H/W vectored interrutp mode is enabled, The above two instructions should ;be changed like below, to work-around with H/W bug of S3C44B0X interrupt controller. ; b HandlerIRQ -> subs pc,lr,#4 ; b HandlerIRQ -> subs pc,lr,#4 大意是如果使用向量中断模式,必须用subs pc,lr,#4代替b HandlerIRQ。 首先我不太确定发生向量中断时,CPU是否执行b HandlerIRQ,还是直接转向相应中断源的向量地址。如果不执行b HandlerIRQ,那么subs pc,lr,#4有何意义?如果执行b HandlerIRQ,那subs pc,lr,#4岂不是又使CPU从IRQ模式转换回SVC模式,继续执行被中断了的代码,这又是何意义? 另外,我按照他的方法试过,设置INTCON为向量中断,但一运行系统就重起,改回非向量中断一切正常。

Click here to find out more!
 
 
    回复      回复本帖      回到顶端  
   发表于 2005-02-27 21:07:00我想评分   回到列表 [2楼] 
 puppypyb
我是GG    普通会员
用户等级:菜鸟
加为好友 发短消息
所有发言 个人档案
最后登陆时间:2007-07-30 17:24:40
状态:离线

不知道是哪位兄弟写的<<关于S3C44b启动代码中中断初始化部分的讨论和问题>>, 我觉得写的非常好, 其实这个启动代码在samsung的网

站上都可以找到, 一般都是直接拿来用, 至于中间很多问题都不知道为什么! 其中很多问题我也一直很困惑 , 这位兄弟开了个好头 ,大家不妨集思广益 ,来讨论一下这些问题.

一开始要讨论的还是文件最后那34个字空间的数据区, 存放的是相应的中断服务程序的首地址 .每个字空间都有一个标号,以Handle***命名. 可以说这34个字空间的数据区是关键,不管是向量中断还是非向量中断 ,最终的落脚点都是要调用该34字空间存放的各个中断服务的首地址.

举个例子:

(1)非向量中断 假如设置为非向量中断模式, 中断模式为IRQ, 则中断发生后程序会跳转到0x18, 该处指令是 b HandlerIRQ , 又根据HandlerIRQ HANDLER HandleIRQ, 这是一个宏, 展开后就是: HandlerIRQ sub sp,sp,#4 ; decrement sp(to store jump address) stmfd sp!,{r0} ; PUSH the work register to stack

ldr r0,=HandleIRQ 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)

那位兄弟把该宏称为"加载程序", 用于把中断服务程序的首地址装载到pc中. 这时程序应该跳转到哪里呢? 要看pc里是什么, 显然, 这时候pc的值就是标号为HandleIRQ的存储空间所存储的值 , 但是我们看最后的那34字

的存储空间, 发现只是单纯的划分出了这34字的一个存储结构,并没有给每个存储空间赋值. 也就是说对应的34个存储空间存储的内容都为空(好像默认为0,反正是无效的值) . 不要急 , 我们还发现源程序中有这么一段: ;**************************************************** ;* Setup IRQ handler * ;**************************************************** ldr r0,=HandleIRQ ;This routine is needed ldr r1,=IsrIRQ ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0]

可以很清楚的看到: 在bootloader初始化的时候, 标号为HandleIRQ的存储空间被赋了值, 被赋予的值就是中断服务程序 IsrIRQ的首地址.

; 用软件方式来判断中断源 IsrIRQ ;using I_ISPR register. sub sp,sp,#4 ;reserved for PC stmfd sp!,{r8-r9}

ldr r9,=I_ISPR ldr r9,[r9] mov r8,#0x00

0 movs r9,r9,lsr #1 bcs %F1 add r8,r8,#4 b %B0

1 ldr r9,=HandleADC add r9,r9,r8 ldr r9,[r9] str r9,[sp,#8] ldmfd sp!,{r8-r9,pc}

非向量中断通过执行IsrIRQ判断中断源,并同时计算出相应Handle***的地址,再将此地址的内容加载到PC。该Handle***地址的内容就是相应的中断源的中断服务程序, 应该也是: ;**************************************************** ;* Setup *** handler * ;**************************************************** ldr r0,=Handle*** ;This routine is needed ldr r1,=Isr*** ;if there isn't 'subs pc,lr,#4' at 0x18, 0x1c str r1,[r0]

;**************************************************** ;* 相应的中断源的ISR * ;**************************************************** Isr*** ....... .......

或者用C程序实现该ISR

写到这里我也想问一个问题: 为什么要用那个宏作加载程序呢?? 这个宏的作用就是把中断服务程序的首地址装载到pc中, 可不可以简化??

(2) 向量中断 假如为向量中断模式, 若这时候产生EINT0中断, 那么interrupt controler会使程序自动跳转到 0x20, 该处的指令是ldr pc,=HandlerEINT0, 又根据 HandlerEINT0 HANDLER HandleEINT0 ,同样展开后就是: HandlerEINT0 sub sp,sp,#4 ; decrement sp(to store jump address) stmfd sp!,{r0} ; PUSH the work register to stack(lr does't push because it return to original address) ldr r0,=HandleEINT0 ; 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)

接下来的过程就应该和上面的过程类似了. 其实用向量中断模式过程更为简单, 省去了用软件方法来判断中断源这一过程

最后,关于那位兄弟最后提的两个问题: 问题一, 正如那位兄弟所说的 , 是通过分析I_ISPR寄存器来识别发生的中断的. 而即便有多个中断同时发生, I_ISPR寄存器只有一位置位,

44B0的datasheet上面对此没有清楚的说明, 我认为那些中断源还是有优先级的, 在那些没有被INTMSK屏蔽的中断源中找优先级最高的中断

源, 然后在 I_ISPR寄存器中把相应位置位. 不过这只是偶的猜想, samsung的datasheet说的不清不楚的, 看的很是恼火.

问题二, 据datasheet上所说:

假如在向量模式下发生EINT0 时, 当ARM在0x18取指令时, interrupt controller将生成一条指令,该指令直接送给ARM执行,执行的结果就是使

程序跳转到EINT0的向量地址0x20. 还给出了该指令的机器码算法 0xea000000 +((<destination address> - <vector address> - 0x8)>>2). 那么据此, 我们就可以知道CPU是要执行0x18处的指令的, 按bootloader上所说,就是要先执行 subs pc,lr,#4 . 这个关于向量中断的地方有些特殊, 我想所以就需要subs pc,lr,#4这样处理吧 , 忘有明白的兄弟指点!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值