OS-Ucos Interrupt

    技术2022-05-20  29

    中断需要底层汇编接口的,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=0x05Setup 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=0x01Setup 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 HandlerIRQb HandlerIRQ已经被芯片自动替换成了ldr pc,=HandlerTIMER0,然后芯片再执行此条指令,参考汇编:ldr pc,=HandlerTIMER00X20地址单元的指令是宏ldr pc,=HandlerTIMER0操作,HandlerEINT0宏对应底层汇编处理函数,函数一部分是ldr r0,=HandleLabel,因而程序PC执行这个宏操作,一些汇编操作并把外部中断的函数的地址赋给r0ldr r0,=HandleLabel

    接着应用代码中,只需要pISR_TIMER0= (unsigned)__vT0Interrupt;就把中断挂上了

     

    3.        非向量中断另外实现

    还可以不采用pISR_IRQ跳转,直接利用汇编中跳转解析函数,在main函数的port_init种初始化中断寄存器rINTCON的时候,必须选择rINTCON=0x01Setup 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-bootu-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);打开中断

     


    最新回复(0)