ucos的中断向量表构建

今天又review了一下以前写过的ucos代码,发现ucos在重新setup中断向量表的操作xxxx
void OS_CPU_InitExceptVect (void)
{
(*(INT32U *)OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_UNDEF_INSTR_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptUndefInstrHndlr;
(*(INT32U *)OS_CPU_ARM_EXCEPT_SWI_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_SWI_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptSwiHndlr;
(*(INT32U *)OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_HANDLER_ADDR) = (INT32U)OS_CPU_ARM_ExceptPrefetchAbortHndlr;
(*(INT32U *)OS_CPU_ARM_EXCEPT_DATA_ABORT_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_DATA_ABORT_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptDataAbortHndlr;
(*(INT32U *)OS_CPU_ARM_EXCEPT_ADDR_ABORT_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_ADDR_ABORT_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptAddrAbortHndlr;
(*(INT32U *)OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptIrqHndlr;
(*(INT32U *)OS_CPU_ARM_EXCEPT_FIQ_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_FIQ_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptFiqHndlr;
}
大多数ARM 处理器都支持把RAM remap 到0x00000000 的地址上来,这样就给了重构中断向量提供了可能
ucos里通过调用这个函数就可以重新初始化0x00000000-0x0000003f 这段ram的内容,实际就是重构中断向量表.
以irq中断向量来说:
(*(INT32U *)OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR)=OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;
(*(INT32U *)OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR)= (INT32U)OS_CPU_ARM_ExceptIrqHndlr;
#define OS_CPU_ARM_INSTR_JUMP_TO_HANDLER0xE59FF018
OS_CPU_ARM_ExceptIrqHndlr //是ucos core中的一小段用asm写的irq例程.相当于函数入口地址
#define OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR(OS_CPU_ARM_EXCEPT_IRQ* 0x04 + 0x00)







#define OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR(OS_CPU_ARM_EXCEPT_IRQ* 0x04 + 0x20)
#define OS_CPU_ARM_EXCEPT_IRQ0x06 //irq 在8个中断向量里是number6,reset 是number0
先在irq 所在的number6中断向量上(地址是0x00000018) 写入" 0xE59FF018" 这样一个指令(LDR PC,[PC,0x18] 的指令码)
然后在 0x00000018+0x20 的地址处填上 ucos core 函数OS_CPU_ARM_ExceptIrqHndlr 的地址.
这样在产生irq中断后,PC会被弹到 0x00000018 来取指“0xE59FF018” 执行LDR PC,[PC,0x18] 的操作
这里 pc+0x18 的 位置正好是填充OS_CPU_ARM_ExceptIrqHndlr 的位置,使PC获得OS_CPU_ARM_ExceptIrqHndlr 的入口地址,然后调转过去,执行这个函数(实际是asm代码段)
在OS_CPU_ARM_ExceptIrqHndlr() 函数里
ucos会做保存上下文的操作,然后调用一个叫OS_CPU_ExceptHndlr的函数,这个函数实际上就是给用户中断处理程序的接口函数(call back),用户在自己的BSP c代码里要实现这个函数 完成针对于自己处理器中断控制器的ISR例程。
这个函数原型是,
void OS_CPU_ExceptHndlr (CPU_DATA except_type)
参数except_type 在asm里由R0传递过来,
值可能为:
#define OS_CPU_ARM_EXCEPT_RESET0x00
#define OS_CPU_ARM_EXCEPT_UNDEF_INSTR0x01
#define OS_CPU_ARM_EXCEPT_SWI0x02
#define OS_CPU_ARM_EXCEPT_PREFETCH_ABORT0x03
#define OS_CPU_ARM_EXCEPT_DATA_ABORT0x04
#define OS_CPU_ARM_EXCEPT_ADDR_ABORT0x05
#define OS_CPU_ARM_EXCEPT_IRQ0x06
#define OS_CPU_ARM_EXCEPT_FIQ0x07
#define OS_CPU_ARM_EXCEPT_NBR0x08
其实就是那8个中断向量number, 对于irq来说 是number6
--------------------------
这一点在ucos AN-1014 datasheet上也说得很
【ucos的中断向量表构建】Below is the sequence of events that take place when an IRQ occurs
(assuming the I-bit in the CPSR is 0):
The CPU switches mode to IRQ mode (MODE = 0x12);
The CPSR is saved into the SPSR_irq register;
The return address PC is saved into R14_irq (i.e. the Link Register of the IRQ mode);
The I-bit of the CPSR is set to 1 disabling further IRQs;
The PC is forced to address 0x00000018;
The PC is loaded with the address of OS_CPU_ARM_ExceptIrqHndlr() because of the
LDR PC,[PC,#0x18] instruction that we placed at address 0x00000018.
The CPU executes the code in OS_CPU_ARM_ExceptIrqHndlr(), then
OS_CPU_ARM_ExceptHndlr() (found in OS_CPU_A.S).
OS_CPU_ARM_ExceptHndlr() calls OS_CPU_ExceptHndlr() (found in BSP.C) to
determine the source of the interrupt and handle it accordingly.
When OS_CPU_ARM_ExceptHndlr() returns from OS_CPU_ExceptHndlr(), it calls
OSIntExit() (in case of task interrupted) which determines whether there has been a
more important task that has been made ready to run by the exception handler or,
whether we simply need to return to the interrupted task.
If the interrupted task is still the highest priority task, OSIntExit() returns to
OS_CPU_ARM_ExceptHndlr() which simply returns to this task.
If there is a more important task, OSIntExit() calls OSIntCtxSw() (see OS_CPU_A.S) which
takes care of switching to the more important task.

    推荐阅读