ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ......

15
ARM微控制器代码长度分析 概述 微控制器应用程序代码长度可直接影响产品的成本和功耗,因此,在为嵌入式项目选择 微控制器时,人们始终将其视为一个重要的考虑因素。自Cortex-M3微控制器发布和上 市以来,越来越多的微控制器使用者发现了改用以ARM为内核的产品的好处 功耗更 低、代码长度更小、性能大幅度改善。尽管使用ARM微控制器的好处已经广为人知,但 ARM Cortex微控制器的代码尺寸优势却不那么为人所知。 在本文中我们将阐述为何ARM Cortex微控制器可以减少应用程序代码尺寸,同时实现 高性能和易用性。 关于程序大小的典型误区 误区 18 位和16位控制器的代码尺寸更小 关于从8位微控制器转到ARM微控制器,存在一种普遍的误解,即这会导致代码长度增 加很多——原因何在?很多人有一种错觉:8位微控制器使用8位指令,ARM微控制器 使用 32 位指令。而8位和16位微控制器商稍带误导性质的营销宣传往往又强化了这 一错误印象。 实际上,8位微控制器中的很多指令是16位、24位或者其它大于8位的某个长度,例如 PIC18PIC16的指令长度分别为18位和16位。即使是古老的8051架构,尽管有些指令 的长度为1个字节,但仍有很多指令长达 2个或3个字节。 那么,采用16位微控制器,代码长度就会更好吗?未必如此。以MSP430为例,单操作 数指令可占用4个字节(32 位),而双操作数指令可占用 6个字节(48 位)。在最糟 糕的情况下,MSP430X 中的扩展立即/变址指令会占用8个字节(64 位)。 ARM Cortex微控制器的代码长度如何?ARM Cortex-M3 Cortex-M0处理器基于 Thumb®-2 技术,该技术可提供出色的代码密度。Thumb-2微控制器既包含16位指令, 也包含32位指令,且32位指令是16位指令的超集。在大多数情况下, C编译器使用16 指令。 32 位指令仅在使用16位指令无法完成的操作时才使用。因此, ARM Cortex微控 制器程序中的大多数指令都是16位的。这甚至比8位微控制器中的一些指令还要小。

Transcript of ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ......

Page 1: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

ARM微控制器代码长度分析

概述

微控制器应用程序代码长度可直接影响产品的成本和功耗,因此,在为嵌入式项目选择

微控制器时,人们始终将其视为一个重要的考虑因素。自Cortex-M3微控制器发布和上

市以来,越来越多的微控制器使用者发现了改用以ARM为内核的产品的好处 – 功耗更

低、代码长度更小、性能大幅度改善。尽管使用ARM微控制器的好处已经广为人知,但

ARM Cortex微控制器的代码尺寸优势却不那么为人所知。

在本文中我们将阐述为何ARM Cortex微控制器可以减少应用程序代码尺寸,同时实现

高性能和易用性。

关于程序大小的典型误区

误区 1:8 位和16位控制器的代码尺寸更小

关于从8位微控制器转到ARM微控制器,存在一种普遍的误解,即这会导致代码长度增

加很多——原因何在?很多人有一种错觉:8位微控制器使用8位指令,ARM微控制器

使用 32 位指令。而8位和16位微控制器厂商稍带误导性质的营销宣传往往又强化了这

一错误印象。

实际上,8位微控制器中的很多指令是16位、24位或者其它大于8位的某个长度,例如

PIC18和PIC16的指令长度分别为18位和16位。即使是古老的8051架构,尽管有些指令

的长度为1个字节,但仍有很多指令长达 2个或3个字节。

那么,采用16位微控制器,代码长度就会更好吗?未必如此。以MSP430为例,单操作

数指令可占用4个字节(32 位),而双操作数指令可占用 6个字节(48 位)。在最糟

糕的情况下,MSP430X 中的扩展立即/变址指令会占用8个字节(64 位)。

ARM Cortex微控制器的代码长度如何?ARM Cortex-M3 和Cortex-M0处理器基于

Thumb®-2 技术,该技术可提供出色的代码密度。Thumb-2微控制器既包含16位指令,

也包含32位指令,且32位指令是16位指令的超集。在大多数情况下,C编译器使用16 位

指令。32 位指令仅在使用16位指令无法完成的操作时才使用。因此,ARM Cortex微控

制器程序中的大多数指令都是16位的。这甚至比8位微控制器中的一些指令还要小。

Page 2: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

图1:各种处理器中的单指令的长度

