一、系統時鍾
rt-thread的系統時鍾模塊采用全局變量rt_tick作為系統時鍾節拍,該變量在系統時鍾中斷函數中不斷加1。而系統時鍾中斷源和中斷間隔一般由MCU硬件定時器(如stm32的嘀嗒定時器)決定,rt_tick初始值為0,每次MCU產生硬件定時中斷后,在中斷函數中不斷加1,即rt_tick變量值與MCU硬件定時器定時中斷間隔的乘積為系統真正運行時間(例如rt_tick=10,stm32嘀嗒定時器每隔1ms產生中斷,則系統上電運行時間為10ms)。
在bsp/stm32f40x/drivers/board.c中設置MCU硬件定時器定時間隔,以及執行相應定時器中斷函數:
void SysTick_Configuration(void) { RCC_ClocksTypeDef rcc_clocks; rt_uint32_t cnts; RCC_GetClocksFreq(&rcc_clocks);//獲得系統的晶振頻率
//RT_TICK_PER_SECOND在rtconfig.h中配置,表示每秒包含的系統時鍾節拍數。默認配置為100,則嘀嗒定時器中斷間隔為10ms,rt_tick每隔10ms加1,即默認情況下1s內包含100個系統時鍾節拍,每個時鍾節拍tick表示10ms。為了提高 精度,一般修改宏定義為1000,即1s內包含1000個系統時鍾節拍(此時嘀嗒定時器中斷間隔為1ms,每個時鍾節拍tick則表示1ms)。
cnts = (rt_uint32_t)rcc_clocks.HCLK_Frequency / RT_TICK_PER_SECOND;
cnts = cnts / 8;
SysTick_Config(cnts); //配置系統tick,函數在core_cm4.h中實現,使能嘀嗒定時器中斷、定時器時鍾源頻率HCLK=168MHZ、啟動嘀嗒定時器 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//配置定時器時鍾源,函數在misc.c中實現,將定時器時源鍾頻率設置為HCLK/8=21MHZ } void SysTick_Handler(void) { /* enter interrupt */ rt_interrupt_enter();//表示進入中斷,在src/irp.c中定義,中斷嵌套計數器rt_interrupt_nest加1 rt_tick_increase(); //rt_tick加1,並檢查當前運行線程的剩余時間片是否耗盡,若耗盡則讓出處理器並重新調度線程,接着執行硬件定時器中斷模式下的定時器超時檢查rt_timer_check(); /* leave interrupt */ rt_interrupt_leave();//表示進入中斷,在src/irp.c中定義,中斷嵌套計數器rt_interrupt_nest減1
}
二、硬件定時器中斷模式下線程調度驅動
在src/clock.c中:
void rt_tick_increase(void) { struct rt_thread *thread; /* increase the global tick */ ++ rt_tick; //全局變量系統時鍾節拍數加1 /* check time slice */ thread = rt_thread_self(); //獲取當前運行的線程 -- thread->remaining_tick; //當前運行線程的剩余時間片減1 if (thread->remaining_tick == 0)//如果當前運行線程無剩余時間 { /* change to initialized tick */ thread->remaining_tick = thread->init_tick;//重新將線程的剩余時間片設置為初始化時間片 /* yield */ rt_thread_yield();//將此線程從調度器就緒隊列中取出來放到同優先級線程鏈表末尾,然后再次調度 } /* check timer */ rt_timer_check();//檢查定時器鏈表上是否有時間到達的時鍾,即包括自定義的定時器,也包括線程睡眠時啟動的線程定時器 }
由上述代碼可見,一旦系統產生時鍾中斷,在嘀嗒定時器中斷函數中,系統首先將檢查當前正在運行的線程剩余時間片是否耗盡,如果耗盡則將其從調度器就緒隊列中取出放到同優先級線程鏈表末尾,然后再重新調度線程;接着檢查是否有休眠的線程時間到達(即線程睡眠時啟動的線程定時器是否超時),如果有則觸發相應的線程定時器超時函數rt_thread_timeout(將當前掛起的線程加入到調度器就緒隊列后重新調度),從而將線程從睡眠中喚醒。
總而言之,在硬件定時器中斷模式下,系統時鍾中斷(MCU硬件定時器中斷或嘀嗒定時器中斷)是rt-thread線程調度的驅動力。
三、軟件定時器線程模式下線程調度驅動
若在rtconfig.h中定義了宏RT_USING_TIMER_SOFT,則使用軟件定時器線程模式,此模式下系統中存在定時器線程timer_thread(在rt_system_timer_thread_init中初始化)。在此線程入口函數中通過rt_tick的增加不停地檢查定時器鏈表中是否有定時器超時,其中也包含線程睡眠時啟動的線程定時器,一旦線程對應的定時器超時,則觸發相應的線程定時器超時函數rt_thread_timeout(將當前掛起的線程加入到調度器就緒隊列后重新調度),從而將線程從睡眠中喚醒。
由此可見,在軟件定時器線程模式下,rt_system_timer_thread_init中初始化的定時器線程timer_thread就是rt-thread線程調度的驅動力。