劉長(zhǎng)勇,王宜懷,孫亞軍
(1.武夷學(xué)院 數(shù)學(xué)與計(jì)算機(jī)學(xué)院,福建 武夷山 354300;2.蘇州大學(xué) 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院, 江蘇 蘇州 215006;3.武夷學(xué)院 認(rèn)知計(jì)算與智能信息處理福建省高校重點(diǎn)實(shí)驗(yàn)室, 福建 武夷山 354300)
實(shí)時(shí)操作系統(tǒng)(real-time operating system,RTOS)的運(yùn)用不僅能有效合理地利用現(xiàn)有的CPU資源,而且能簡(jiǎn)化應(yīng)用軟件的設(shè)計(jì),縮短開發(fā)周期、降低開發(fā)費(fèi)用[1],保證系統(tǒng)的可靠性和實(shí)時(shí)性。那么如何發(fā)揮RTOS作用和優(yōu)勢(shì),采用何種技術(shù)實(shí)現(xiàn)RTOS在嵌入式系統(tǒng)中的駐留,實(shí)現(xiàn)RTOS與應(yīng)用程序分開編譯,是有一定難度且值得研究的問(wèn)題,可以采用嵌入式固件技術(shù),將RTOS與應(yīng)用程序進(jìn)行物理隔離,固化在非易失存儲(chǔ)器(如Flash)中[2]。目前,在操作系統(tǒng)的應(yīng)用及駐留等方面已有部分工作者做了一些基本的研究工作,如唐鵬程等[3]提出了一種基于IAP技術(shù)的STM32單片機(jī)在線固件升級(jí)方案;王運(yùn)盛等[4]以VxWorks 653分區(qū)操作系統(tǒng)作為研究對(duì)象,采用統(tǒng)一建模語(yǔ)言來(lái)分析和說(shuō)明分區(qū)的配置和啟動(dòng)機(jī)制,為理解分區(qū)和駐留應(yīng)用提供了參考;薛芳芳等[5]參考ARINC702A的分區(qū)要求,研究了FMS軟件的駐留規(guī)則,提出了分區(qū)設(shè)計(jì)和駐留方案,最后給出了測(cè)試方法;Wang H等[6]采用μC/OS-Ⅱ?qū)崟r(shí)操作系統(tǒng),在ARM內(nèi)核的處理器上開發(fā)了蛇狀機(jī)器人,并給出了步態(tài)規(guī)劃算法;常華利等[7]提出了一種基于MicroBlaze 軟核處理器的μC/OS-Ⅱ的移植方案;馬書紅[8]利用集成電路技術(shù)和密碼學(xué)原理,提出了一種將數(shù)學(xué)計(jì)算機(jī)系統(tǒng)固化于TPM安全芯片的方法。
mbedOS是專門為使用Arm微控制器的物聯(lián)網(wǎng)(IoT)設(shè)備而設(shè)計(jì)的開源操作系統(tǒng)[9],支持確定性、多線程、實(shí)時(shí)性等,廣泛應(yīng)用于協(xié)議棧和IP網(wǎng)絡(luò)組件[10]、物聯(lián)網(wǎng)設(shè)備平臺(tái)[11]、通信技術(shù)和安全訪問(wèn)服務(wù)機(jī)制[12]等方面。依據(jù)固件技術(shù)的設(shè)計(jì)原則,本文基于通用嵌入式計(jì)算機(jī)架構(gòu),在合理劃分Flash和RAM空間的基礎(chǔ)上,研究mbedOS駐留的關(guān)鍵技術(shù),通過(guò)將mbedOS與應(yīng)用程序分開編譯,達(dá)到快速編譯的目的。同時(shí),也為用戶提供函數(shù)原型級(jí)的對(duì)外接口技術(shù)和調(diào)用方法,方便用戶對(duì)任務(wù)函數(shù)的使用,降低了開發(fā)門檻、節(jié)省了編譯時(shí)間、提高了寫入速度,從而提高應(yīng)用程序的健壯性、實(shí)時(shí)性和可移植性,為學(xué)習(xí)和使用mbedOS提供了基礎(chǔ),也為mbedOS的駐留提供了一種解決方案。
為了提升編程顆粒度、提高可移植性,借鑒通用計(jì)算機(jī)(general computer)的概念與做法,把基本輸入輸出系統(tǒng)(basic input and output system,BIOS)與用戶程序分離開來(lái),實(shí)現(xiàn)徹底的工作分工,形成了通用嵌入式計(jì)算機(jī)(general embedded computer,GEC)[13]。GEC架構(gòu)將嵌入式軟件系統(tǒng)分為BIOS工程程序(簡(jiǎn)稱BIOS)和USER工程程序(簡(jiǎn)稱USER)兩部分,BIOS先于USER固化于微控制器(microcontroller unit,MCU)內(nèi)的非易失存儲(chǔ)器(如Flash)中,啟動(dòng)時(shí)BIOS先運(yùn)行,隨后轉(zhuǎn)向USER,最后由USER啟動(dòng)mbedOS。基于GEC架構(gòu),將mbedOS駐留在BIOS中有以下優(yōu)勢(shì):
(1)降低編程難度。由于工程分為了BIOS和USER,mbedOS駐留在BIOS中,成為了一個(gè)固件。因此,用戶只需關(guān)心USER的編程,不改變?cè)械木幊棠J剑瑹o(wú)需了解mbedOS調(diào)度機(jī)制,就可以調(diào)用mbedOS提供的對(duì)外接口函數(shù),從而降低了編程難度;
(2)節(jié)省編譯時(shí)間。由于mbedOS駐留在BIOS中,只需要編譯成功之后就可以作為一個(gè)固件提供給用戶長(zhǎng)期使用,不占用用戶程序時(shí)間,而在USER中由于無(wú)mbedOS,只需編譯用戶程序即可,縮短了程序的編譯時(shí)間;
(3)簡(jiǎn)化寫入方式。在原來(lái)不分BIOS和USER時(shí),每次要使用SWD接口通過(guò)寫入器將程序燒錄到Flash中,若程序有變動(dòng),還需重新寫入。而在GEC架構(gòu)中,只需在BIOS中通過(guò)寫入器將程序燒錄到Flash中,而USER則可以通過(guò)串口進(jìn)行寫入和更新,甚至可以通過(guò)遠(yuǎn)程的方式實(shí)現(xiàn)對(duì)USER的更新,簡(jiǎn)化了程序的寫入方式。
基于GEC架構(gòu),程序雖然分為BIOS和USER,但最終程序代碼和各種變量數(shù)據(jù)都是放在同一個(gè)MCU的Flash和RAM中,要將mbedOS駐留到BIOS中,就必須對(duì)MCU的Flash和RAM空間進(jìn)行合理的劃分,這樣才能確保代碼不重疊,變量使用不越界,從而保證mbedOS能得到正常運(yùn)行,而且又不影響USER的執(zhí)行。
(1)Flash空間的劃分
MCU的Flash 空間一般分為中斷向量段、Flash配置段和程序代碼段,分別用于存放中斷向量、默認(rèn)的Flash保護(hù)設(shè)定與加密屬性、程序代碼。在GEC架構(gòu)下,F(xiàn)lash 空間采用分割獨(dú)享方式劃分為BIOS和USER兩部分,每部分都包含這3個(gè)段,其劃分如圖1所示,需要注意的是由于Flash是以扇區(qū)為單位進(jìn)行擦除,在劃分空間時(shí)要以扇區(qū)為單位。BIOS負(fù)責(zé)MCU的啟動(dòng)、提供各類構(gòu)件、實(shí)現(xiàn)mbedOS的駐留以及生成函數(shù)原型級(jí)的對(duì)外接口函數(shù)表供USER使用;USER由用戶編寫,它可以調(diào)用BIOS提供的對(duì)外接口函數(shù),實(shí)現(xiàn)應(yīng)用程序的功能需求。

