ARM Cortex―M0/M0+單片機(jī)的指針變量替換方法
摘要:32位ARM Cortex-M0/M0+內(nèi)核定位于“全面替代”各類8/16位微控制器(MCU)內(nèi)核,其硬件設(shè)計支持使用16位短指針變量。目前主流的ARM編譯器僅使用32位長指針變量,這對于資源有限的MCU來說十分浪費(fèi)。為了優(yōu)化指針變量的使用方式、節(jié)約RAM資源,本文給出一種替換長指針的方法,并以運(yùn)行μC/OS-II為例,說明替換效果。
本文引用地址:http://www.ex-cimer.com/article/201609/304500.htm引言
Cortex—M0/M0+是RISC類型的低端ARM內(nèi)核,其指令集與高端ARM兼容,在性能、功耗和價格方面遠(yuǎn)優(yōu)于傳統(tǒng)的以8051、68S08/12等為代表的8/16位CISC(復(fù)雜指令流)CPU。目前,各半導(dǎo)體廠商紛紛以之替代原有的8/16位MCU內(nèi)核,32位ARM MCU全面替代8/16位MCU已是大勢所趨。
Cortex—M0+將Cortex—M0的3級流水線簡化為2級,并進(jìn)一步降低功耗、提高性能,這些優(yōu)點使得Cortex—M0+成為目前8/16位處理器較好的替代者。不過替代8/16位MCU的低端ARM往往內(nèi)存資源非常有限,目前典型的Cortex—M0/M0+MCU往往僅有2 KB、4 KB或8 KB,最多16 KB片內(nèi)RAM,F(xiàn)lash一般也不大于64KB。對這類MCU編程,使用短指針變量就夠了。而目前ARM處理器的集成開發(fā)環(huán)境(IDE)中的C編譯器,延續(xù)Cortex—M3/M4的使用傳統(tǒng),仍使用32位長指針變量。這無形中多占用了1倍的RAM資源。這里以飛思卡爾ARM Cortex—M0+處理器中的Kine tis系列MCU為例,說明如何使用16位短指針替代32位長指針,以便在將原有的以8/16位MCU為核心的產(chǎn)品升級到采用32位ARM內(nèi)核時,不增加系統(tǒng)開銷。特別是若使用了實時操作系統(tǒng),系統(tǒng)的內(nèi)存會更加緊張。在專門面向Cortex—M0/M0+的集成開發(fā)環(huán)境(IDE)推出前,可使用本文提供的替換方法,以降低系統(tǒng)的RAM開銷,提升系統(tǒng)的性能。
1 指針替換原理
32位ARM內(nèi)核的內(nèi)部寄存器都是32位的,其尋址空間可以達(dá)到4 GB,通常也應(yīng)使用32位的地址指針。但在數(shù)據(jù)空間、程序空間和I/O空間都不大于64 KB的情況下,可以采用1個32位基地址加1個16位偏移量的方法,合成ARM需要的長指針。
以Cortex—M0+為內(nèi)核的MCU,其SRAM、FLASH很少超過64 KB,一般使用16位的偏移量指針就能滿足需要。
以Freescale公司的KL25Z128 MCU為例,有16 KBSRAM和128 KB FLASH存儲空間。其SRAM的地址范圍是0x1FFF_F000~0x2000_2FFF,使用16位的偏移量指針便可以滿足尋址范圍的要求。
圖1說明了長指針替換方法的基本原理,通過使用一個32位的RAM基地址,完成原始32位絕對地址與相對基地址的16位相對偏移地址的相互轉(zhuǎn)化。
其轉(zhuǎn)化關(guān)系如下所示:
Address_32bits=Address_16bits+Address_base (1)
Address_16bits=Address_32bits_Address_base (2)
對于KL25Z128,Address_base基地址值可選擇為0x1FFF F000。通過以上方法的轉(zhuǎn)化,32位的地址空間0x1FFF_F000~0x2000_2FFF(16 KB)可以轉(zhuǎn)化為16位的地址空間0x0000~0x3FFF(16 KB)。
2 指針替換方案
2.1 常量形式實現(xiàn)方案
以下使用Freescale公司推薦的IDE CodeWarriorv10.5予以說明。
程序中利用宏定義了一個32位常數(shù)的基地址,顯然也可以使用一個全局變量或寄存器變量來存儲基地址。在將長指針變量pt_addr_32轉(zhuǎn)化為16位地址“指針”時,需先將指針變量pt_addr_32做強(qiáng)制類型轉(zhuǎn)化,變?yōu)?2位無符號數(shù)后再進(jìn)行基地址扣除的計算。該段代碼還聲明了一個16位無符號數(shù)的數(shù)據(jù)類型pointer_16,用來定義或存儲16位地址偏移量,例如使用如下語句來定義一個16位的指針變量:
pointer_16 ptl6_data=addr_16(data);
ptl6_data的值便是指向data的16位“指針”(轉(zhuǎn)化而成的16位地址偏移量值),編譯器編譯出的匯編代碼如下所示:
需要將16位地址轉(zhuǎn)化為長指針時,以下面的整型數(shù)據(jù)賦值操作為例:
int temp=*(int*)(addr_32(ptl6_data));
數(shù)據(jù)data的值賦值給了變量temp,其中int數(shù)據(jù)類型可以替換成任意其他的數(shù)據(jù)類型(例如unsigned int、unsigrted short、short、unsigned char、char等)。
2.2 高組寄存器優(yōu)化方案
Cortex—M系列內(nèi)核是專門為ARM MCU設(shè)計的,僅支持無條件執(zhí)行的Thumb指令。Cortex—M0/M0+使用ARMv6指令集,而Cortex-M3/M4使用ARMv7指令集。ARMv6對ARMv7做了高度簡化,僅保留了其中56條指令。指令中除個別32位指令外,都是16位指令。Cortex—M0/M0+的內(nèi)部寄存器結(jié)構(gòu)與高端ARM兼容,但低端MCU應(yīng)用往往不需要那么多寄存器,Cortex—M0/M0+僅提供了R0~R12共13個通用寄存器。這些通用寄存器分為兩部分:低組寄存器(Low registers,R0~R7),高組寄存器(High registers,R8~R12)。Cortex—M0/M0+犧牲了大量面向高組寄存器的指令,盡量減少32位指令的使用。實際上Cortex—M0/M0+的指令集中僅有以下3條指令支持高組寄存器R8~R12:
MOV
ADD
CMP
這里Rd和Rm之一可以是高組寄存器??梢钥闯?,對于高組寄存器,ARMv6僅保留了高低組寄存器間數(shù)據(jù)傳遞、不影響標(biāo)志位的加法運(yùn)算和單獨(dú)的地址比較這3種操作,其用處顯然是為了支持將高組寄存器用于地址運(yùn)算。
目前基于gcc的主流ARMC編譯器對Cortex—M0/M0+的高組寄存器采取盡量不予使用的策略,在定義指針變量時,僅使用長指針。而分析ARMv6指令集的設(shè)計初衷,顯然應(yīng)該用高組寄存器和相關(guān)指令。這對于旨在替代8/16位MCU的低成本ARM器件非常必要。
評論