在Cortex-M处理器的编译出的代码中,32位指令的数量只占整个指令数量的一小部分。

例如,在为Cortex-M3 编译时,Dhrystone程序映像中的32位指令只占总指令数量的

15.8%(平均指令长度是18.53位)。对于Cortex-M0,32位指令的比例甚至更低,只有

5.4%(平均指令长度为16.9位)。

误区 2:我的应用程序只处理 8 位和 16 位数据

很多嵌入式开发人员认为,如果他们的应用程序只处理8位数据,那么改用ARM微控制

器就没有任何好处。但是,仔细研究C编译器的输出可以发现,大多数情况下,简单的

“整数”(integer) 数据类型实际上是16位。因此,如果你有一个用整数作为循环变量

的for循环,该循环将一个值与一个整数值相比较,或者该循环使用了一个采用整数的C

库函数(例如 memcpy()),那么你实际上使用了16位或者更大的数据。这会以如下方

式影响代码长度和性能:

• 对于每个整数计算,8位处理器需要多个指令来执行操作。这将直接增加代码长度和

时钟周期数。

• 如果需要将整数值保存到内存中,或者您需要从程序ROM将一个立即值装载到这个整

数中,则需要使用多条指令和多个时钟周期。

• 由于整数会占用两个8位寄存器,因此存放相同数量的整数变量需要更多的寄存器。

如果寄存器阵列中的寄存器数量不足以存放局部变量,则必须将一些变量放到存储器

中。因此,8位微控制器可能会导致更多内存访问,这会增加代码长度并降低性能和功

效。在16位微控制器上处理32位数据时会面临同样的问题。

• 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

内容时,8 位微控制器中需要更多的寄存器来存放整数,因此所需的堆栈操作次数超过

了使用ARM微控制器时的堆栈操作次数。这增加了程序长度,并会影响中断延时,因为

中断服务例程 (ISR) 必须确保使用的所有寄存器都保存在 ISR入口并在 ISR退出时恢

复。在16位微控制器上处理32位数据时会面临同样的问题。

Page 3: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

对于 8 位微控制器用户来说,还有个更糟糕的消息:存储器地址指针占用多个字节,

因此数据处理若涉及到指针使用,效率就会非常低。

误区 3 号:32 位处理器在处理 8位和16位数据时效率不高

所有ARM处理器实际上都能非常高效地处理8位和16位数据。ARM处理器针对带符号和

无符号的8位、16位和32位数据提供了紧凑的存储器访问指令,还为数据类型转换特别

包含了很多指令。总体来看,ARM处理器对8位和16位数据的处理与对32位数据的处理

一样轻松高效。

误区 4 号:ARM 处理器的C库过于庞大

ARM处理器拥有不同的C库选择。对于微控制器应用,很多编译器供应商已经开发了占

用资源要小得多的C库。例如,ARM开发工具有一个名为MicroLib的轻量级C库。这个C

库是为微控制器特别设计的,可使应用程序代码长度更短、更具效率。

误区 5 号:ARM微控制器的中断处理更为复杂

在ARM Cortex微控制器上,中断服务例程只是普通的C子例程。向量中断或者嵌套中断

由嵌套向量中断控制器 (NVIC) 提供支持,无需软件干预。事实上,在 ARM Cortex微

控制器中,中断请求的建立过程和处理要比8位和16位微控制器简单得多,通常只需对

中断优先级编程然后启用该中断即可。

中断向量存放在存储器(通常是闪存)的开始位置的一个向量表中,无需任何软件编程

步骤。发生中断申请时,处理器自动获取相应的中断向量,并开始执行ISR。按照硬件

序列将某些寄存器压入到堆栈中,并在中断处理程序退出时自动恢复。对于硬件堆栈操

作序列没有涵盖的其它寄存器,只有在ISR中使用并修改该寄存器时,才由C编译器生

成的代码将寄存器压入到堆栈中。

改用16位微控制器的效果如何?

16位微控制器在处理16位整数和8位数据(例如字符串)时的效率可能很高,但是代码

长度仍然不如使用ARM处理器那样理想:

处理32位数据:如果应用程序需要处理任何长整型数(32 位)或者浮点型数,那

么16位处理器的效率会大大降低,因为每个处理操作、以及处理器与存储器之间的

数据传送都需要使用多条指令。

寄存器的使用:在处理32位数据时,16 位处理器需要两个寄存器来存放每个32位

变量。这减少了寄存器阵列中所能存放的变量个数,导致处理速度降低,并增加了