圖1 分割獨(dú)享式Flash空間劃分
(2)RAM空間的劃分
MCU的RAM空間一般分為重定向段、data段、bss段、heap段和stack段,各段的作用見表1。棧空間的使用方向是從大地址向小地址方向進(jìn)行的,棧空間的棧底位置應(yīng)該設(shè)置為RAM最大地址+1處;而堆空間的使用方向是從小地址向大地址方向進(jìn)行的。

表1 RAM中的各段作用
RAM空間的劃分也同樣分為BIOS和USER兩部分,前者包含重定向段、data段、bss段、heap段和stack段,后者包含data段、bss段、heap段和stack段。由于heap段和stack段都是用于存放臨時(shí)局部變量,可以重疊使用。因此,在RAM空間劃分上可以采用分割獨(dú)享和重疊共享兩種方式。分割獨(dú)享方式的優(yōu)勢(shì)在于BIOS和USER獨(dú)享自己的RAM空間,可以避免BIOS和USER運(yùn)行時(shí)彼此間的數(shù)據(jù)重疊干擾,一般適用于RAM空間較大的情況。由于本文采用的KL36的RAM空間較小,因此采用重疊共享方式。
由于芯片上電啟動(dòng),運(yùn)行完BIOS之后,程序會(huì)跳轉(zhuǎn)到USER執(zhí)行。此時(shí),雖然BIOS完成了它的使命,但其RAM空間中的重定向段、data段、bss段和heap段仍要為USER服務(wù),故需保留,而stack段的臨時(shí)變量不再被使用,無(wú)需保留。因此,可以充分利用這一特性,只需確保USER的RAM區(qū)域從BIOS的heap段之后開始,且BIOS的stack段的棧底地址與USER的stack段的棧底地址都指向RAM最大地址+1的位置,這樣可以將BIOS的stack段與USER的RAM空間共同使用同一段區(qū)域。基于此思想,針對(duì)RAM空間較小的情況,提出了采用重疊共享的方式來(lái)劃分RAM空間,如圖2所示,BIOS占用整個(gè)RAM空間,USER只占用BIOS的stack段這塊區(qū)域。

