ARM Cortex―M0/M0+單片機(jī)的指針變量替換方法
實(shí)際上,應(yīng)用程序中可通過MOV指令將R8~R11初始化成“寄存器常數(shù)”,而以后不再改變它們的值。例如可以令:
R8,=0 用于低寄存器的快速清零
R9,=RAM基地址 用于拼接長指針
R10,=I/O模塊基地址
R11,=庫函數(shù)基地址
當(dāng)FLASH存儲器空間不大于64 KB時,函數(shù)指針無需設(shè)定基地址,可以直接使用低16位作為16位指針。對于超過64 KB的FLASH,可以使用庫函數(shù)基地址,采用類似分頁的方法實(shí)現(xiàn)16位指針替換。
最后一個高組寄存器R12可在響應(yīng)中斷時和R0~R3,PC、SP一同自動入棧,是用戶可以使用的寄存器變量。
2.1節(jié)中提出的宏定義方案形式上簡單清楚,但展開后需要多條指令才能完成。將Address_base作為寄存器變量,存放在R8~R12中的某個高組寄存器中,而不是使用宏定義常量或全局變量。由于C語言不能直接對通用寄存器進(jìn)行操作,需通過將匯編嵌入到C語言中實(shí)現(xiàn)長指針的替換。在程序初始化時,將R8~R12中的一個寄存器初始化為Address_base的值,例如下面給出的語句:
asm(“LDR r1,=0x1ffff000”);//R1=基地址
asm(“MOV R9,R1”);//R9=R1,即基地址
R9寄存器初始化后無需再修改,是一個“寄存器常數(shù)”。對于已經(jīng)存儲在R0中的長指針,則使用如下匯編代碼,很容易將其轉(zhuǎn)化為16位地址:
asm(“MOV R1,R9”);//R1=基地址
asm(“SUB R0,R0,R1”);//R0=R0-R1,R0低16位即16位
//短指針值
代碼首先將R9寄存器存儲的基地址轉(zhuǎn)移到R1寄存器,隨后利用單條指令完成從R0寄存器所存長指針值減去R1中存儲的基地址,并將所得結(jié)果保存在R0中。執(zhí)行完成后,R0低16位便是轉(zhuǎn)化后的16位地址。16位地址轉(zhuǎn)化為長指針是類似的轉(zhuǎn)化形式(SUB指令換為ADD指令),在此不再贅述。這種方法充分利用了內(nèi)核提供的高組寄存器,并且簡化了指針轉(zhuǎn)化的算法,減少了所需指令的數(shù)目,提高了運(yùn)行效率,縮短了轉(zhuǎn)換時間,降低MCU因指針替換而產(chǎn)生的時間損失。轉(zhuǎn)換所需指令數(shù)目也壓縮到兩條,減少轉(zhuǎn)換過程所帶來的額外指令代碼的存儲空間開銷。
3 指針替換結(jié)果
μC/OS(含μC/OS-II、μC/OS—III)是適用于低成本MCU的多任務(wù)實(shí)時內(nèi)核。以μC/OS為例,當(dāng)最大任務(wù)數(shù)為10時,整個內(nèi)核需使用12個全局指針型變量,而非指針型變量僅需占用8字節(jié)RAM空間。若使用默認(rèn)的長指針模式,共需12×4+8=56字節(jié);若改用短指針,則需使用12 ×2+8=32字節(jié)。任務(wù)數(shù)目、任務(wù)間通信機(jī)制增多時,指針變量的使用將更頻繁,本文介紹的方法所節(jié)約的RAM空間也更加顯著。在Cortex-M0/M0+處理器替代8/16位MCU的應(yīng)用中,非常有必要使用短指針。
最新版本的μC/OS—III針對帶有計算前導(dǎo)零硬件指令(CLZ)的Cortex—M3/M4處理器進(jìn)行了重大改進(jìn),提高了其優(yōu)先級任務(wù)搜索的效率。但Cortex—M0/M0+的ARMv6指令集簡化掉了CLZ指令,故不適宜使用μC/OS—III。這里以運(yùn)行μC/OS—II v2.92(最多256個任務(wù))為例,說明指針替換效果。實(shí)際上對于內(nèi)存緊張的MCU,μC/OS—II v2.82及以下的版本(最多64個任務(wù))就足夠用了。
μC/OS—II每個任務(wù)都需要使用任務(wù)控制塊TCB(Task Control Block)的數(shù)據(jù)結(jié)構(gòu),來維護(hù)任務(wù)相關(guān)的信息。在μC/OS—II v2.92中,每個任務(wù)的TCB數(shù)據(jù)結(jié)構(gòu)包含9個指針變量,采用本文描述的16位指針替換方法后,每個任務(wù)控制塊均可以節(jié)省18字節(jié)的RAM空間。在μC/OS—II中還存在很多數(shù)據(jù)結(jié)構(gòu),均包含著大量的指針變量。這些數(shù)據(jù)結(jié)構(gòu)采用本文描述的方法所節(jié)約的RAM空間如表1所列。
可以看出,以16位短指針替代ARM編譯器默認(rèn)的32位長指針,能使Cortex—M0/M0+MCU對RAM資源的占用接近8/16位MCU。這一點(diǎn)對“全面替代”是十分重要的。
結(jié)語
以ARM Cortex-M0/M0+為內(nèi)核的32位MCU以其性能、功耗和價格的優(yōu)勢,“全面替代”以8051/52、68S08/12等為代表的8/16位MCU已是大勢所趨。而目前主流ARM IDE中的C編譯器僅支持長指針變量。若將原有的8/16位MCU應(yīng)用程序移植到內(nèi)存資源相當(dāng)?shù)腁RM MCU上,大量長指針變量的使用可能會導(dǎo)致RAM資源不足,而改用更大內(nèi)存的MCU無疑會增加產(chǎn)品成本。通過使用Cortex—M0/M0+內(nèi)核的高組寄存器操作指令,可以實(shí)現(xiàn)長短指針的轉(zhuǎn)換,極大地節(jié)約RAM占用量,為既有應(yīng)用的順利移植提供幫助。
當(dāng)然,長短指針的轉(zhuǎn)換操作會帶來額外的運(yùn)行時間的開銷,轉(zhuǎn)換指令也帶來代碼存儲量的增加。在一定程度上,這種方法是通過增加程序存儲量和運(yùn)行周期的代價來換取數(shù)據(jù)存儲量的減少。由于ARM精簡指令集的結(jié)構(gòu),其指令編碼長度和執(zhí)行速度上都有提升,可以部分抵銷程序存儲量和運(yùn)行周期的開銷,而數(shù)據(jù)存儲量的矛盾則更加突出和棘手。本文介紹的方法對此作出了有益嘗試。
本文介紹的方法需要對已有代碼進(jìn)行一定的改造,筆者希望ARM編譯器能盡快提供面向Cortex—M0/M0+內(nèi)核的短指針優(yōu)化編譯選項(xiàng),為完成ARM對8/16位MCU內(nèi)核的“全面替代”提供良好的支持。
評論