1. 如何劃分 Priority?
這大概是剛接觸 RTOS 應用的工程師最頭痛的部份,也可能是最重要的部份。前面提到的 uC/OS-II 其實已經是1x 年前的產品,後面的 uC/OS-III 乃至於當紅的 FreeRTOS 都支援 time-slicing,哪怕你把兩個 task 設成相同 priority,其中一個 task 時間額度用完,OS kernel 就會切到另一個 task,那這樣把 task 全部設成相同 priority 不就免煩惱? 但這樣何必用 RTOS?
所以 uC/OS-II 這個老 RTOS 反而可以迫使我們對重要的問題思考 - 那劃分 priority 的依據是什麼?依筆者所知:
- 依執行頻率劃分:執行頻率越高,priority 越高,反之越低
- time critical
控制器通訊 task(歐美稱為 protocol driver):
- 高頻率
- time critical
- 以上兩者除了筆者所舉的例子,Linux/Windows 也不約而同把 TCP/IP stack 作為 kernel 的一部分。
- 低頻率: 即便傳統電視視訊格式 NTSC 也只有 30FPS,PAL 只有 25FPS,甚至 15FPS 其實就相當夠用了,見另一篇關於子彈時間的討論。
- non time critical: 差個幾 ms(甚至更大)並沒有什麼影響,如果你能看出來可以考慮當戰鬥機駕駛員或者當電競選手。
2. 事後諸葛亮分析法
這恐怕才是大部分人碰到的問題,沒辦法科技公司的流動率太高了,老闆不會懂你的難處,他的直覺是我都投資這麼多錢下去了,你來一句話就要砍掉重練,那前面的投資等於丟到水裡了。而且 debug 或優化時,了解各個 task 的執行頻率也是必要的。
那要如何分析?筆者的作法是統計一秒內,各個 task 佔用的百分比,以 uC/OS-II 來說,他有一個 global variable - OSCtxSwCtr:
//ucos_ii.h OS Version : V2.85 //... // Counter of number of context switches OS_EXT INT32U OSCtxSwCtr;OS kernel 每次進行 context switch 時,都會遞增 OSCtxSwCtr,另外同時也遞增每個將被執行的 task 的 OSTCBCtxSwCtr:
//ucos_ii.h OS Version : V2.85 //... typedef struct os_tcb { //... // Number of time the task was switched in INT32U OSTCBCtxSwCtr; //... };
//os_core.c void OSIntExit (void) { //... if(OSIntNesting==0) /* Reschedule only if all ISRs complete ... */ { if(OSLockNesting==0) /* ... and not locked. */ { OS_SchedNew(); if(OSPrioHighRdy!=OSPrioCur) /* No Ctx Sw if current task is highest rdy */ { OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; #if OS_TASK_PROFILE_EN > 0 OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ #endif OSCtxSwCtr++; /* Keep track of the number of ctx switches */ OSIntCtxSw(); /* Perform interrupt level ctx switch */ } } } //... } void OS_Sched(void) { //... if(OSLockNesting==0) /* ... scheduler is not locked */ { OS_SchedNew(); if(OSPrioHighRdy != OSPrioCur) /* No Ctx Sw if current task is highest rdy */ { OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; #if OS_TASK_PROFILE_EN > 0 OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */ #endif OSCtxSwCtr++; /* Increment context switch counter */ OS_TASK_SW(); } } //... }清除 OSTCBCtxSwCtr, OSCtxSwCtr 並不會對 OS kernel 造成影響,所以你可以做出一個統計 task,在每秒結束時將每個 task 的 OSTCBCtxSwCtr*100/OSCtxSwCtr,就能得到該 task 佔用的百分比,這個數據可以灌進 Excel 裡畫出折線圖,然後泡杯咖啡好好觀察是哪裡不對勁,比方說有時系統卡死了,那你就會看到某 task 快衝到 100%了。
其實在原書第一章裡,作者就給出了範例,甚至還精細到每個 task 佔用了多少 us,但筆者的作法比較簡單,因為書中的 uC/OS-II 版本太舊,沒有提供 OSTCBCtxSwCtr:
當紅的 FreeRTOS,也提供了類似的資訊。
3. CPU 佔用率
如果您留意的話,應該會注意到上圖下方有一個 CPU Usage:這跟 Windows 上的"CPU 使用率"意義相同:
對於大多數寫純軟體的工程師來說,他們對於這個數字可能沒太大感覺,但對於 Real-Time System 來說,這個弄不好產品是不能賣的,甚至會弄出人命。那多少以下才是合理的?根據 uC/OS-II 作者在書中的說法應該小於 70%,這個當然有學理上的依據,稱為 RMA(Rate Monotonic Analysis),這在上個世紀就由清大前校長劉炯朗博士與 Layland, J 分析完畢,對細節有興趣的朋友除了 uC/OS-II 原書外,也可以參考 Real-Time Concepts for Embedded Systems 一書。
雖然學理上是小於 70%,但其實是越小越好,筆者親眼見證過超過 60% 其實系統就開始遲緩了。越高會造成 priority 越低的 task 越少機會分配到 CPU,甚至可能完全分不到 CPU,那你的產品就會很有問題了。
這個 CPU Usage 是依據一個很簡單的條件計算出來的,你在 Windows 上也見過:
基本上,這個 idle task 被分配的 CPU time 越多,代表 CPU 負載越低,在 RTOS 裡通常就是最低 priority 的 task。
4. CPU 使用率 - 讓老闆看得懂
寫了一大堆,那要怎麼讓老闆看得懂,不然至少也要讓其他同事(包含硬體工程師)一眼就能看得懂?除了用 UART 印一大堆訊息外,這邊再提供幾個爭議少的可視化方法,這些方法取自 The Art of Designing Embedded Systems,這本書非常值得收藏,裡面提供了很多實務技巧與見解。4.1 toggle GPIO
如果你的 MCU/MPU 上有閒置的 GPIO,這個方法最簡單,把閒置的 GPIO pin 設定為輸出,在 idle task 內不斷對其on/off,如果 CPU usage 小,那你會看到密集的方波,如果 CPU usage 大就會看到方波出現的很少不密集,如果到了 100%,那你就會到電影中常出現的 - 病床上去世的人的心跳圖變成一直線。4.2 觀察 duty cycle
這個方法可以用示波器,也可以用電錶。跟 4.1 不一樣的地方是在 idle task 對 GPIO on,而切換到 non-idle task 時對 GPIO off,於是如果 CPU 越閒,在示波器上看到的方波 low 的部份就越少,如果你拿電錶監測,如果 GPIO 的位準是 3.3V,趨近 3.3V 代表 CPU 越閒,反之趨近 0,那代表你的系統有問題,這邊要注意的是電錶的反應速度比起示波器要慢多了,所以示波器還是較好的選擇。4.3 R-2R
這個方法對於寫軟體的人來說太麻煩了,而且要花很多時間解釋,也需要更多 GPIO 與硬體,這邊只大概提一下,有興趣的朋友請自行查書:
簡單來說就是炮製一個簡單的 D/A 轉換器,以上 PIO0-2 都設定為 output,每次在 task switch 時都輸出 outportb(test_port, task_id),這樣就可以得到:
- 0v: task 0(task_id = 0)
- 1/8v(如果是5V = 5*1/8): task1
- 以此類推
通常要解釋的越多,聽眾吸收越差,質疑也就越多,通常我只推薦 4.1...
5. 實務探討
筆者在工控打滾的這段期間內發現一件事,就是台廠除了產品比歐美日便宜外,一些細節就比不上進口貨了,當然也有例外,像是那個跟筆者有點淵源的 xx4,他們就會把這些細節測乾淨(所以人家才能一年發到12月年終),但有些公司能聽得懂人話就要偷笑了。5.1 HMI 寸動(jog)
一台工業設備總免不了需要微調,有可能是馬達轉個幾度,或者某個部份前進幾mm:筆者之前服務的公司,這個部份就有待加強,進口貨是按一下設備動一下,筆者做的那台是有時按很多下動一下,或者是按很多下沒反應,這很多下累積到 buffer(FIFO) 裡一次送出,這甚至差點把客人的設備搞壞。
所以這也是 ChamberPlus 老大講的,怎麼搞了這麼多年還是弄不出一個精緻的軟(軔)體,既不事前分析也不事後檢討,結果可想而知。
5.2 PLC 通訊模組
筆者之前接觸過歐美日的 PLC 通訊模組,注意到以下幾件事:- 可以接受的連線數極少,只有個位數
- 在通訊協議裡加上容忍多少延遲之類的參數
這也難怪一向把成本看很重的台廠,一邊抱怨貴一邊掏錢買了,也難怪如三菱、西門子能成為百年企業,人家老工程師是家有一老如有一寶,台廠是家有一老如有一草,老闆恨不得快點汰舊換新,還搬出諸如平均年齡太大影響公司活力的奇葩說法,當然部份老工程師們號稱10年經驗1年用10次也不能怪人家,只能說是歷史共業啊..
寫得很詳細
回覆刪除感謝支持~
刪除