圖2 重疊共享式RAM空間劃分
通過(guò)對(duì)Flash和RAM空間的劃分,為mbedOS駐留在BIOS中提供了空間,但要發(fā)揮mbedOS的作用,還需將mbedOS的功能通過(guò)對(duì)外接口函數(shù)表的方式向USER提供服務(wù)。要達(dá)到這樣的目的,首先需要在BIOS中進(jìn)行對(duì)外接口函數(shù)的定義、聲明、注冊(cè),形成對(duì)外接口函數(shù)表;其次要在USER中獲取對(duì)外接口函數(shù)表的入口地址,并重定向?qū)ν饨涌诤瘮?shù)名稱;最后在USER中實(shí)現(xiàn)對(duì)函數(shù)的調(diào)用,如圖3所示。

圖3 對(duì)外接口函數(shù)表的設(shè)計(jì)與實(shí)現(xiàn)
(1)對(duì)外接口函數(shù)的定義
對(duì)外接口函數(shù)不僅包含mbedOS的功能函數(shù),而且還可以包括各類構(gòu)件函數(shù),其定義與一般函數(shù)的定義并無(wú)區(qū)別,主要包括函數(shù)名、函數(shù)的返回值類型、函數(shù)的參數(shù)、函數(shù)體等。
(2)對(duì)外接口函數(shù)的聲明
對(duì)外接口函數(shù)定義好之后,一般應(yīng)在與之同名的.h頭文件中進(jìn)行聲明,函數(shù)的聲明要給出函數(shù)名、函數(shù)的返回值類型、函數(shù)的參數(shù)以及函數(shù)的功能說(shuō)明。
(3)對(duì)外接口函數(shù)的注冊(cè)
在對(duì)外接口函數(shù)定義和聲明之后,還要對(duì)函數(shù)進(jìn)行注冊(cè)才能形成對(duì)外接口函數(shù)表。借鑒中斷向量表的定義做法,可以給所有的或部分的對(duì)外接口函數(shù)編號(hào),并將函數(shù)名(即函數(shù)的入口地址)集中在一起按編號(hào)有序地放在一個(gè)統(tǒng)一的區(qū)域中,這個(gè)區(qū)域就稱為對(duì)外接口函數(shù)表。對(duì)外接口函數(shù)表常用數(shù)組(如BIOS_API)來(lái)存放,對(duì)外接口函數(shù)的編號(hào)與數(shù)組的下標(biāo)元素一一對(duì)應(yīng),如0號(hào)對(duì)外接口函數(shù)對(duì)應(yīng)BIOS_API[0],1號(hào)對(duì)外接口函數(shù)對(duì)應(yīng)BIOS_API[1],依此類推。
(4)獲取對(duì)外接口函數(shù)表的入口地址
當(dāng)BIOS的對(duì)外接口函數(shù)表形成之后,USER要使用它必須先獲得對(duì)外接口函數(shù)表的入口地址,也就是獲得存放對(duì)外接口函數(shù)表的數(shù)組首地址。為了與該數(shù)組的元素一一對(duì)應(yīng),在USER中一般也定義一個(gè)重定向表數(shù)組(如USER_API),這樣USER使用USER_API就相當(dāng)于使用BIOS_API。也可以說(shuō),USER通過(guò)USER_API就可以訪問(wèn)BIOS提供的對(duì)外接口函數(shù)。
(5)對(duì)外接口函數(shù)表的重定向
USER對(duì)對(duì)外接口函數(shù)表中函數(shù)的訪問(wèn)是通過(guò)USER_API數(shù)組,如USER_API[1]訪問(wèn)的是1號(hào)對(duì)外接口函數(shù)。但采用USER_API[i]這種形式對(duì)具體訪問(wèn)的對(duì)外接口函數(shù)的類型、函數(shù)名、參數(shù)以及功能等不夠清晰明了。因此,類似中斷向量重定向的做法,也可以對(duì)對(duì)外接口函數(shù)進(jìn)行重定向,即重新給USER_API[i]取另外一個(gè)用戶熟悉的函數(shù)名,這個(gè)函數(shù)名可以與對(duì)外接口函數(shù)名同名,也可以是不同名的,這樣就可以為用戶提供函數(shù)原型級(jí)的訪問(wèn)方式,易于用戶記住和使用。如mbedOS中延時(shí)函數(shù)的名稱是wait,在重定向時(shí)可以取名為delay,表2列出了部分mbedOS對(duì)外接口函數(shù)。

