劉 肖 王宜懷 汪 恒 劉長勇,2
1(蘇州大學(xué)計算機科學(xué)與技術(shù)學(xué)院 江蘇 蘇州 215006)
2(武夷學(xué)院認(rèn)知計算與智能信息處理福建省高校重點實驗室 福建 武夷山 354300)
在面向以微控制器(Microcontroller Unit,MCU)的嵌入式系統(tǒng)的開發(fā)中,常常需要使用實時操作系統(tǒng)(Real Time Operation System,RTOS)。為降低嵌入式系統(tǒng)的編程難度,節(jié)省程序的編譯時間,將實時操作系統(tǒng)駐留在MCU中,即固化在MCU內(nèi)的非易失存儲器中,并提供對外的應(yīng)用程序接口。
目前針對RTOS移植文獻較為豐富,如文獻[1]實現(xiàn)了將muTKernel RTOS移植到H8S/2377 MCU上;文獻[2]實現(xiàn)了uC/OS-III的移植;文獻[3]實現(xiàn)了將MicroC/OS-II RTOS移植到PowerPC 7410處理器上等,而對于RTOS的駐留較少;文獻[4]以VxWorks 653分區(qū)操作系統(tǒng)為研究實例,采用統(tǒng)一建模語言分析了分區(qū)配置和啟動機制,為理解分區(qū)和駐留提供了參考;文獻[5-6]雖實現(xiàn)操作系統(tǒng)的駐留,但均針對的是PC機。
實時操作系統(tǒng)駐留的關(guān)鍵技術(shù)在于駐留后實時操作系統(tǒng)的函數(shù)如何被調(diào)用、駐留后的程序框架如何設(shè)計合理和RAM和Flash空間的劃分設(shè)置。本文在通用嵌入式計算機(General Embedded Computer,GEC)架構(gòu)的基礎(chǔ)上,針對以上問題設(shè)計出合理方案,利用直接調(diào)用應(yīng)用程序編程接口(Application Programming Interface,API)實現(xiàn)開發(fā)應(yīng)用程序,使得用戶不需要進行寄存器級編程,無須關(guān)心RTOS的調(diào)用細節(jié),提高編程顆粒度和可移植性,達到降低編程難度、快速編譯之目的,同時為RTOS的駐留提供了一種方案。
MCU性能的不斷提高、軟件工程概念的普及和為提高編程顆粒度和可移植性,借鑒通用計算機概念與做法,提出通用嵌入式計算機的概念。在軟件上,將嵌入式軟件分為基本輸入輸出系統(tǒng)程序(Basic Input and Output System,BIOS)與用戶程序(User)兩個部分[7]。RTOS隨BIOS程序駐留于MCU內(nèi)的Flash中,在User程序中啟動RTOS。
BIOS的功能主要是進行系統(tǒng)的初始化;實現(xiàn)RTOS的駐留;為用戶程序提供相關(guān)構(gòu)件接口,包括底層驅(qū)動構(gòu)件接口、應(yīng)用構(gòu)件接口以及操作系統(tǒng)構(gòu)件接口。
以“分門別類、各有歸處”為主要原則,遵循硬件層次與軟件層次的遞進包含關(guān)系以及合理命名文件夾名稱設(shè)計了如表1所示帶前綴編號01-09的文件夾,分別存放文檔、芯片內(nèi)核、微控制器、GEC、用戶板、軟件構(gòu)件、主程序、RTOS組件和RTOS啟動相關(guān)文件。這里將文檔放入工程結(jié)構(gòu)中,其目的是讓文檔與源程序密切聯(lián)系在一起。接著是由內(nèi)到外的四個文件夾:芯片內(nèi)核、微控制器、GEC、用戶板。然后是軟件構(gòu)件文件夾,存放與硬件無關(guān)的構(gòu)件,如操作系統(tǒng)構(gòu)件。隨后是主程序文件夾,存放相應(yīng)的頭文件、中斷例程文件、主程序文件。最后是RTOS文件夾,存放RTOS封裝的組件和啟動相關(guān)文件。
表1 BIOS程序工程框架
User程序是真正的用戶二次編程模板,在User程序中以正常函數(shù)名及傳參的方式調(diào)用BIOS程序提供的API接口,實現(xiàn)對底層驅(qū)動構(gòu)件、應(yīng)用構(gòu)件、操作系統(tǒng)構(gòu)件的調(diào)用等,而無須再次進行底層驅(qū)動的開發(fā)。User程序工程框架類似于BIOS程序工程框架,區(qū)別在于User程序08文件夾和09文件夾,BIOS程序的08文件夾為RTOS封裝的組件,User程序08文件夾為08_OSThread,用于存放主線程和任務(wù)線程,User程序無09文件夾。
基于GEC架構(gòu),將RTOS隨BIOS程序駐留于MCU中有以下好處:
(1) 降低編程難度。由于RTOS隨BIOS程序駐留于MCU中,提供RTOS相關(guān)接口函數(shù)給User程序使用,使得用戶只需關(guān)心User程序的編程,無須關(guān)心RTOS的調(diào)用細節(jié),從而降低了編程難度。
(2) 節(jié)省編譯時間。由于RTOS隨BIOS程序駐留在MCU中,編譯成功燒入非易失存儲器Flash后就一直存在于MCU中,而User程序中無RTOS,只需編譯User程序,從而縮短了程序的編譯時間。
(3) 提高用戶程序的可移植性。在不同的內(nèi)核、不同MCU已駐留RTOS的前提下,由于BIOS程序提供統(tǒng)一的接口函數(shù)給User程序使用,故User程序只需修改少量配置信息,便可在不同的內(nèi)核之間移植,提高了用戶程序的可移植性。
在GEC架構(gòu)下,整個工程被分為BIOS程序和User程序,要想實現(xiàn)mbedOS的駐留,首先需要對MCU的RAM和Flash空間進行合理的劃分,使得代碼不重疊,變量使用不越界,其次應(yīng)設(shè)計出符合軟件工程可復(fù)用、可移植、可拓展的接口函數(shù)。
(1) Flash空間的劃分。在嵌入式系統(tǒng)軟件開發(fā)中,中斷向量、程序代碼和常數(shù)通常存放于Flash中。在GEC架構(gòu)下,Flash空間的劃分采用互不干涉的原則,即BIOS程序占據(jù)Flash空間的前a個扇區(qū),User程序占據(jù)Flash空間的后b個扇區(qū),Flash總空間為a+b個扇區(qū),如圖1所示。因為Flash的擦除是以扇區(qū)為單位的,故也應(yīng)該以扇區(qū)為單位進行Flash空間的劃分。
圖1 Flash空間的劃分
(2) RAM空間的劃分。RAM通常用來存放可讀可寫的數(shù)據(jù)段(.data段)、可讀可寫且沒有初始化的.bss段、heap段、stack段。因為stack段是用來存放臨時變量的,故RAM空間的劃分可分為棧獨享和棧共享兩種方式。棧共享方式如圖2所示,BIOS程序占用整個RAM空間,User程序則從BIOS程序堆段之后開始使用,且BIOS程序和User程序有共同的棧底(RAM地址的最大值+1)。棧共享方式能夠使得RAM空間得到充分使用,但需注意內(nèi)存沖突,一般當(dāng)RAM空間小于16 KB時使用。棧獨享方式如圖3所示,類似于Flash空間的劃分,BIOS程序占據(jù)RAM空間的前mKB,User程序占據(jù)RAM空間的后nKB,RAM總空間為m+nKB,BIOS程序和User程序有各自的棧底。棧獨享方式可以使得BIOS程序和User程序內(nèi)存不沖突,但RAM空間利用率低,一般當(dāng)RAM空間大于60 KB時使用。
圖2 RAM空間棧共享方式
圖3 RAM空間棧獨享方式
在Flash和RAM空間分配合理的基礎(chǔ)上,User程序若要成功調(diào)用BIOS程序提供的接口函數(shù),還需要獲取被調(diào)用函數(shù)的地址。為此,在GEC架構(gòu)下,BIOS程序?qū)⒔涌诤瘮?shù)封裝后固化于Flash中,并將接口函數(shù)的地址有序地存放于API表中,User程序就可以通過訪問這個API表實現(xiàn)對接口函數(shù)的調(diào)用。API表的設(shè)計主要包括接口函數(shù)的定義、聲明、登記,其過程如圖4所示。
圖4 API表設(shè)計
2.2.1接口函數(shù)的定義與聲明
接口函數(shù)的定義與聲明需滿足嵌入式軟件構(gòu)件(Embedded Software Component)的基本原則。規(guī)范的軟件構(gòu)件由頭文件(.h)及源程序文件(.c或.cpp)文件構(gòu)成[8]。接口函數(shù)在源程序文件中定義,在頭文件中聲明。API表中主要包含底層驅(qū)動構(gòu)件、應(yīng)用構(gòu)件和操作系統(tǒng)構(gòu)件(軟件構(gòu)件)這三類構(gòu)件的函數(shù)。
(1) 底層驅(qū)動構(gòu)件。底層驅(qū)動構(gòu)件是根據(jù)MCU內(nèi)部功能模塊的基本知識要素,針對MCU引腳功能或MCU內(nèi)部功能,利用MCU內(nèi)部寄存器所制作的直接干預(yù)硬件的構(gòu)件[7]。常用的底層驅(qū)動構(gòu)件主要有GPIO、UART構(gòu)件等。
(2) 應(yīng)用構(gòu)件。應(yīng)用構(gòu)件是調(diào)用芯片底層驅(qū)動構(gòu)件而制作完成的,符合軟件工程封裝規(guī)范的,面向?qū)嶋H應(yīng)用硬件模塊的驅(qū)動構(gòu)件,例如printf構(gòu)件。
(3) 操作系統(tǒng)構(gòu)件。RTOS提供各種類,如線程類、線程信號類等。為了方便用戶使用,將RTOS常用函數(shù)如操作系統(tǒng)啟動函數(shù)、創(chuàng)建線程函數(shù)、延時函數(shù)等封裝成構(gòu)件,表2列出了操作系統(tǒng)部分接口函數(shù)。
表2 操作系統(tǒng)部分接口函數(shù)
2.2.2接口函數(shù)的登記
所謂接口函數(shù)登記,就是將接口函數(shù)的入口地址按順序放置在一個統(tǒng)一的區(qū)域,該區(qū)域即為API表。API表可用一個一維數(shù)組(如ComponentFun)來表示,接口函數(shù)的編號與數(shù)組的下標(biāo)一一對應(yīng)。在API表中,預(yù)留了一些缺省的接口函數(shù)名,方便應(yīng)用程序接口表的更新與擴充。
User程序獲取BIOS程序的API表地址后還需要對接口函數(shù)地址進行重定義,最后才能實現(xiàn)對接口函數(shù)的調(diào)用,其過程如圖5所示。
圖5 API表的調(diào)用
在BIOS程序跳轉(zhuǎn)到User程序之后,執(zhí)行main函數(shù)之前,調(diào)用函數(shù)BIOS_API_Init,該函數(shù)獲取BIOS程序提供的API表首地址并將其保存在一個全局?jǐn)?shù)組(如component_fun)中。由于數(shù)組component_fun中的元素只是接口函數(shù)的入口地址,并沒有接口函數(shù)實現(xiàn)的具體形式,因此,還需要對接口函數(shù)的地址進行重定義,以便用戶調(diào)用。重定義后的函數(shù)名可與之前的不一致,但接口函數(shù)重定義順序必須和登記順序一致。其一般格式如下:
#define 函數(shù)名((接口函數(shù)聲明指針表達形式)(全局?jǐn)?shù)組[接口函數(shù)序號])),例如操作系統(tǒng)啟動函數(shù)可以定義為#define OS_start((void(*)(void(*func)(void)))(component_fun[63]))。
(1) 合理分配Flash空間。在實際的Flash空間劃分中,應(yīng)避免BIOS程序的Flash空間劃分過大或過小。過大會使得Flash空間的浪費,甚至以犧牲User程序功能來滿足程序的需要;過小則會使得BIOS程序無法運行。當(dāng)Flash空間較小時,只需保留最基本的各類構(gòu)件和mbedOS的最基本功能函數(shù)以滿足實際工程需要即可,確保BIOS的Flash空間不浪費。
(2) RAM內(nèi)存沖突問題。當(dāng)RAM空間的劃分采用棧共享的方式時,由于堆的使用方向是由小地址向大地址方向進行的,因此當(dāng)BIOS程序中使用new或malloc函數(shù)申請空間時,可能會使得堆溢出,從而和User程序的.data和.bss段重疊,導(dǎo)致User程序無法正常運行。因此,在BIOS程序中主動在堆區(qū)申請空間,從而避開User程序的全局變量區(qū),如圖6所示。
圖6 RAM空間分配示意圖
(3) 系統(tǒng)服務(wù)調(diào)用問題。mbedOS的調(diào)度依賴于SVC、可掛起系統(tǒng)調(diào)用(Pendable Supervisor,PendSV)、系統(tǒng)時間嘀嗒SysTick[9],故在啟動mbedOS前,應(yīng)及時將SVC、PendSV、SysTick的中斷向量寫入User程序的中斷向量表中。
選取mbedOS實時操作系統(tǒng)進駐留測試,駐留測試工程在STM32CubeIDE 1.3.0開發(fā)環(huán)境和STM32L431RC微控制器上完成。其中,RAM空間劃分方式采用棧共享方式。
mbedOS是ARM公司在2014年推出的,它是一個專門為物聯(lián)網(wǎng)(IoT)中的“物體”而設(shè)計開源嵌入式實時操作系統(tǒng)[10]。mbedOS提供統(tǒng)一的應(yīng)用程序編程接口[11],具有嵌入式系統(tǒng)的軟、硬件資源的分配、線程(任務(wù))調(diào)度、同步機制、中斷處理等基本功能,在IP網(wǎng)絡(luò)組件[12]、物聯(lián)網(wǎng)[13]等方面得到廣泛應(yīng)用。
STM32L431RC微控制器的片內(nèi)Flash大小為256 KB,Flash區(qū)的地址范圍為:0x0800_0000-0x0804_0000。Flash區(qū)中扇區(qū)大小2 KB,扇區(qū)總共有128個。片內(nèi)RAM為靜態(tài)隨機存儲SRAM,大小為64 KB,地址范圍為0x2000_0000-0x2001_0000。
(1) 功能設(shè)計。User程序的主要功能是依次創(chuàng)建紅燈、綠燈、藍燈線程,實現(xiàn)三個線程申請同一個互斥量并在申請到互斥量后,分別延時3 s、1 s、2 s。
(2) 測試結(jié)果。User程序中,在調(diào)用操作系統(tǒng)啟動、線程創(chuàng)建、線程啟動、互斥量鎖定、互斥量釋放等函數(shù)前加上相應(yīng)printf函數(shù)輸出提示信息,來驗證mbedOS是否駐留成功。駐留測試實驗結(jié)果如圖7所示,可以看出mbedOS駐留成功,能準(zhǔn)確調(diào)用BIOS程序提供的接口函數(shù),線程運行正常,該方法具有可行性。
圖7 測試結(jié)果
在駐留測試工程中,BIOS程序占Flash的前26個扇區(qū)(52 KB)、RAM的全部空間;User程序占Flash的后102個扇區(qū)(204 KB)、RAM的后48 KB。mbedOS駐留后的Flash和RAM空間劃分和實際使用如表3所示,BIOS和User程序?qū)嶋H使用空間大小均小于實際分配空間大小,且User程序剩余空間較大,能滿足后續(xù)程序開發(fā)需要,故Flash和RAM空間分配較為合理。
表3 STM32L431RC中BIOS和User空間劃分表
本文在GEC架構(gòu)的基礎(chǔ)上,深入剖析RTOS駐留的關(guān)鍵技術(shù),給出駐留后程序的合理工程框架,提出采用互不干涉的原則劃分Flash空間和棧共享、棧獨享兩種方式劃分RAM空間,詳細給出API表的設(shè)計與實現(xiàn),最后以mbedOS實時操作系統(tǒng)為例,在STM32L431RC上進行了駐留測試,測試結(jié)果表明mbedOS駐留成功,Flash和RAM空間劃分合理,并且降低編程難度,縮短程序的編譯時間,提高用戶程序的可移植性,具有一定的參考價值。