初学ARM,犹如幼儿学步,蹒跚跌撞,始获得一点点站立的经验. 深恐日后忘却,故做了一些日记. 今日无事,整理一下,贴之于论坛,希望: 1) 于我一样在入门时迷茫的朋友,希冀能提供一点帮助,少走点弯路. 2) 于我理解的错误,希冀有高人指点一二. 3) 没有第3了,我刚才明明想到3点的,忘了,呵呵.
【开发环境】keil for arm 2.40a 【arm 芯片】LPC2138 =========================================================================== 2006/05/8 关于向量中断
Vectors: LDR PC,Reset_Addr LDR PC,Undef_Addr LDR PC,SWI_Addr LDR PC,PAbt_Addr LDR PC,DAbt_Addr NOP /* Reserved Vector */ ; LDR PC,IRQ_Addr LDR PC,[PC, #-0x0FF0] /* Vector from VicVectAddr */ LDR PC,FIQ_Addr
Reset_Addr: DD Reset_Handler Undef_Addr: DD Undef_Handler?A SWI_Addr: DD SWI_Handler?A PAbt_Addr: DD PAbt_Handler?A DAbt_Addr: DD DAbt_Handler?A DD 0 /* Reserved Address */ IRQ_Addr: DD IRQ_Handler?A FIQ_Addr: DD FIQ_Handler?A
为什么是 LDR PC,[PC,#-0x0FF0]? irq的向量号是6,中断时的PC地址是0x18. 基于ARM的机构,此指令<=>LDR PC,[0x20,#-0x0FF0] <=> LDR PC,[#-0x0FD0] 对32位数, -0x0FD0 = 0xFFFF F030. 这个就是向量中断地址寄存器的地址. 当向量中断irq中有某个中断源发生中断,VICVectAddr中存放的是那个发生中断的中断源 的ISR地址. 这样,LDR PC,[PC,#-0x0FF0]将自动跳转到ISR处理程序. VICVectAddr 0xFFFF F030 ... ... VICVectAddr0 0xFFFF F100 VICVectAddr0 0xFFFF F104 ... ... =========================================================================== 2006/05/9 中断嵌套的问题
对于采用VIC的芯片,有时候涉及到中断嵌套的问题. 比如我现在做的LED显示,VIC中断分配如下: TIMER1: 用做ARTX操作系统的时钟源. TIMER0: 用于LED显示扫描. UART0: 用做通讯. 这里的关键是: TIMER0必须没大约1ms中断一次,而每次扫描的时间从100us-400us不等. 为了不至于使UART的数据丢失,在TIMER0进入中断后,必须"立即"使能UART0的中断. 但UART0和TIMER0都是使用的同一个中断irq.当TIMER0进入中断后,PSR中的I位是自动置'1'了的. 也就是irq已经禁止了. 我强行打开I如何?但如果TIMER0没执行完毕,而UART0中断发生,势必会破坏寄存器的内容. 所以此时涉及到中断嵌套的问题.
keil建议的解决方案如下:
void timer0_srv (void) __irq { T0IR = 1; // Clear interrupt flag IENABLE; // allow nested interrupts longtimerdelay (); // 这里处理一段花费比较长时间的任务 IDISABLE; // disable interrupt nesting VICVectAddr = 0; // Acknowledge Interrupt } // Macros for Interrupt Nesting #define IENABLE /* Nested Interrupts Entry */ \ __asm { MRS LR, SPSR } /* Copy SPSR_irq to LR */ \ __asm { STMFD SP!, {LR} } /* Save SPSR_irq */ \ __asm { MSR CPSR_c, #0x1F } /* Enable IRQ (Sys Mode) */ \ __asm { STMFD SP!, {LR} } /* Save LR */ \
#define IDISABLE /* Nested Interrupts Exit */ \ __asm { LDMFD SP!, {LR} } /* Restore LR */ \ __asm { MSR CPSR_c, #0x92 } /* Disable IRQ (IRQ Mode) */ \ __asm { LDMFD SP!, {LR} } /* Restore SPSR_irq to LR */ \ __asm { MSR SPSR_cxsf, LR } /* Copy LR to SPSR_irq */ \
============================================================== |