【STM32F429】第16章 ThreadX原裝任務統計分析功能實現(含IAR的ThreadX外掛使用)
論壇原始地址(持續更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514
第16章 ThreadX原裝任務統計分析功能實現(含IAR的ThreadX外掛使用)
本章節為大家講解ThreadX原裝任務統計分析功能的實現,支援MDK,IAR和GCC。
16.1 ThreadX的任務統計分析實現原理
16.2 ThreadX的任務統計分析功能移植
16.3 IAR的ThreadX外掛實現
16.4 實驗例程說明
16.5 總結
16.1 ThreadX的任務統計分析實現原理
對於Cortex-M核心,帶有DWT時鐘週期計數器,比如晶片主頻是100MHz,那麼DWT統計的時鐘週期解析度就是10ns。
ThreadX就是藉助此功能實現任務統計分析,使用簡單,僅需使能就可以使用。M3,M4和M7核心都帶這個功能,而M0核心不帶,使用中要注意。
16.2 ThreadX的任務統計分析功能移植
這裡以移植到MDK為例進行說明,其它IAR,GCC的移植方法是一樣的。
16.2.1 新增任務分析程式碼
從ThreadX 核心V6.1.7版本開始,加入了任務統計分析功能,位於原始碼軟體包的如下路徑:
ThreadX\utility\execution_profile_kit 。
按照前面章節的移植方法,升級ThreadX核心的版本到V6.1.7後,新增此檔案即可。
別忘了新增相應路徑:
16.2.2 設定巨集定義
C檔案要新增巨集定義:TX_EXECUTION_PROFILE_ENABLE, TX_CORTEX_M_EPK
彙編檔案要新增巨集定義:TX_EXECUTION_PROFILE_ENABLE,TX_ENABLE_EXECUTION_CHANGE_NOTIFY
對於MDK AC5,Misc Controls加上 –cpreproc
16.2.3 使能DWT時鐘週期計時器
預設情況下,ThreadX的移植檔案tx_initialize_low_level.s帶了DWT時鐘週期計數器的使能:
/* Enable the cycle count register. */ LDR r0,=0xE0001000 ; Build address of DWT register LDR r1, [r0] ; Pickup the current value ORR r1, r1, #1 ; Set the CYCCNTENA bit STR r1, [r0] ; Enable the cycle count register
保險起見,在bsp.c檔案也呼叫了函式bsp_InitDWT()做初始化。
16.2.4 展示任務統計方法
Threadx提供了三個64bit的全域性變數統計時間資訊,單位是系統時鐘計數器,比如主頻是100MHz,那麼單位就是10ns。
- _tx_execution_thread_time_total
統計從上電開始,所有任務總的執行時間。
- _tx_execution_idle_time_total
統計從上電開始,總的空閒時間。
- _tx_execution_isr_time_total
統計從上電開始,中斷服務程式總的執行實現。
為了方便統計CPU利用率,可以採用:
_tx_execution_thread_time_total/(_tx_execution_thread_time_total + _tx_execution_idle_time_total + _tx_execution_isr_time_total)
但這種統計不能反應CPU利用率瞬時變化,所以做了一個瞬時的統計方法,每200ms統計一次:
/* ********************************************************************************************************* * 函 數 名: AppTaskStart * 功能說明: 啟動任務。 * 形 參: thread_input 是在建立該任務時傳遞的形參 * 返 回 值: 無 優 先 級: 2 ********************************************************************************************************* */ static void AppTaskStart (ULONG thread_input) { EXECUTION_TIME TolTime, IdleTime, deltaTolTime, deltaIdleTime; uint32_t uiCount = 0; (void)thread_input; /* 核心開啟後,恢復HAL裡的時間基準 */ HAL_ResumeTick(); /* 外設初始化 */ bsp_Init(); /* 建立任務 */ AppTaskCreate(); /* 建立任務間通訊機制 */ AppObjCreate(); /* 計算CPU利用率 */ IdleTime = _tx_execution_idle_time_total; TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total; while (1) { /* 需要週期性處理的程式,對應裸機工程呼叫的SysTick_ISR */ bsp_ProPer1ms(); /* CPU利用率統計 */ uiCount++; if(uiCount == 200) { uiCount = 0; deltaIdleTime = _tx_execution_idle_time_total - IdleTime; deltaTolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total - TolTime; OSCPUUsage = (double)deltaIdleTime/deltaTolTime; OSCPUUsage = 100- OSCPUUsage*100; IdleTime = _tx_execution_idle_time_total; TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total; } tx_thread_sleep(1); } }
任務資訊統一通過函式DispTaskInfo進行列印:
/* ********************************************************************************************************* * 函 數 名: DispTaskInfo * 功能說明: 將ThreadX任務資訊通過串列埠打印出來 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ static void DispTaskInfo(void) { TX_THREAD *p_tcb; /* 定義一個任務控制塊指標 */ p_tcb = &AppTaskStartTCB; /* 列印標題 */ App_Printf("===============================================================\r\n"); App_Printf("CPU利用率 = %5.2f%%\r\n", OSCPUUsage); App_Printf("任務執行時間 = %.9fs\r\n", (double)_tx_execution_thread_time_total/SystemCoreClock); App_Printf("空閒執行時間 = %.9fs\r\n", (double)_tx_execution_idle_time_total/SystemCoreClock); App_Printf("中斷執行時間 = %.9fs\r\n", (double)_tx_execution_isr_time_total/SystemCoreClock); App_Printf("系統總執行時間 = %.9fs\r\n", (double)(_tx_execution_thread_time_total + \ _tx_execution_idle_time_total + \ _tx_execution_isr_time_total)/SystemCoreClock); App_Printf("===============================================================\r\n"); App_Printf(" 任務優先順序 任務棧大小 當前使用棧 最大棧使用 任務名\r\n"); App_Printf(" Prio StackSize CurStack MaxStack Taskname\r\n"); /* 遍歷任務控制列表TCB list),列印所有的任務的優先順序和名稱 */ while (p_tcb != (TX_THREAD *)0) { App_Printf(" %2d %5d %5d %5d %s\r\n", p_tcb->tx_thread_priority, p_tcb->tx_thread_stack_size, (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_ptr, (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_highest_ptr, p_tcb->tx_thread_name); p_tcb = p_tcb->tx_thread_created_next; if(p_tcb == &AppTaskStartTCB) break; } }
效果:
16.3 IAR的ThreadX外掛實現
IAR和MDK的實現一樣,移植了V6.1.7或者以上版本後,新增統計分析檔案即可,剩下就是使能IAR的ThreadX外掛:
- 第1步,使能ThreadX外掛:
- 第2步,進入除錯狀態,新增ThreadX元件,大家可以更新需要選擇展現那些資訊:
- 第3步,先全速執行,然後點選暫停才可以檢視資訊,效果如下:
16.4 實驗例程
配套例子:
V6-3011_ThreadX Task Statistics
實驗目的:
- ThreadX原裝任務統計分析功能
實驗內容:
1、共建立瞭如下幾個任務,通過按下按鍵K1可以通過串列埠或者RTT列印任務堆疊使用情況
========================================================
CPU利用率 = 0.89%
任務執行時間 = 0.586484645s
空閒執行時間 = 85.504470575s
中斷執行時間 = 0.173225395s
系統總執行時間 = 86.264180615s
=======================================================
任務優先順序 任務棧大小 當前使用棧 最大棧使用 任務名
Prio StackSize CurStack MaxStack Taskname
2 4092 303 459 App Task Start
5 4092 167 167 App Msp Pro
4 4092 167 167 App Task UserIF
5 4092 167 167 App Task COM
0 1020 191 191 System Timer Thread
串列埠軟體可以使用SecureCRT或者H7-TOOL RTT檢視列印資訊。
App Task Start任務 :啟動任務,這裡用作BSP驅動包處理。
App Task MspPro任務 :訊息處理,這裡用作LED閃爍。
App Task UserIF任務 :按鍵訊息處理。
App Task COM任務 :這裡用作LED閃爍。
System Timer Thread任務:系統定時器任務
2、 (1) 凡是用到printf函式的全部通過函式App_Printf實現。
(2) App_Printf函式做了訊號量的互斥操作,解決資源共享問題。
3、預設上電是通過串列埠列印資訊,如果使用RTT列印資訊
(1) MDK AC5,MDK AC6或IAR通過使能bsp.h檔案中的巨集定義為1即可
#define Enable_RTTViewer 1
(2) Embedded Studio繼續使用此巨集定義為0, 因為Embedded Studio僅製作了除錯狀態RTT方式檢視。
串列埠列印資訊方式(AC5,AC6和IAR):
波特率 115200,資料位 8,奇偶校驗位無,停止位 1
RTT列印資訊方式(AC5,AC6和IAR):
Embedded Studio僅支援除錯狀態RTT列印:
由於Embedded Studio不支援中文,所以中文部分顯示亂碼,不用管。
程式執行框圖:
16.5 總結
本章節主要為大家講解了ThreadX原裝的任務統計分析功能的實現,比較實用。