2010年2月20日 星期六

8051簡單多工7:堆疊(stack)使用狀況

發現忘了說使用這個架構是為了什麼。當然是省記憶體,但到底是省到那一種。答案是我想省下使用8051 Register file。

有玩8051的應該會知道8051產生副程式呼叫所使用的堆疊在那裏,就是Registers file。問題是它的大小只有256byte。

也就是說,最大只能呼叫128層的副程式,還要扣除使用暫存器、中斷程式的使用,實際上連100層都到不了。

當堆疊玩爆了,什麼怪現象都會冒出來,沒有對處理器了解的人,是永遠也不知問題出在那裡。

可是有人會問,是誰有辦法寫出40層以上的呼叫,玩到堆疊爆掉。其實也不用那麼多層也可以爆掉的。

在函式內的區域變數也是在用堆疊的,也就是如果函式內皆使用30byte的區域變數,呼叫個十層,就會爆了。

可是有人會問,他寫8051程式已經很大了,並沒有遇到我說的現象。這就是Compiler的工作了,像Keil C在每次函式呼叫,會去計算使用多少堆疊。所以可以預測是否出現堆疊爆掉的狀況。

不過中斷程式也是使用堆疊,卻不在計算範圍內,所以有時中斷程式寫太大仍會發生怪現象。


好了,談了這麼多,和多工有何關係?

當然有,因為多工,所以函式的數量一定大增,以RTOS來寫,每一個Task都會要求獨立的堆疊,8051的堆疊根本不夠用。

不過8051上仍有RTOS,像uCOS就有8051版本,只不過它在切換Task時,是將整個Stack都搬到外部記憶體去,然後又從外部記憶體搬另一個Task的回來。這樣做其實效率並不好,但也只能接受。因為8051原設計就沒想到裝作業系統這樣東西進去。

而Bee在設計上,有想到保留堆疊(stack),所以採用非強制多工的方法,如此一來就可以確定函式執行完成退出後,才會輪到另一個task的函式執行。這就是一開始設計上的考量。

不過有所犧牲,程式只能以狀態機的方式寫,會使得別人不好閱讀程式。

不過Task之間因為要回到main()中才能切換,回到main()即表示全部堆疊都已釋放,也就是Task之間不會有堆疊互相堆積的問題。也就可以確保每個Task都幾乎有完整的8051堆疊可用。

這是這個架構的好處,在實際使用上,就有許多變數可以放進Register file可以增加8051的運作速度了。或者可以使用比較多層的中斷程式也比較不用擔心。

但這個架構仍有一個問題,那就是Keil C因為會去預測堆疊的使用。當安排一個Task是由一群循環的狀態函式所組成時,Keil C會提出使用到遞迴結構的警告。這個我還不知要如何去除。看看那天能有人給點建議。

不過只是警告,還不至於影響執行。


Bee實作上,有遇到一次的是,單一的Task掛了,產生資料存取錯誤,另三個Task仍很正常。大概是沒有影響到全域變數,所以還好。可見穩定性還可以。

至於是那一個事件,可以去另一篇LCM當機解法看看。


沒有留言:

張貼留言