我們在做嵌入式產品的軟件開發時,經常會遇到因為成本、交期或芯片資源緊張等原因而更換MCU平臺的情況;再加上不同MCU廠商在芯片外設、寄存器和庫函數接口等方面的命名規則和名稱又不一樣,這個時候就肯定會涉及到代碼跨平臺移植操作。
其實,代碼移植是一個比較耗費精力和磨性子的過程,可能會讓人“發狂”。這個時候,如果你的代碼框架在起初設計時就考慮了后續可能會出現的代碼跨平臺移植這個可能性,那么你的代碼移植工作量就會大大減少。
那么,什么樣的軟件框架有利于代碼移植呢?下面給出一個比較適用于剛出校門入職場的軟件同仁們的參考框架,我們一起來看看吧!
代碼一定要分層設計,切忌把全部文件放在同一個文件夾下面,最簡單的就是區分一下代碼層次:
應用層:主要實現業務邏輯,不涉及與MCU平臺相關的操作;
MCU驅動層:可以稱為BSP(板級支持包)層,主要實現MCU外設驅動代碼;
外置芯片驅動層:主要實現與MCU通過總線等方式進行通信的芯片驅動代碼;
固件庫層:MCU芯片的固件庫源文件;
協議層:如果有標準協議,可以單獨建個文件夾存放。
根據以上描述,基本可以按照如下拓撲進行設計:

app文件夾下面以模塊化的方式實現需要的應用功能,一個功能/模塊對應一個源文件+一個頭文件,可以用app_功能名稱命名源文件和頭文件:

main.c文件可以直接放到app文件夾下面。
bsp文件夾下面以區分外設的方式實現需要的芯片驅動,可以用bsp_外設名稱命名源文件和頭文件:

并且盡量用宏定義方式在頭文件里申明GPIO和引腳配置信息,類似下面代碼:

MCU芯片處理中斷向量表的源文件也可以放到bsp文件夾下面。
driver文件夾下面以區分外置芯片的方式實現需要的芯片驅動,可以用芯片名稱來命名源文件和頭文件:

并且盡量用宏定義方式在頭文件里申明與MCU平臺相關的信息,包括GPIO和庫函數操作等,后續移植時僅需要修改頭文件即可,類似下面操作:

宏定義的越詳細越具體,代碼移植修改時會越簡單越方便。
libraries文件夾下面存放固件庫文件:

另外,在設計工程時,可以新建兩個文件夾,把固件庫文件區分開(外設文件+啟動文件):

ethercat文件夾存放協議文件,直接用協議名稱命名該文件夾即可,比如wifi、tcp_ip等:

通過以上的分層和解耦設計,在執行代碼移植時,你只需要以下的幾個操作步驟,即可完成大部分的代碼移植:
直接把固件庫全部替換;
修改bsp相關文件,這塊的工作量相對來說是最大的;
修改driver里面的驅動頭文件,其源文件不需要任何修改;
修改工程配置里的庫文件包含信息。
通過以上的幾個移植修改步驟,基本就完成了代碼跨平臺移植,編譯后可能還會出現個別報錯,再修改修改就可以了,畢竟代碼移植的第一步就是要讓你的代碼編譯通過,然后再慢慢調試功能即可。
當然,軟件框架的設計還可以繼續深入,比如把MCU底層配置抽象出來并形成一個獨立的文件,這樣外置芯片驅動的頭文件可能都不需要修改了,而只需要修改MCU底層配置文件即可;或者把包括排序算法、濾波算法等通用的算法,以API接口的方式封裝起來并放到一個源文件里等等。
比如封裝GPIO名稱:
目前是在驅動代碼頭文件里按照如下方式申明:
可以把GPIOB封裝到單獨的通用頭文件(commonHeader.h)里,并按照如下方式命名:
而驅動頭文件里修改如下:
如此操作后,代碼移植時,只需要修改commonHeader.h文件即可。
其他宏定義的封裝操作類似。
以上就是作者針對如何降低代碼跨平臺移植的工作量的實操經驗和拙見,希望這篇文章能對大家有所幫助!另外,如果有需要查看原圖、代碼的小伙伴,請點擊底部“閱讀原文”進行下載。

END
作者:dffzh