堆栈操作和存储器访问次数。

存储器寻址模式:很多16位架构仅提供类似于8位架构的基本寻址模式。因此,当

Page 4: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

它们用于需要处理复杂数据集的应用时,代码密度会很低。

64K字节限制:很多16位处理器的寻址空间只有64K字节,限制了应用程序的功能。

有些16位架构进行了扩展,可允许访问超过64K 字节的存储器,但是,这些扩展会

增加指令代码和时钟周期开销,例如,存储器指针将大于16位,可能需要多条指令

和多个寄存器进行处理。

指令集效率

客户将其应用程序从8位架构移植到ARM Cortex微控制器上时,他们经常会发现总代码

长度减小了。例如,在 Melfas(一家电容式传感触摸屏控制器方面的领先厂商)评估

了Cortex-M0处理器之后,他们发现使用Cortex-M0 取代8051可将程序大小降低一半,

并且在相同时钟频率下可将性能提升到原来的5倍。这样,就可以用同等8051产品的1/5

时钟速度来运行应用程序,从而降低功耗,同时降低了程序闪存大小方面的要求,降低

了产品成本。

那么ARM架构为何具备如此大的优势?关键在于Thumb-2 技术提供了高效的统一指令

集。

强大的寻址模式

ARM Cortex微控制器支持内存传送指令的各种寻址方式。例如:

立即数偏移(地址 = 寄存器的值 + 偏移量)