表2 部分對(duì)外接口函數(shù)重定向
(6)函數(shù)調(diào)用
在對(duì)外接口函數(shù)表重定向之后,就可以利用重定向后的名字來(lái)調(diào)用對(duì)外接口函數(shù),如USER在調(diào)用delay函數(shù)時(shí),實(shí)際上是指向了USER_API[3],而USER_API[3]對(duì)應(yīng)BIOS_API[3],BIOS_API[3]存放的就是wait函數(shù)的入口地址,也就是USER通過(guò)delay達(dá)到調(diào)用wait的目的。
在GEC架構(gòu)下,實(shí)現(xiàn)將mbedOS駐留在BIOS中,有以下幾個(gè)方面的關(guān)鍵點(diǎn)需要注意:
(1)合理分配Flash空間。由于Flash空間的劃分是以扇區(qū)為單位的,當(dāng)Flash空間較小時(shí),只須保留最基本的各類構(gòu)件和mbedOS的最基本功能函數(shù)以滿足實(shí)際工程需要即可,確保BIOS的Flash空間不浪費(fèi);
(2)確保RAM空間不沖突。當(dāng)RAM空間較小采用重疊共享方式劃分時(shí),若BIOS使用new或malloc等動(dòng)態(tài)內(nèi)存申請(qǐng)函數(shù),此時(shí)申請(qǐng)的空間占用的是BIOS的heap段,當(dāng)申請(qǐng)的內(nèi)存過(guò)大,可能會(huì)出現(xiàn)heap段空間不夠而越界到USER的重定向段、data段、甚至bss段,造成USER無(wú)法正常運(yùn)行;
(3)及時(shí)回收系統(tǒng)服務(wù)調(diào)用權(quán)。在GEC架構(gòu)中,從芯片上電到最終用戶的任務(wù)執(zhí)行是先啟動(dòng)BIOS,接著啟動(dòng)USER,最后才啟動(dòng)mbedOS。由于mbedOS的調(diào)度依賴于系統(tǒng)服務(wù)調(diào)用SVC、可掛起服務(wù)調(diào)用PendSV和系統(tǒng)時(shí)間嘀嗒SysTick等,而在啟動(dòng)BIOS和USER時(shí)都會(huì)使用到SVC中斷,SysTick中斷也有可能會(huì)被作為定時(shí)器使用。因此,在啟動(dòng)mbedOS前,必須及時(shí)將SVC、PendSV和SysTick的調(diào)用權(quán)回收,移交給mbedOS。
mbedOS的駐留測(cè)試工程在Kinetis Design Studio 3.0.0 IDE開發(fā)環(huán)境和金葫蘆AHL-A系列Cortex-M0+內(nèi)核的KL36微控制器[14](即AHL-AN100VL型號(hào)開發(fā)板)上進(jìn)行,分為BIOS和USER兩個(gè)工程,BIOS工程實(shí)現(xiàn)mbed-OS的駐留,先于USER固化到Flash中,USER工程實(shí)現(xiàn)應(yīng)用功能。
KL36片內(nèi)Flash大小為64 KB,分為64個(gè)扇區(qū),一般用來(lái)存放中斷向量(共有48個(gè),占192字節(jié))、程序代碼、常數(shù)等;片內(nèi)RAM為靜態(tài)隨機(jī)存儲(chǔ)器SRAM,大小為8 KB,一般用來(lái)存儲(chǔ)全局變量、靜態(tài)變量、臨時(shí)變量(堆棧空間)等。測(cè)試工程考慮到Flash和RAM空間較小,F(xiàn)lash空間采用圖1劃分方式,RAM采用圖2劃分方式。當(dāng)mbedOS駐留后,F(xiàn)lash和RAM空間劃分情況見表3。

