cubemx在使用freertos的時候爲何推薦使用除systick以外的timebase

摘要

第一次使用stm32cubemx,在配置freertos後生成代碼時會提示:

When FreeRTOS is used.It is strongly recommended to use a HAL timebase source other than the Systic

 

Why???

網上搜了下,結合相關源碼看了下,理清了思路.用一句話總結就是:防止在高優先級(優先級高於systick)中斷服務中調用HAL_Delay(),導致中斷服務忙等待,這樣任何優先級低於該中斷的中斷都得不到服務,當然也包括os的全部調度.

當然可能還有一些其他我想不到的原因,也歡迎小夥伴們提供寶貴信息.

 

分析:

stm32+freertos之所以要用到兩套timebase(一是freertos的心跳tick (os_tick),二是更底層的與freertos的api無關的HAL心跳tick (hal_tick),譬如systick (這個是強制的os_tick)和timer (譬如timer1,hal_tick)):

是因爲freertos強制使用systick作爲自己的心跳,且systick的優先級被強制設置爲最低;如果HAL的心跳也使用systick,也即sys_tick == hal_tick.那麼在某些情況下將產生我們不想看到的結果,譬如:

案例:

systick的中斷優先級爲最低的5,我們有個中斷int_a的優先級爲4,顯然int_a的優先級要高於systick,systick的中斷是不能夠搶佔int_a的.

考慮以下情形,int_a的中斷服務裏調用了HAL_Dealy(10),等待10個tick (HAL_Delay()內部是一個while循環,不斷的讀取當前的hal_tick來判斷是否到時間);hal_tick隨着時間的流失是不斷增長的,由於只有一個timebase源(systick),hal_tick增長的任務也就交給systick的中斷服務了,由於systick不能夠搶佔int_a,就導致了systick無法處理自己的中斷服務,hal_tick也就不會增長,int_a的HAL_Delay(10)也就永遠等不來自己返回的日子了.其結果就是int_a中斷無法返回,任何優先級低於此中斷的中斷都無法得到服務,當然也包括os的全部調度,因爲os的調度依賴與systick中斷.

正確的做法:

timer(譬如timer1)產生HAL心跳,systick產生freertos心跳.HAL是不依賴os API的一套硬件操作接口.

一般的HAL心跳每1ms發生一次

os_tick是如何工作的:

當配置了兩套時基時,systick作爲os的心跳,它的優先級應該配置成最低(cubemx爲我們實現了這一工作).這事因爲:

systick的中斷服務,主要處理一些os層面的東西,譬如查看是否有blocked的任務已經就緒了,然後執行任務切換等工作.作爲一個實時系統爲了保持實時性不打攪其他的中斷服務,stm32cubemx裏會強制systick的優先級爲最低,譬如我用的stmf107的systick的搶佔優先級爲15(最低).mcu運行過程中按照設定週期性地產生中斷,譬如設置爲100HZ那就是每10ms產生一次systick更新中斷.每一次中斷中都會增加sys_tick計數,執行一些os的操作,然後調度任務(調度的方法是trigger一個pensv中斷,這是一個優先級最低的中斷,他會等到其他中斷服務都執行完後,再處理自己的服務,獲取下一個執行的任務,服務返回時跳轉到該任務堆棧執行,這一塊還是看一下<cortex-M3權威指南>吧,不贅述了).

osDelay()這一freertos API就是參考sys_tick這一時基,任務的調度切換(或者說os系統層面)是基於這一時基的,我們可以通過cubemx來配置這一時基的週期,譬如100HZ

 

hal_tick是如何工作的:

爲了保證HAL時基的可靠,防止出現上面我們講的一直忙等待問題,強制設定它的優先級爲最高0,譬如我們用timer1作爲HAL時基(cubemx裏SYS部分配置).一般HAL時基一般是1ms,每1ms hal_tick計數加1(它的中斷服務也就只幹了這麼一件事).

HAL_Delay()這一HAL API就是參考hal_tick這一時基的.

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章