寄存器偏移((地址 = 寄存器值 1 + 偏移(寄存器值 2))

PC 关联(地址 = 当前程序计数器值 + 偏移量)

堆栈指针关联(地址 = SP + 偏移量)

多寄存器加载和存储,带可选的自动基址更新

多寄存器的 PUSH/POP 指令

由于有上述多种寻址方式,寄存器与存储器之间的数据传送仅需少数指令即可。因为

PUSH 和 POP 指令支持多寄存器,在大多数情况下,若要在函数调用中保存和恢复

寄存器,只需函数开头的一个PUSH指令和函数结尾的一个POP指令即可。甚至可以将

POP指令与函数结尾的返回指令相结合,以进一步减少指令数。

条件分支

几乎所有处理器都提供条件分支指令,但是ARM处理器为带符号数据和无符号数据操作

结果分别提供了不同的分支条件并提供了合理的分支范围,从而带来了条件分支方面的

改进。

例如,在比较Cortex-M0和MSP430的条件分支时,Cortex-M0有更多的条件分支可供使

用,这样就可以生成更为紧凑的代码,不管正在处理的数据是带符号数还是无符号数。

MSP430条件分支可能需要多条指令来实现相同的操作。

Page 5: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

很多8位或者16位控制器通常也是如此,在处理带符号数据时,条件分支中可能也需要

额外的步骤。

除了在Cortex-M0中提供的分支指令外,Cortex-M3 处理器还支持“比较和分支”指令

(CBZ 和 CBNZ)。这进一步简化了某些条件分支的指令序列。

条件执行

除此以外,条件执行功能也能帮助 ARM Cortex-M3微控制器生成更紧凑的代码。

Cortex‐M3支持一个名为 IT (IF‐THEN) 的指令。此指令允许高达4个后续指令以条

件方式执行,从而减少了对条件分支的需求。例如,

if (xpos1 < xpos2) { x1 = xpos1;

x2 = xpos2;

} else {

x1 = xpos2;

x2 = xpos1;

可以转换为以下汇编代码(在 Cortex‐M3 中需要 12 个字节):

CMP R0, R1

ITTEE CC ; if unsigned ―<‖

MOVCC R2, R0

MOVCC R3, R1

MOVCS R3, R0

MOVCS R2, R1

其它架构可能另需一个分支(例如在MSP430中需要14个字节):

CMP.W R14, R13

Page 6: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

JGE Label1 ; if unsigned ―<‖

MOV.W R11, R14

MOV.W R12, R13

JMP Label2

Label1

MOV.W R11, R13

MOV.W R12, R14

Label2

因此,与Cortex-M3相比,MSP430需要多使用两个字节。

乘法和除法

Cortex-M0和Cortex-M3处理器均支持单周期乘法操作。Cortex-M3还为32位或者64位结

果提供了乘法和乘加指令。在处理大变量乘法运算时,这些指令可大幅度减小代码长度。

大多数8位和16位微控制器也有乘法指令,但是由于寄存器大小方面的限制,在结果超

过8位或者16位时乘法操作往往需要多个步骤。

MSP430没有乘法指令(MSP430文档slaa329,参考 1)。要执行乘法操作,就必须使

用内存映射硬件乘法器,或者通过软件用加法和移位来处理乘法操作。即使提供了硬件

乘法器,由于乘法器具有内存映射性质,因此与外部硬件之间的双向数据传送会引起额

外开销。此外,在中断处理程序中使用乘法器会导致乘法器中的现有数据丢失。因此,

在乘法操作之前通常禁用中断,在乘法操作完成之后再重新启用中断。这就额外增加了

软件开销并影响了中断延迟和确定性。

Cortex-M3 处理器还具有无符号和带符号整数除法指令。这降低了需要执行整数除法的

应用程序所需的代码长度,因为C库无需包含用于处理除法操作的函数。

强大的指令集

除了标准数据处理、存储器访问和程序控制指令,Cortex 微控制器还支持很多其它指

令,以帮助完成数据类型转换。Cortex-M3处理器还支持很多位字段操作,这可以降低

外设控制和通信数据处理等任务的软件开销。

突破 64K 字节的内存限制

正如上文所述,很多8位和16位微控制器只适用于64K字节寻址。8 位和16位微控制器

架构的本质决定了当应用程序超过64K字节内存限制时,这些微控制器的代码效率通常

会急剧下降。在 8位和16位微控制器(如 8051、PIC24、C166)中,为解决这个问题,

经常通过由C编译器自动生成的切换代码来进行内存切换或内存分段。每当所需的函数

或者数据位于不同内存页时,就需要内存切换代码,这进一步增加了代码尺寸。

Page 7: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

图2: 8 位或者16位系统中的内存切换或分段开销增加了代码尺寸

内存切换不仅导致代码长度增加,还会大幅度降低系统的性能。如果正在处理的数据位

于不同内存页上,就更是如此(例如,将数据块从一页复制到另一页可能会非常影响性

能)。诸如8051等8位微控制器此时效率尤低,因为MCS-51架构没有为这样的内存切

换功能提供合适的支持。因此,内存切换必须通过保存并更新内存控制(如 I/O 端口

寄存器)来执行。此外,在大小有限的共享内存空间,通常需要执行内存页面切换代码。

同时,有些内存页面可能没有得到充分利用,因而浪费了内存空间。

对于8位和16位微控制器,要支持超过64K字节的内存,会有一定的代价。MSP430X的

设计将程序计数器 (PC) 和寄存器宽度提高到20位,突破了64K字节的内存限制。尽管

避免了内存分页,但MSP430X的一些指令的长度要比原始MSP430的指令长得多。例

如,在使用大内存模式时,双操作数格式的指令可能占用8个而不是6个字节(增加了

33%):

MSP430双操作数指令

MSP430X双操作数指令

图 3: MSP430X对大内存系统的支持增加了某些指令的长度

除了指令长度本身,使用20位寻址还增加了所需的堆栈操作数量。由于存储器只有16

Page 8: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

位,保存20位地址指针需要两个压栈操作,导致额外的指令的增加,并降低了堆栈的利

用效率。

图 4:在MSP430X中使用大内存数据模式增加了代码长度

因此,当地址范围超过64K字节范围,需要使用大内存模式时,MSP430X应用程序的

代码密度会降低。

ARM Cortex微控制器使用32位线性寻址为嵌入式应用程序提供4G字节的内存空间。这

样就不存在分页开销,并且易于使用。

示例

为了与8位和16位处理器比较代码长度,我们编译了很多测试用例并如下加以说明。测

试以德州仪器公司提供的“MSP430 Competitive Benchmarking”文档为依据

(SLAA205C,参考 2)。下面列出的结果展示了总的程序大小,以字节为单位。

MSP430 结果:

所列出的测试是使用IAR Embedded Workbench 4.20.1编译的,启用了硬件乘法器,优

化级别设为“高”(High),并采用“大小”(Size) 优化。除非另有规定,否则使用“Small”

数据模式,双精度型为 32 位。结果请见连接程序输出报告(代码+常量)。

ARM Cortex 处理器结果:

列出的测试是使用RealView开发套件4.0-SP2编译的。优化级别为3,使用最小向量表

和MicroLIB。结果请见连接程序输出报告(向量+代码)。

Test

测试

Generic

MSP430

MSP430F54

38

MSP430F54

38 large

data model

CortexM3

Page 9: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

Math8bit 198 198 202 144

Math16bit 144 144 144 144

Math32bit 2562 244 2562 120

MathFloat 112 1122 116 600

Matrix2dim8bit 180 178 196 184

Matrix2dim 16bit 268 246 290 256

Matrixmult 276 228 连接程序错误 228

Switch8bit 200 218 218 160

Switch16bit 198 218 218 160

Firfilter(说明 1) 1202 1170 1222 716(820 没

有修改)

Dhry 923 893 1079 900

Whet(说明 2) 6434 6308 6614 4384(8496

没有修改)

说明 1:Firfilter测试中的常数数据数组被修改为使用Cortex-M处理器上的16位数据类

型 (const unsigned short int INPUT[])。

说明 2:在ARM C标准中使用某些数学函数 (sin, cos, atan,sqrt, exp, log) 时,默认情

况下使用双精度库。除非采取调整措施,否则这会导致程序长度大幅增加。为了实现同

等情况下的比较,我们对程序代码进行了编辑,以便使用单精度版本(sinf、cosf、atanf、

sqrtd、expf、logf)。同时还将某些常量定义调整为单精度(例如 1.0变为1.0F)。

Page 10: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

图 5:基本操作的代码长度比较

简单测试(整数数学运算、矩阵运算和 switch 运算测试)的总体长度为:

简单测试的总结 Generic MSP430 MSP430F5438 Cortex‐M3

Total size (bytes)

总长度(字节)

1720 1674 1396

Advantage (% smaller)

优势(减小百分比)

- 2.6% 18.8%

对于使用浮点数的应用程序,Cortex 微控制器的明显优势,而 Dhrystone 程序大小则较

为接近。

Page 11: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

图 6:浮点运算和基准套件的代码长度比较

基准和浮点测试的总长度(Dhrystone、Whetstone、Firfilter 和 MathFloat)是:

Summary for simple tests

Generic MSP430 MSP430F5438 Cortex‐M3

Total size (bytes)

9681 9493 6600

Advantage (% smaller) ‐ 1.9% 31.8%

观察结果:

1. 从结果可以看出,在绝大多数情况下,与MSP430相比,Cortex微控制器的代码密

度更高。其余测试的结论也相似。

2. 其中一项测试 (firfilter) 对常数数组使用了整数数据类型。由于ARM处理器中整数为

32 位,MSP430中整数为 16 位,因此对程序进行了修改以便于直接比较。

3. 当MSP430中使用大数据内存模式时,代码长度增加了20% (dhrystone)。

4. 我们无法再现TI公司文档中所声明的结果。这可能是因为代码长度计算结果中省略了

ROM中存储的常数数据。

Page 12: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

关于浮点数的其它研究

分析whetstone基准测试的结果时可以清楚地看出,MSP430 C编译器只生成单精度浮

点运算,而ARM C编译器为用到的某些数学函数生成了双精度浮点运算。

将代码更改为仅使用单精度浮点之后,代码尺寸大幅下降,远小于MSP430的代码尺寸。

IAR MSP430 编译器有一个定义浮点的选项: ―Size of type double‖(双精度型的长度),

默认情况下设置为 32 位(单精度)。如果设置为 64 位(如 ARM C 编译器),那么代码

长度会大幅增加。

Program size Generic MSP430 MSP430430F5438

Type Double is 32‐bit

6434 6308

Type Double is 64‐bit

11510 11798

这些结果与使用 ARM Cortex-M3 处理器时观察到的结果相一致。

Program size Cortex‐M3

修改 Whetstone,以便只使用单精度。 4384

Whetstone 的现成可用编译(对数学函数

使用双精度)

8496

某些小型微控制器应用程序的 C 代码可能只需处理从 12 位/14 位 ADC 生成的源数据,

这时将双精度型设置为 32 位的选项是非常明智的。使用其它默认类型的基准测试可能

会产生很大的差异,无法显示精确的比较结果。

关于如何利用 CortexM 微控制器获取最小代码尺寸的建议

使用 MicroLib

ARM开发工具中有一个选项,可使用MicroLIB来取代标准C库。MicroLIB适合大多数嵌

入式应用程序,与使用标准C库相比,它的代码长度要小得多。

确保面积优化的使用

Cortex-M微控制器的性能远高于16位和8位微控制器,因此在从这些微控制器移植应用

程序时,通常可以选择最高面积优化而不是速度优化。所实现的性能仍然远远高于以相

同时钟频率运行的16位或8位系统。

使用合适的数据类型

从 8 位或者 16 位微控制器移植应用程序时,可能需要修改常数数组的数据类型,以实

现最优程序长度。例如,在 8 位或者 16 位微控制器中,整数通常为 16 位,而在 ARM

微控制器中,整数为 32 位。

Page 13: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

类型 在8051中的位数 在MSP430中的位数

在 ARM 中的位数

“char”, “unsigned

char”

8 8 8

“enum” 8/16 16 8/16/32(选择最小的)

“short”, “unsigned

short”

16 16 16

“int”, “unsigned int”

16 16 32

“long”, “unsigned

long”

32 32 32

Float 32 32 32

double

32 32 64

从8位或者16位架构移植常量数组时,应将数据类型从“int”修改为“short int”,以

确保常量数组保持相同长度。例如,

const int mydata = { 1234, 5678, …};

应修改为:

const short int mydata = { 1234, 5678, …};

对于整数变量数组(非常量数据),从integer改为short integer还能防止软件移植期间

增加内存使用。大多数其它数据(例如变量)不需要修改。

浮点函数

我们在whetstone测试分析中发现:8位和16位微控制器将有些浮点函数定义为单精度,

而ARM微控制器默认情况下将这些函数定义为双精度。从8位或者16位微控制器将应用

程序移植到ARM微控制器时,您可能需要将数学函数调整为单精度版,并修改常量定义,

以确保程序以相同方式运行。例如,在whetstone程序代码中,一段代码使用的某些函

数在 ARM 编译器中是双精度型:

X=T*atan(T2*sin(X)*cos(X)/(cos(X+Y)+cos(X‐Y)‐1.0));

Y=T*atan(T2*sin(Y)*cos(Y)/(cos(X+Y)+cos(X‐Y)‐1.0));

如果我们希望只使用单精度,则必须将程序代码更改为:

X=T*atanf(T2*sinf(X)*cosf(X)/(cosf(X+Y)+cosf(X‐Y)‐1.0F));

Y=T*atanf(T2*sinf(Y)*cosf(Y)/(cosf(X+Y)+cosf(X‐Y)‐1.0F));

其它常量定义,如:

Page 14: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

/* Module 7:

Procedure calls */

X = 1.0;

Y = 1.0;

Z = 1.0;

应更改为以下形式,以实现单精度表示:

/* Module 7:

Procedure calls */

X = 1.0F;

Y = 1.0F;

Z = 1.0F;

将外设定义为数据结构

您也可以将外设中的寄存器定义为数据结构来减小程序长度。例如,不必将SysTick定

时器寄存器表示为:

#define SYSTICK_CTRL (*((volatile unsigned long *)(0xE000E010)))

#define SYSTICK_LOAD (*((volatile unsigned long *)(0xE000E014)))

#define SYSTICK_VAL (*((volatile unsigned long *)(0xE000E018)))

#define SYSTICK_CALIB (*((volatile unsigned long *)(0xE000E01C)))

你可以将SysTick寄存器定义为:

typedef struct

{

volatile unsigned int CTRL;

volatile unsigned int LOAD;

volatile unsigned int VAL;

unsigned int CALIB;

} SysTick_Type;

#define SysTick ((SysTick_Type *) 0xE000E010)

这样,只需在程序ROM中保存一个地址常量。寄存器访问可用这个地址常量和不同的

地址偏移去访问不同的寄存器。如果外设需要硬件寄存器访问序列,那么使用数据结构

可减小代码长度并提高性能。大多数8位微控制器没有上述寻址模式,使得执行相同任

务时所需的代码尺寸增加不少。

结论

ARM 处理器在显著改善性能的同时,可提供比8位或者16位架构更小的代码尺寸。

Page 15: ARM Microcontroller Code Size Analysis - eetrend.com€¦ · 关于程序大小的典型误区 ... • 由于在通过堆栈将变量传递给函数时,或者在上下文切换或中断服务期间保存寄存器

诚然,8位微控制器用户换到16位架构可以解决原有的一些问题,但是用户获得的总体

效益远不如直接切换到ARM Cortex-M处理器。

过去几年来,ARM 微控制器的功耗和成本大幅降低,ARM 已经成为很多嵌入式项目的

最佳选择。

参考文献

本文参考了以下关于 MSP430 的文章:

Reference

1 MSP430 Competitive Benchmarking

http:// focus.ti.com/lit/an/slaa205c/slaa205c.pdf

2 Efficient Multiplication and Division Using MSP430

http://focus.ti.com/lit/an/slaa329/slaa329.pdf