FPPA vs. RTOS

P.S FPPATM相關智慧財產權皆屬於應廣科技所有!

 

0. 前言

近來流行的 ARM + RTOS 幾乎已經變成 Embedded System 的代名詞,不過
99% 的書籍雜誌都只有提到這種系統的優點,而沒有提到這種系統
潛在的問題
,甚至其實這種問題也是造成很多寫 8051、PIC 的工程師裹足
不前的原因(也可說是代溝啦,哈~)

剛好最近小弟有機會接觸到新一代的 MCU - FPPA(註1),才瞭解這種問題
不靠 FPPA 這種多核心 MCU 是很難解決的
,而這顆 MCU 提供給一些對於
「升級」到 ARM 有所疑慮的工程師一個很好的解決方案!!

1. Delay Time

下圖是 FPPA 的特殊指令 delay 與 MicroC/OS-II 的 system API - OSTimeDly。
別以為這個 API 沒什麼,事實上這可以算是 RTOS 中最重要 API 之一,尤其對於
uC/OS-II 這種先佔式(preemptive)的RTOS,得靠這個 API 調節 task 執行速度

但是他的延遲時間只能做到 ms 級,因為 OSTimeDly() 實際上是 delay n 個 OS
Timer Tick,以 uC/OS-II 的建議值 200hz 來講 OS Timer 的週期就是 5ms,再上
去調到 1KHz 好了,大多數中檔 MCU/MPU 就會執行的很吃力了,Why?因為每次
Timer Interrupt 都必須 save task context, restore task context, execution
timer function, decision task priority...做一堆雜七雜八的事,這些都是要
執行成本的!所以你看到某 RTOS 號稱 task switch 只需要 2us ,但是他用的可是
60Mhz 32bits RISC MPU!靠∼軟體要錢,MCU還要高速的才能跑,這對對成本極為
敏感的台灣人來說是一件無法接受的事!

而且,最關鍵的是 OSTimeDly() 無法做到精確的時間延遲(下一節會講為什麼),
FPPA 就不同了, 他是在硬體上直接提供這種指令,所以能做到 100% 精確!這也是
software RTOS 的弱點之一!

抱歉!其實上面的指令寫錯了,因為 delay 指令的寫法是 "delay n + 1",也就是上面的
指令會 delay 6us(假設該FPP執行頻率1MHz),正確的寫法是 delay 4。

 

2. OSTimeDly() 彈跳問題

前面談到 OSTimeDly() 無法做到精確的時間延遲,這是為什麼呢?請看下圖,
當 TaskA 呼叫 OSTimeDly(1),一般的想法應該是 5ms 之後才會恢復執行(
實際上還會跟該 task 的 priority 有關,這邊假設為最高 priority),但是
當 15ms 這個 OS Timer Interrupt 發生時,TaskA 就會恢復執行,原因就是
前面提到的,OSTimeDly() 實際上延遲的是 timer tick。原理是 task 在 TCB
(Task Context Block)用一個整數紀錄延遲幾個 tick,每次 Timer Interrupt
發生時就會遞減,直到 0 時該 task 就有機會恢復執行。

所以 MicroC/OS-II 這本書會告訴你,假如你想延遲 5ms,至少要 OSTimeDly(2),
也就是至少會有 5ms 的誤差,推演下去假如想要更高的精確度,只有提高 OS Timer
的頻率,比方說想要 1ms 的精確度,OS Timer 的週期就要 0.5ms,以 2KHz 跑
OS 恐怕對一些 ARM7, MIPS 都是難以承受的 overhead。

