基于ADuC7026的uCOS-II系统分析

本文分析了uCOS-II实时操作系统在ADuC7027平台上的移植细节,包括中断处理流程、时钟配置以及任务切换机制等关键部分。
下面是在Micrium公司网站上下载的基于ADuC7027平台运行的uCOS-II操作系统代码的简单分析。
一、中断分析
当CPU收到中断信号在本指令执行完后立即响应中断,其响应过程如下:
CPU收到中断信号→当前指令执行完成→程序寄存器PC根据中断种类跳入中断向量表中→根据中断向量表进入中断服务函数.
uCOS-II的中断向量表代码如下:
            PRESERVE8
                AREA    RESET, CODE, READONLY
                ARM
Vectors
                LDR     PC, Reset_Addr
                LDR     PC, Undef_Addr
                LDR     PC, SWI_Addr
                LDR     PC, Prefetch_Addr
                LDR     PC, Abort_Addr
                NOP
		LDR 	PC, IRQ_Addr
		LDR 	PC, FIQ_Addr

Reset_Addr      DCD     Reset_Handler
Undef_Addr      DCD     OS_CPU_ARM_ExceptUndefInstrHndlr
SWI_Addr       	DCD     OS_CPU_ARM_ExceptSwiHndlr
Prefetch_Addr   DCD     OS_CPU_ARM_ExceptPrefetchAbortHndlr
Abort_Addr      DCD     OS_CPU_ARM_ExceptDataAbortHndlr
                NOP
IRQ_Addr       	DCD     OS_CPU_ARM_ExceptIrqHndlr
FIQ_Addr       	DCD     OS_CPU_ARM_ExceptFiqHndlr

中断服务函数OS_CPU_ARM_ExceptIrqHndlr的代码如下:
    		AREA CODE, CODE, READONLY
    		CODE32
OS_CPU_ARM_ExceptIrqHndlr
    		SUB     LR, LR, #4         	; LR offset to return from this exception: -4.
    		STMFD   SP!, {R0-R12, LR}  	; Push working registers.
    		MOV     R3, LR           	; Save link register.
    		MOV     R0, #OS_CPU_ARM_EXCEPT_IRQ
    		B       OS_CPU_ARM_ExceptHndlr 
 
OS_CPU_ARM_ExceptHndlr的代码如下:
    		AREA CODE, CODE, READONLY
    		CODE32
