新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > ARM Cortex―M0/M0+单片机的指针变量替换方法

ARM Cortex―M0/M0+单片机的指针变量替换方法

作者:时间:2016-09-12来源:网络收藏

摘要:32位ARM Cortex-M0/M0+内核定位于“全面替代”各类8/16位微控制器(MCU)内核,其硬件设计支持使用16位短指针变量。目前主流的ARM编译器仅使用32位长指针变量,这对于资源有限的MCU来说十分浪费。为了优化指针变量的使用方式、节约资源,本文给出一种替换长指针的方法,并以运行μC/OS-II为例,说明替换效果。

本文引用地址:http://www.eepw.com.cn/article/201609/304500.htm

引言

Cortex—M0/M0+是RISC类型的低端ARM内核,其指令集与高端ARM兼容,在性能、功耗和价格方面远优于传统的以8051、68S08/12等为代表的8/16位CISC(复杂指令流)CPU。目前,各半导体厂商纷纷以之替代原有的8/16位MCU内核,32位ARM MCU全面替代8/16位MCU已是大势所趋。

Cortex—M0+将Cortex—M0的3级流水线简化为2级,并进一步降低功耗、提高性能,这些优点使得Cortex—M0+成为目前8/16位处理器较好的替代者。不过替代8/16位MCU的低端ARM往往内存资源非常有限,目前典型的Cortex—M0/M0+MCU往往仅有2 KB、4 KB或8 KB,最多16 KB片内,Flash一般也不大于64KB。对这类MCU编程,使用短指针变量就够了。而目前ARM处理器的集成开发环境(IDE)中的C编译器,延续Cortex—M3/M4的使用传统,仍使用32位长指针变量。这无形中多占用了1倍的资源。这里以飞思卡尔ARM Cortex—M0+处理器中的Kine tis系列MCU为例,说明如何使用16位短指针替代32位长指针,以便在将原有的以8/16位MCU为核心的产品升级到采用32位ARM内核时,不增加系统开销。特别是若使用了实时操作系统,系统的内存会更加紧张。在专门面向Cortex—M0/M0+的集成开发环境(IDE)推出前,可使用本文提供的替换方法,以降低系统的RAM开销,提升系统的性能。

1 原理

32位ARM内核的内部寄存器都是32位的,其寻址空间可以达到4 GB,通常也应使用32位的地址指针。但在数据空间、程序空间和I/O空间都不大于64 KB的情况下,可以采用1个32位基地址加1个16位偏移量的方法,合成ARM需要的长指针。

以Cortex—M0+为内核的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位相对偏移地址的相互转化。

ARM Cortex—M0/M0+单片机的指针变量替换方法

其转化关系如下所示:

Address_32bits=Address_16bits+Address_base (1)

Address_16bits=Address_32bits_Address_base (2)

对于KL25Z128,Address_base基地址值可选择为0x1FFF F000。通过以上方法的转化,32位的地址空间0x1FFF_F000~0x2000_2FFF(16 KB)可以转化为16位的地址空间0x0000~0x3FFF(16 KB)。

2 方案

2.1 常量形式实现方案

以下使用Freescale公司推荐的IDE CodeWarriorv10.5予以说明。

ARM Cortex—M0/M0+单片机的指针变量替换方法

程序中利用宏定义了一个32位常数的基地址,显然也可以使用一个全局变量或寄存器变量来存储基地址。在将长指针变量pt_addr_32转化为16位地址“指针”时,需先将指针变量pt_addr_32做强制类型转化,变为32位无符号数后再进行基地址扣除的计算。该段代码还声明了一个16位无符号数的数据类型pointer_16,用来定义或存储16位地址偏移量,例如使用如下语句来定义一个16位的指针变量:

pointer_16 ptl6_data=addr_16(data);

ptl6_data的值便是指向data的16位“指针”(转化而成的16位地址偏移量值),编译器编译出的汇编代码如下所示:

ARM Cortex—M0/M0+单片机的指针变量替换方法

需要将16位地址转化为长指针时,以下面的整型数据赋值操作为例:

int temp=*(int*)(addr_32(ptl6_data));

数据data的值赋值给了变量temp,其中int数据类型可以替换成任意其他的数据类型(例如unsigned int、unsigrted short、short、unsigned char、char等)。

2.2 高组寄存器优化方案

Cortex—M系列内核是专门为ARM MCU设计的,仅支持无条件执行的Thumb指令。Cortex—M0/M0+使用ARMv6指令集,而Cortex-M3/M4使用ARMv7指令集。ARMv6对ARMv7做了高度简化,仅保留了其中56条指令。指令中除个别32位指令外,都是16位指令。Cortex—M0/M0+的内部寄存器结构与高端ARM兼容,但低端MCU应用往往不需要那么多寄存器,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仅保留了高低组寄存器间数据传递、不影响标志位的加法运算和单独的地址比较这3种操作,其用处显然是为了支持将高组寄存器用于地址运算。

目前基于gcc的主流ARMC编译器对Cortex—M0/M0+的高组寄存器采取尽量不予使用的策略,在定义指针变量时,仅使用长指针。而分析ARMv6指令集的设计初衷,显然应该用高组寄存器和相关指令。这对于旨在替代8/16位MCU的低成本ARM器件非常必要。


上一页 1 2 下一页

评论


相关推荐

技术专区

关闭