表3 KL36中BIOS和USER空間劃分
在GEC架構(gòu)中,當(dāng)mbedOS駐留在BIOS后,整個(gè)程序從上電啟動(dòng)到最后由mbedOS實(shí)現(xiàn)對(duì)用戶任務(wù)的調(diào)度,需要經(jīng)歷BIOS啟動(dòng)、USER啟動(dòng)以及mbedOS啟動(dòng)3個(gè)階段,其簡(jiǎn)易啟動(dòng)流程如圖4所示。

圖4 GEC架構(gòu)下mbedOS的簡(jiǎn)易啟動(dòng)流程
首先,MCU上電開始BIOS的啟動(dòng),由硬件自動(dòng)完成從Flash的0地址處取值對(duì)BIOS的堆棧指針初始化和啟動(dòng)復(fù)位向量,接著進(jìn)行系統(tǒng)時(shí)鐘初始化和各數(shù)據(jù)段的初始化,然后在main函數(shù)中調(diào)用projectJump跳轉(zhuǎn)到USER的執(zhí)行。
其次,從BIOS轉(zhuǎn)到USER的啟動(dòng),由用戶指令完成從Flash的0地址處取值對(duì)USER的堆棧指針初始化和啟動(dòng)復(fù)位向量,接著進(jìn)行各數(shù)據(jù)段的初始化,然后在USER的main函數(shù)調(diào)用mbedOS_start啟動(dòng)mbedOS。
最后,從USER轉(zhuǎn)到mbedOS的啟動(dòng),包括設(shè)置mbed-OS的堆棧區(qū)、重定向中斷向量表、內(nèi)核初始化、設(shè)置自啟動(dòng)任務(wù)屬性、創(chuàng)建自啟動(dòng)任務(wù)、啟動(dòng)內(nèi)核、調(diào)用自啟動(dòng)任務(wù)的執(zhí)行函數(shù),然后由mbedOS完成對(duì)用戶任務(wù)的調(diào)度執(zhí)行。
USER工程的主要功能是創(chuàng)建兩個(gè)任務(wù),實(shí)現(xiàn)每秒紅燈閃爍一次,藍(lán)燈任務(wù)每2 s切換亮暗一次,綠燈任務(wù)當(dāng)收到藍(lán)燈任務(wù)的線程信號(hào)(34)時(shí),切換綠燈亮暗。在USER 工程中,使用到了mbedOS提供的對(duì)外接口函數(shù)有延時(shí)、任務(wù)創(chuàng)建、任務(wù)啟動(dòng)、信號(hào)設(shè)置和信號(hào)等待等函數(shù)。駐留測(cè)試工程的運(yùn)行結(jié)果如圖5所示,從中可以看出mbedOS駐留成功,程序啟動(dòng)流程正確,能準(zhǔn)確調(diào)用mbedOS提供的對(duì)外接口函數(shù),任務(wù)在mbedOS調(diào)度下運(yùn)行正常、程序執(zhí)行邏輯準(zhǔn)確、實(shí)時(shí)性能得到滿足。

圖5 駐留測(cè)試工程的運(yùn)行結(jié)果
為充分發(fā)揮實(shí)時(shí)操作系統(tǒng)mbedOS的強(qiáng)大功能和較高實(shí)時(shí)性的性能,本文結(jié)合固件技術(shù)的設(shè)計(jì)原則,深入剖析了GEC架構(gòu)下mbedOS的駐留優(yōu)勢(shì)和關(guān)鍵技術(shù),提出了分割獨(dú)享和重疊共享兩種方式來(lái)合理劃分Flash和RAM空間,詳細(xì)給出了對(duì)外接口函數(shù)設(shè)計(jì)與實(shí)現(xiàn),最后測(cè)試結(jié)果表明mbedOS駐留成功,F(xiàn)lash和RAM空間劃分合理,程序運(yùn)行邏輯正確。同時(shí),本文提出的對(duì)外接口函數(shù)重定向方法,使得用戶可以使用自己定義的函數(shù)名稱而不依賴于RTOS提供的函數(shù)名稱,提高了用戶程序的可移植性。后續(xù)將在不同MCU的可移植性和駐留等方面展開進(jìn)一步的研究,文中的程序可在蘇州大學(xué)嵌入式學(xué)習(xí)社區(qū)(http://sumcu.suda.edu.cn)中下載查看。