搜了好多网上的文章,有说u-boot不支持中断的,有说支持的,众说纷纭,反正我的u-boot-1.1.6中断处理不好使。
本文以arm7为例,分析一下arm7的u-boot中断处理,并提出一些疑问,希望高手们给出准确答案。
首先说一下不拷贝u-boot代码到SDRAM中去的情况,此时在地址0x00开始的FLASH中运行
1. arm7处理器上电后的状态为0x13supervisor模式,且禁止IRQ和FIQ,同时在arm状态。u-boot在reset后并没有改变arm7的模式,也没有打开IRQ和FIQ状态位,所以照此状态运行下去是不会响应任何中断的。所以我在reset后将arm7的工作模式改为0x1f的系统模式,并使能中断位。
2. LPC2468的arm7处理器中断向量表可以进行重新影射到0x00的FLASH、0x40000000的SRAM、0x80000000的片外存储器,通过寄存器MEMMAP来指定。我觉得正常情况下arm7的中断响应地址就是在0x00000018的位置,其他arm处理器是否也可以重新映射中断向量表不是很清楚?
3.中断处理程序的设计。首先要声明的是arm在响应中断进入0x00000018时自动禁止CPSR中的中断位,在退出中断处理程序后自动使能中断位。
(1)LPC2468的0x00000018位置是这样一条语句LDR PC,[PC,#-0x0120],目的是将PC=0x00000018+8-0x0120=0xffffff00,此地址为装有中断处理程序首地址的中断控制器寄存器地址,通过将PC切换到该地址,进入注册的中断处理程序。公式中的8是代表arm7位3级流水,PC为当前指令地址+8。
(2)因为在keil环境下,声明中断处理程序需要在函数名旁边加入__irq标志,
如void __irq xxx_irqhandler(void),该标志作用是通知keil编译器在编译中断处理程序时自动加入保护现场的语句。如果没有__irq标志,则程序不能正常运行。解决keil中不加入__irq标志注册中断程序的方法是自己编写保护现场语句,方法是:
LDR PC,irqhandle /*将0x0018处改为这句*/
irqhandle DCD myirq /*定义irqhandle标号*/
irq_stack DCD 0x40004000 /*定义中断栈区地址 */
EXPORT myirq /*声明标号myirq*/
myirq
stmdb r13!, {r14} /*保存中断地址*/
stmdb r13!, {r0} /*保存要使用的寄存器*/
stmdb r13!, {r8}
ldr r0, IRQ_STACK /*此时已进入IRQ模式,设置该模式栈指针*/
mov sp, r0
mvn r8, #255 /*将PC切换到地址0xffffff00,中断处理程序入口地址*/
ldr r8, [r8]
mov lr,pc /*手动保存返回地址*/
mov pc, r8
ldmia r13!, {r8} /*恢复的顺序要与保存时相反*/
ldmia r13!, {r0}
ldmia r13!, {r14}
subs pc, lr, #0x04 /*arm中断处理要求的必须返回到程序中断处的指令重新执行*/
同时不要忘记修改arm的CPSR,使能中断位。
(3)经过(2)的修改u-boot在不拷贝代码的情况下可以处理中断,但拷贝代码到SDRAM后只能进入一次中断后跑飞。
疑问1:怀疑是否是代码拷贝的情况下程序链接地址与执行的中断代码有关造成在低地址处执行了链接地址处的代码,发生错误?
疑问2:myirq中的代码应该与链接地址无关,PC切换后又进入了SDRAM执行中断处理程序,此代码也与链接地址匹配,难道是0x0018处的语句中的PC和链接地址一致而不是我们认为的0x00000018,造成程序跑飞?
疑问3:u-boot中start.S的代码最后是一条bl do_irq语句进入中断处理程序,但LPC2468的flash地址为0x00开始,sdram为0xa0000000开始,bl指令只能正负32M范围调转,它是如何进入SDRAM的呢?u-boot又会如何实现代码拷贝的中断处理跳转?
阅读(2734) | 评论(0) | 转发(0) |