另外在此澄清一下這跟 time slot 技巧不同,曾經有前輩問小弟假如一個 task 無法
在 5ms 內執行完怎麼辦?當時小弟一時沒會過意來,這其實是一個很基本的OS概念,
OS的目的是什麼?就是製造有數個 CPU 同時執行的假象!可是真正的 CPU 只有一顆啊,
所以每個 task 會一塊重要的資料結構 TCB(Task Context Block),負責儲存 CPU
的相關資訊,至少會儲存 SP,這樣當 task switch 發生時,就會把目前 registers
的內容 push 到該 task's stack,下次恢復執行時就從 stack pop 回來,大概像是下圖
這樣子:

因為各個 task 都有獨立的 stack 與 registers(image),所以在 5ms
內沒執行完也沒關係。這跟 time slot 共用 stack 與 register 的觀念
是不一樣的。

 

3. OSTimeDly() 延伸出的問題

前面提到 OSTimeDly() 要做到夠精確與夠小的時間延遲是很困難的,有人可能會問
什麼情形下會有這方面的需求?其實這個需求對於寫 8bit MCU firmware 出身的
工程師來說再平常不過了,也就是用軟體實做週邊

翻開 I2C、SPI Device 的 datasheet,要求的 delay 都是 us 級的,ms 級的 OSTimeDly()
根本不夠用!所以在 RTOS 上用軟體寫週邊,頂多寫出 LCM、keypad,至於 I2C、UART幾乎是
不可能的任務!

假如硬要在 RTOS 用軟體寫週邊,幾乎只有下面個方法,就是把中斷與快取記憶體統統
disable,然後專心產生 timing,不用說這樣會製造更多中斷延遲,對於系統整體的效能
影響是很大的!例如 HMI 為了能夠將畫面上的資料透過 IEEE 1284 送到印表機印出來,
用 GPIO 模擬 IEEE1284(沒有SoC會去作這種古老的介面),所以列印時通訊的速度大幅
降低,當然這個 bug 就留給 sales 去解了...XD

但是 FPPA 就不會有這方面的問題,因為他是真正提供 8 顆核心平行執行,完全不用
disable any interrupt,事實上連中斷也不用,因為此時用 polling 的方式寫就好了,
比寫 ISR 不知道容易幾倍!

4. Semaphore

Semaphore 是 OS 最重要的基本服務,其實講白了,他也只是一種軟體旗標,以 binary semaphore
來講就是 0/1 罷了,當 0 時 task 必須停下來直到旗標變成 1 才能有機會繼續執行。對於 FPPA
這種多核心 MCU 來講,可以把一顆核心視為一個 task,假如這個 task 負責當 RS232 Rx,就需要
一個機制來通知其他 task 有資料進來了,最簡單的方式當然是旗標,從下圖你會發現這跟 OS 的
semaphore 是大同小異的,但是 FPPA 只需要 1,2 條指令就可以完成,RTOS 卻必須作一卡車事情,
而且還要 disable interrupt(有些 OS 號稱從不 disable - 註2)

有人馬上會問,那要是其他核心同時 access UARTStat 怎麼辦?這就是 FPPA 的厲害之處,他保證
同一個記憶體位址,在同一時間內只有一個核心可以存取!也就是在硬體指令層次作到了 mutual exclusive!

 

5. 附錄:FPPA 的特殊指令技巧

FPPA 提供一個非常有用的指令 - icall,以 icall FuncPtr 為例,CPU 會提取 FuncPtr 這個變數的內容
作為 sub routines 的位址跳過去執行,也就是說可以用組合語言輕易完成 C 語言的 function pointer
table!有了這個指令,就可以用一個變數充當命令索引暫存器,當其他的 FPP(master) 想要請求服務,就可以把
命令編號填入,接著 trigger slave FPP 就好了,如此一來程式好寫又容易維護!也歡迎 8051、PIC 的高手
用其他方式挑戰看看!

6. 附註

註1:FPPA 官方網站 http://www.padauk.com.tw/

註2:FPPA 實際範例可以參考 ChamberPlus

註3:Green Hills 開發的 velOSity 號稱從不 disable interrupt,不過這家公司的產品是不賣亞洲的,而且不提供 source!