/**********************************戰(zhàn)艦版實例**************************************/
P80:μc/osⅡ時鐘 硬件定時器中斷(使用了STM32中的Systick中斷)每產(chǎn)生一次,μc/osⅡ時鐘就會進入一次系統(tǒng)中斷服務(wù)程序(OSTickISR()),系統(tǒng)中斷服務(wù)程序通過調(diào)用OSTimeTick()來完成系統(tǒng)每個時鐘節(jié)拍所要完成的工作(包括遍歷每個任務(wù)控制塊將其延時參數(shù)減1等)。 任哲版教材P87鉤子函數(shù)在戰(zhàn)艦的對應(yīng)源碼: 鉤子函數(shù)的使用(以O(shè)STimerTickHook為例): 需要到os_cfg.h中把這兩個宏#define成>0。 P88:OSTimeDly在OSTimeDly中完成OSTCBCur->OSTCBDly(任務(wù)延時寄存器)的寫入并進行一次任務(wù)切換:
關(guān)于 μc/osⅡ的疑難: ·μc/osⅡ的時鐘OSTimeTick()是怎么與STM32的SysTick關(guān)聯(lián)起來的? 戰(zhàn)艦開發(fā)板配套程序中在main()中有delay_init()(delay.c下)函數(shù),其原代碼如下: void delay_init() { #ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了. u32 reload; #endif SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //選擇外部時鐘 HCLK/8 fac_us=SystemCoreClock/8000000; //為系統(tǒng)時鐘的1/8 #ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定義了,說明使用ucosII了. reload=SystemCoreClock/8000000; //每秒鐘的計數(shù)次數(shù) 單位為K reload*=1000000/OS_TICKS_PER_SEC;//根據(jù)OS_TICKS_PER_SEC設(shè)定溢出時間 //reload為24位寄存器,最大值:16777216,在72M下,約合1.86s左右 fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延時的最少單位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //開啟SYSTICK中斷 SysTick->LOAD=reload; //每1/OS_TICKS_PER_SEC秒中斷一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //開啟SYSTICK #else fac_ms=(u16)fac_us*1000;//非ucos下,代表每個ms需要的systick時鐘數(shù) #endif } 可見delay_init()開啟了STM32的SYSTICK中斷,下面繼續(xù)找SYSTICK的中斷服務(wù)程序(同樣也在delay.c),代碼如下: void SysTick_Handler(void) { OSIntEnter(); //進入中斷,其作僅僅是將判斷中斷層數(shù)是否達到255否則OSIntNesting++ OSTimeTick(); //調(diào)用ucos的時鐘服務(wù)程序 OSIntExit(); //觸發(fā)任務(wù)切換軟中斷 } 發(fā)現(xiàn)OSTimeTick(); 在 SYSTICK的中斷服務(wù)程序被調(diào)用,現(xiàn)在μc/osⅡ的時鐘OSTimeTick()就與STM32的SysTick關(guān)聯(lián)了起來。 OSIntExit (void)的作用除了執(zhí)行了OSIntNesting--之外 還進行了一次中斷級任務(wù)調(diào)度OSIntCtxSw() 。 ·OSIntCtxSw()切換任務(wù)的原理: Step1:SIntCtxSw()觸發(fā)了一次軟件中斷,代碼如下 ;/************************************************************************************** ;* 函數(shù)名稱: OSIntCtxSw ;* 功能描述: 中斷級任務(wù)切換(其實是進行了一次軟件中斷) ;* 參 數(shù): None ;* 返 回 值: None ;***************************************************************************************/ OSIntCtxSw PUSH {R4, R5} LDR R4, =NVIC_INT_CTRL ;觸發(fā)PendSV異常 (causes context switch) ;NVIC_INT_CTRL就是軟件中斷控制寄存器 LDR R5, =NVIC_PENDSVSET ;NVIC_PENDSVSET是觸發(fā)軟件中斷的值. STR R5, [R4] ;將R5中的字?jǐn)?shù)據(jù)寫入以R4為地址的存儲器中就發(fā)生了PendSV中斷 POP {R4, R5} BX LR NOP Step2:執(zhí)行完了step后會進入軟件中斷服務(wù)函數(shù),代碼(在os_cpu_aasm中)如下 ;/************************************************************************************** ;* 函數(shù)名稱: OSPendSV ;* ;* 功能描述: 該函數(shù)實際上完成了cpu各寄存器的壓棧和新任務(wù)堆棧向cpu的進棧; ;* 參 數(shù): None ;* ;* 返 回 值: None ;***************************************************************************************/ PendSV_Handler ;軟件中斷服務(wù)函數(shù) CPSID I ; Prevent interruption during context switch MRS R0, PSP ; PSP is process stack pointer 如果在用PSP堆棧,則可以忽略保存寄存器,參考CM3權(quán)威中的雙堆棧-白菜注 CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time SUBS R0, R0, #0x20 ; Save remaining regs R4-11 on process stack STM R0, {R4-R11} LDR R1, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP; =OSTCBCur就是取的OSTCBCur ;首地址,即任務(wù)控制塊的堆棧。 LDR R1, [R1] STR R0, [R1] ; R0 is SP of process being switched out
|