不知道是哪位兄弟写的<<关于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这样处理吧 , 忘有明白的兄弟指点! |