The following is a simple analysis of UCOS-II operating system code that is run on the ADuC7027 platform, which is downloaded on the Micrium company website.
I. Interrupt analysis when the CPU receives an interrupt signal and responds to an interrupt immediately after the execution of this instruction, the response process is as follows: The CPU receives the interrupt signal → The current instruction execution completes → The program register PC jumps into the interrupt vector table according to the interrupt type → enters the interrupt service function according to the interrupt vector table.
The Ucos-ii interrupt vector table code is as follows: 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_AR M_EXCEPTDATAABORTHNDLR NOP irq_addr DCD os_cpu_arm_exceptirqhndlr fiq_addr DCD OS_CP The code for the U_ARM_EXCEPTFIQHNDLR Interrupt service function OS_CPU_ARM_EXCEPTIRQHNDLR is as follows: Area code, code, READONLY CODE32 os_cpu_arm_except IRQHNDLR 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 code is as follows: Area code, C ODE, READONLY CODE32 os_cpu_arm_excepthndlr MRS R1, SPSR;
Save CPSR (i.e exception ' s SPSR). ;D etermine 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_brea The code for Kexcept os_cpu_arm_excepthndlr_breakexcept is as follows: 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.
The code for the OS_CPU_EXCEPTHNDLR function is as follows: 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 are 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 >>) & 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 is replaced by other Behav IOR (reboot, etc.)
*/while (def_true) {;
}}} The Bsp_intvecttbl table is the address pointer that records the interrupt service function, which is declared as follows: typedef void (*cpu_fnct_void) (void);
Static Cpu_fnct_void bsp_intvecttbl[24];
Second, clock analysis #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); The task switching task switch is to make the high priority task get the CPU rights by changing the value of the program register. Of course, before the task is switched on, you need to save the site of the previous task and resume the upcoming task.
The task switch code is as follows: Area code, code, READONLY CODE32 OSCTXSW ; SAVE Current TASK ' S context:stmfd sp!, {LR}; Push return address,//full stack decrement, copy the link register contents into the stack stmfd sp!, {LR} stmfd sp!, {r0-r12} ; Push registers,//Copy the contents of the register into the stack 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] LdrR0, __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. The general task is to add the ostimedly () function to the infinite loop for time delay, but this function also calls os_sched () to switch the CPU usage to the task with the highest priority in the ready table, the implementation of which is primarily the result of invoking the function above.