眾所周知,一款優秀的產品,不僅要有很高的性能,很好的穩定性,而且還要具備對用戶非常友好和極具吸引力的圖形交互界面。
然而,運行一個非常酷炫且極具吸引力的圖形用戶界面,就要求有一個高主頻,高性能,存儲資源豐富的MCU作為支撐。?
恩智浦擁有眾多高性能,低功耗,大容量存儲資源的MCU/MPU, 在這樣的MCU/MPU上,流暢地運行圖形元素豐富,酷炫且富于吸引力的圖形用戶界面完全沒有壓力。
但是,在實際的客戶支持過程中,我發現有一些客戶基于成本的考慮,會選擇主頻相對低一些,存儲資源相對少一些的MCU。與此同時,他們仍然希望給自己的產品賦予一個精美的圖形界面。
真實案例——電動車屏幕
因此,本文通過一個運行在LPC55S06上的,基于GUI Guider和LVGL的圖形界面設計項目——電動車(簡稱EBike)為例,說明如何在資源有限的MCU上進行圖形應用設計。
圖片與字體的存儲
在設計中, 電動車的GUI使用了大小為1.18MB的26個圖片和大小為35KB的2種字體,共計約為1.22MB。
但事實上,LPC55S06的片上Flash容量為256KB,其中12KB為系統保留,可以為用戶使用的Flash容量只有244KB,不可能將全部圖片和字體存放到片上Flash中。
因此,為了能夠容納這些圖片和字體,可以考慮外擴Flash。同時,為了兼顧顯示性能,可以考慮將圖片存放到外部串行Flash中,而將字體存放到片上Flash中。
歸納一下,在資源有限的MCU上進行圖形界面開發,首先需要考慮的因素就是如何存儲圖片和字體。為了提高顯示性能,可以把圖片和字體盡可能放到片上Flash中存儲。但是,隨著開發的推進,用戶會不斷添加非圖形界面業務邏輯。這時,如果遇到片上Flash存儲空間不夠的情況,可以將原本存放到片上Flash中的圖片和字體放到外部Flash中,從而節省片上Flash存儲空間給非圖形界面業務邏輯使用。
存儲區域的劃分與分配
那么,這里存在一個關鍵問題,如何為圖片和字體分配存儲空間呢,依據什么原則呢?換句話說,哪些圖片和字體存放到外部Flash,哪些圖片和字體存放到片上Flash。
第一點,就是確保片上Flash可以容納全部用戶應用邏輯。
第二點,在滿足第一點的情況下,將需要頻繁刷新的圖片保存到片上Flash。例如,視頻所示界面中儀表盤的表針掃過的區域使用的圖片,隨著表針的轉動,這些圖片會不斷地從外部Flash進行讀取并被顯示在屏幕上。
常見優化手段
除了將消耗片上Flash資源的大戶放到外部Flash上,為了進一步減少用戶應用對存儲資源的消耗,一些優化手段也是必要的。
常用的優化手段包括如下幾點:
將經常需要調用的公共代碼段封裝成函數?
調整編譯優化等級。使用不同的編譯優化等級編譯生成的可執行文件大小是不同的,如果所選的編譯器具有優化代碼大小的編譯優化選項,則可以通過使用該編譯優化選項壓縮可執行文件的大小,從而減少對Flash和RAM存儲資源的占用。不同IDE中優化代碼大小的編譯選項如下所示。
圖1 MCUXpresso IDE中的代碼大小編譯優化選項
圖2?Keil uVision IDE中的代碼大小編譯優化選項
圖3?IAR Embedded Workbench IDE中的代碼大小優化選項
通過LVGL的配置文件lv_conf.h跳過設計中沒有使用的模塊的編譯。例如,在我們的設計中沒有用到控件,如SWICH, TABLE, TABVIEW和TILEVIEW, 就可以將相應控件的開關宏定義為0,這樣沒有使用的控件對應的C文件就不會編譯到最終的可執行文件中,從而減少代碼的大小。
圖4?裁剪LVGL功能
選擇合理的屏幕加載策略
了解LVGL的小伙伴都清楚,GUI上的每一個圖形元素,如按鈕、圖片、標簽、表格等,都是作為一個對象存在的,都是需要消耗一定的RAM資源。
如果我們的GUI設計包含多個屏幕,每個屏幕都包含大量的圖形元素,如果一次性的創建所有的圖形元素,很可能有限的RAM資源不足以容納這些圖形元素。因此,合理的選擇屏幕加載策略很有必要。
基于LVGL的GUI開發工具采用不同的屏幕加載策略。目前,屏幕加載策略有兩種:
第一種是以LVGL官方推出的SquareLine Studio為代表的靜態加載策略,即一次性地把所有屏幕上的圖形元素全部創建。這可以從其生成的代碼工程看到。
以SquareLine Studio的POS機界面示例為例,其UI初始化函數如下圖所示。我們可以看到其5個屏幕一次性創建,那么就意味著這種靜態屏幕加載策略消耗更多的RAM資源。
圖5?SquareLine Studio的UI初始化
第二種是以NXP官方推出的GUI Guider為代表的動態加載策略,即只加載在系統啟動后顯示的屏幕,后面如果需要顯示哪一個屏幕再動態加載。
下圖所示是GUI Guider的官方示例ScreenTransition。這個示例總共有兩個屏幕,即screen1與screen2。函數setup_ui是UI初始化函數。
可以看到,在UI初始化函數setup_ui中只是靜態加載了屏幕screen1,沒有加載screen2。只有當screen1的Next Screen按鈕按下時,在事件回調函數screen_btn1_event_handler中才會調用setup_scr_screen2動態加載screen2。
圖6?ScreenTransition示例的第一個屏幕
圖7?ScreenTransition示例的第二個屏幕
圖8?GUI Guider的UI初始化
圖9?Next Screen按鈕的事件回調函數
由此可見,NXP的GUI Guider的動態屏幕加載策略,充分考慮了在資源有限的微控制器上從事GUI開發時,遇到的存儲資源利用效率問題。
當然,如果您所選擇的MCU或者MPU的存儲資源豐富,可以采用第一種策略,那樣的話,可以能在一定程度上提高顯示性能。
總結
本篇文章以一個GUI示例——電動車為例,重點關注如何在資源有限的微控制器上進行GUI開發,給出了圖片和字體的存儲策略,以及若干存儲資源優化方法。
有關電動車的技術細節,可以參考AN13730: How to Develop LVGL GUI Demo on Memory-constrained MCU with GUI Guider.
編輯:黃飛
?
評論