中断需要底层汇编接口的,ARM一般采用IRQ中断,三星片子的IRQ中断又分向量中断和非向量中断,就个人来讲是习惯是非向量中断,应该这样更直观,代码可读性更强
以44b0x提供的bsp包说起,下面是44b0x最先跑的汇编代码,上电后过程种会设置IRQ中断,下面代码基于timer0的时钟中断来记录说明
;****************************************************
;* START *
;****************************************************
ResetHandler
......
;****************************************************
;* 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]
......
1. 非向量中断
在main函数的port_init种初始化中断寄存器rINTCON的时候,必须选择rINTCON=0x05,Setup IRQ handler 汇编代码是注释掉的
b HandlerIRQ这是0x18的地址,在flash中,就是中断到来的时候的跳转函数,继续读汇编代码
HandlerIRQ HANDLER HandleIRQ 其实跳转函数是指向HandleIRQ
下面代码看到HandleIRQ # 4映射倒了一个地址,这个地址是根据sdram大小来计算的,山寨板这里地址是0xc7fff18
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
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
在应用代码中,同样计算出相应的地址
#define _ISR_STARTADDRESS 0xc7fff00 //GCS6:64M DRAM/SDRAM
#define pISR_IRQ (*(unsigned *)(_ISR_STARTADDRESS+0x18))
当中断到来时,实际跳转到0xc7fff18来处理的,在应用代码中
pISR_IRQ = (U32) UCOS_IRQHandler;
这样最终进入C_IRQHandler函数来解析出相应的中断处理函数
void C_IRQHandler(void)
{
U32 temp, i;
temp = rI_ISPR;
if (temp == 0)
return;
for (i = 0; i < 26; i++)
{
if (temp & 0x1 == 1)
{
break;
}
else
{
temp = temp >> 1;
}
}
if (i == 26)
{
return;
}
temp = i << 2;
((void(*) (void)) (*((U32 *) (_ISR_STARTADDRESS + 0x20 + temp)))) ();
}
比如timer0中断,就到地址
#define pISR_TIMER0 (*(unsigned *)(_ISR_STARTADDRESS+0x54))
而在应用代码中,肯定会事先指定中断处理函数的pISR_TIMER0= (unsigned)__vT0Interrupt;
0xc700000+0xff000+0xf20+temp 这就是非向量中断的流程
2. 三星默认是采用向量中断
在main函数的port_init种初始化中断寄存器rINTCON的时候,必须选择rINTCON=0x01,Setup IRQ handler 汇编代码是注释掉的;因为向量中断几乎都是汇编来实现的,所以他更快,但是完全是汇编代码,看起来也费劲
向量中断,有中断到来的时候,按理来说应该跳转到0x00000018,但是实际上跳转倒0x00000060
这就是向量中断和非向量中断的区别
再跳转到0x00000334,注意还是在flash中,因此还得归功于bootloader汇编类似宏调用HandlerTIMER0 HANDLER HandleTIMER0
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
上门的汇编就是这个宏实现,比如一个timer0发生,芯片会跳转到0x18处执行,先在0x18处取指,这时取到的指令已经不是b HandlerIRQ,b HandlerIRQ已经被芯片自动替换成了ldr pc,=HandlerTIMER0,然后芯片再执行此条指令,参考汇编:ldr pc,=HandlerTIMER0,0X20地址单元的指令是宏ldr pc,=HandlerTIMER0操作,HandlerEINT0宏对应底层汇编处理函数,函数一部分是ldr r0,=$HandleLabel,因而程序PC执行这个宏操作,一些汇编操作并把外部中断的函数的地址赋给r0(ldr r0,=$HandleLabel)
接着应用代码中,只需要pISR_TIMER0= (unsigned)__vT0Interrupt;就把中断挂上了
3. 非向量中断另外实现
还可以不采用pISR_IRQ跳转,直接利用汇编中跳转解析函数,在main函数的port_init种初始化中断寄存器rINTCON的时候,必须选择rINTCON=0x01,Setup IRQ handler 汇编代码必须打开;唯一的区别就是中断解析函数采用汇编实现的,其它都一样
;****************************************************
;* START *
;****************************************************
ResetHandler
......
;****************************************************
;* 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]
......
4. u-boot的中断
参考u-boot
5. 小结
44b0x中断一直搞了两个星期,每次中断一来程序就挂了,因为之前一直调试u-boot,烧录在flash中的是u-boot,u-boot的中断时跳到0x0c00 0000的二级中断;应该烧录44binit.s那个程序进去,44binit.s是跳转到0x0c7f ff00最顶端的位置,两个汇编代码不一样,跳转位置也不一样;可以把u-boot的二级中断跳转到0x0c7f ff00,就可以顺利加载了
网卡中断pISR_EINT1 = (unsigned) ne2k_isr;在 rINTMSK设置之前要设置好,要不然网卡中断来了还没处理函数,这个时候就挂了,切记----一定先挂中断函数,再配置rINTMSK = ~(BIT_GLOBAL | BIT_EINT4567 |BIT_TIMER0 |BIT_EINT1);打开中断