OS_CPU_ARM_ExceptHndlr
    		MRS     R1, SPSR     	; Save CPSR (i.e. exception's SPSR).
					;DETERMINE IF WE INTERRUPTED A TASK OR ANOTHER LOWER PRIORITY EXCEPTION:
					;SPSR.Mode = SVC                :  task,                                             
					;SPSR.Mode = FIQ, IRQ, ABT, UND :  other exceptions,
					;SPSR.Mode = USR                : *unsupported state*.
		AND     R2, R1, #OS_CPU_ARM_MODE_MASK
    		CMP     R2,     #OS_CPU_ARM_MODE_SVC
    		BNE     OS_CPU_ARM_ExceptHndlr_BreakExcept

OS_CPU_ARM_ExceptHndlr_BreakExcept的代码如下:
OS_CPU_ARM_ExceptHndlr_BreakExcept
    		MRS     R2, CPSR             ; Save exception's CPSR.
                                                                ; Change to SVC mode & disable interruptions.
    		MSR     CPSR_c, #(OS_CPU_ARM_CONTROL_INT_DIS | OS_CPU_ARM_MODE_SVC)

                                                                ; HANDLE NESTING COUNTER:
    		LDR     R3, __OS_IntNesting                                 ;   OSIntNesting++;
    		LDRB    R4, [R3]
    		ADD     R4, R4, #1
    		STRB    R4, [R3]

    		MSR     CPSR_cxsf, R2                           ; RESTORE INTERRUPTED MODE.
                                                                ; EXECUTE EXCEPTION HANDLER:
    		LDR     R3, __OS_CPU_ExceptHndlr                ; OS_CPU_ExceptHndlr(except_type = R0);
    		MOV     LR, PC
    		BX      R3
                                                                ; Change to SVC mode & disable interruptions.
    		MSR     CPSR_c, #(OS_CPU_ARM_CONTROL_INT_DIS | OS_CPU_ARM_MODE_SVC)

                                                                ; HANDLE NESTING COUNTER:
    		LDR     R3, __OS_IntNesting                     ;   OSIntNesting--;
    		LDRB    R4, [R3]
    		SUB     R4, R4, #1
    		STRB    R4, [R3]

    		MSR     CPSR_cxsf, R2                           ; RESTORE INTERRUPTED MODE.
                                                                ; RESTORE OLD CONTEXT:
    		LDMFD   SP!, {R0-R12, PC}^                      ; Pull working registers and return from exception.
OS_CPU_ExceptHndlr函数的代码如下:
void  OS_CPU_ExceptHndlr (CPU_DATA  except_type)
{
    CPU_FNCT_VOID  pfnct;
    CPU_INT32U     irq_sig;
    CPU_INT32U     irq_en;
    CPU_INT08U     byte_low;
    CPU_INT08U     byte_mid;
    CPU_INT08U     byte_high;
    CPU_INT08U     src;
                                                                        /* If this exception is an IRQ.                 */
    if (except_type == OS_CPU_ARM_EXCEPT_IRQ) {
        irq_en   = IRQEN;
        irq_sig  = IRQSIG;
        irq_sig &= irq_en;
                                                                        /* Handle 1st byte ...                          */
        byte_low = (CPU_INT08U)(irq_sig & 0xFF);
        while (byte_low != 0) {
            src = BSP_UnMapTbl[byte_low];
            if (src > 0) {
                pfnct = BSP_IntVectTbl[src];
                if (pfnct != (CPU_FNCT_VOID)0) {
                    (*pfnct)();
                }
            }
            byte_low &= ~(1 << src);
        }
                                                                        /* Handle 2nd byte ...                          */
        byte_mid = (CPU_INT08U)((irq_sig >> 8) & 0xFF);
        while (byte_mid != 0) {
            src   = BSP_UnMapTbl[byte_mid];
            pfnct = BSP_IntVectTbl[src + 8];
            if (pfnct != (CPU_FNCT_VOID)0) {
                (*pfnct)();
            }
            byte_mid &= ~(1 << src);
        }
                                                                        /* Handle 3rd byte ...                          */
        byte_high = (CPU_INT08U)((irq_sig >> 16) & 0xFF);
        while (byte_high != 0) {
            src   = BSP_UnMapTbl[byte_high];
            pfnct = BSP_IntVectTbl[src + 16];
            if (pfnct != (CPU_FNCT_VOID)0) {
                (*pfnct)();
            }
            byte_high &= ~(1 << src);
        }

    } else {
                                                                /* Infinite loop on other exceptions.                       */
                                                                /* Should be replaced by other behavior (reboot, etc.)      */
        while (DEF_TRUE) {
            ;
        }
    }
}

BSP_IntVectTbl表是记录中断服务函数的地址指针,其声明形式如下:
typedef void (*CPU_FNCT_VOID)(void);
static  CPU_FNCT_VOID  BSP_IntVectTbl[24];

二、	时钟分析
#define  MAIN_OSC_FRQ   	41780000L
CPU_INT32U  BSP_CPU_ClkFreq (void)
{
    CPU_INT08U  clk_div_bits;
    CPU_INT08U  clk_div;
    CPU_INT32U  clk_freq;
    clk_div_bits = (POWCON & 0x07);
    clk_div      = 1 << clk_div_bits;
    clk_freq     = MAIN_OSC_FRQ / clk_div;
    return (clk_freq);
}
static  void  BSP_Tmr_TickInit (void)
{
    CPU_INT32U  clk_freq;


    BSP_IntVectSet(BSP_IRQ_TIMER0, Tmr_TickISR_Handler);

    T0CON    = DEF_BIT_06                                       /* Periodic mode.                                       */
             | DEF_BIT_03;                                      /* Prescaler = 256.                                     */

    clk_freq = BSP_CPU_ClkFreq();

    T0LD     = clk_freq / 256 / OS_TICKS_PER_SEC;               /* Assign load value.                                   */

    T0CON   |= DEF_BIT_07;                                      /* Enable timer.                                        */

    BSP_IntEn(BSP_IRQ_TIMER0);
}

三、任务切换
任务切换是通过改变程序寄存器的值使高优先级的任务获得CPU使用权的。当然,任务切换之前需要保存前一任务的现场,恢复即将执行任务的现场。任务切换代码如下:
    AREA CODE, CODE, READONLY
    CODE32

OSCtxSw
                                                                ; SAVE CURRENT TASK'S CONTEXT:
    STMFD   SP!, {LR}                                           ;     Push return address,	   //满栈递减,将链接寄存器内容拷入堆栈中
    STMFD   SP!, {LR}
    STMFD   SP!, {R0-R12}                                       ;     Push registers,		   //将寄存器内容拷入堆栈中
    MRS     R0, CPSR                                            ;     Push current CPSR,
    TST     LR, #1                                              ;     See if called from Thumb mode,
    ORRNE   R0, R0, #OS_CPU_ARM_CONTROL_THUMB                   ;     If yes, set the T-bit.
    STMFD   SP!, {R0}

    LDR     R0, __OS_TCBCur                                     ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R0]
    STR     SP, [R1]

    LDR     R0, __OS_TaskSwHook                                 ; OSTaskSwHook();
    MOV     LR, PC
    BX      R0

    LDR     R0, __OS_PrioCur                                    ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, __OS_PrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    LDR     R0, __OS_TCBCur                                     ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, __OS_TCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]

    LDR     SP, [R2]                                            ; SP = OSTCBHighRdy->OSTCBStkPtr;

                                                                ; RESTORE NEW TASK'S CONTEXT:
    LDMFD   SP!, {R0}                                           ;    Pop new task's CPSR,
    MSR     SPSR_cxsf, R0

    LDMFD   SP!, {R0-R12, LR, PC}^                              ;    Pop new task's context.
一般的任务都会在无限循环中增加OSTimeDly()函数,用于时间延迟,但此函数中也调用了OS_Sched()将CPU使用权切换到就绪表中任务优先级最高的任务中,此过程的实现主要是调用上面函数的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值