当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]本章主要介绍嵌入式应用程序的设计方法。本章中的一些实例程序是以ARM公司的Realview2.2为开发平台。由于目前嵌入式应用环境相差非常大,这里主要是通过这些实例程序来更直接地介绍嵌入式应用系统的开发方法,具体的代码因具体的嵌入式环境不同而有所差异。

本章主要介绍嵌入式应用程序的设计方法。本章中的一些实例程序是以ARM公司的Realview2.2为开发平台。由于目前嵌入式应用环境相差非常大,这里主要是通过这些实例程序来更直接地介绍嵌入式应用系统的开发方法,具体的代码因具体的嵌入式环境不同而有所差异。

13.1 基于ARM处理器的嵌入式系统设计

ARM系列处理器是RISC(Reducded Instruction Set Computing)处理器。很多基于ARM的高效代码的程序设计策略都源于RISC处理器。和很多RISC处理器一样,ARM系列处理器的内存访问也要求数据对齐,即存取“字(Word)”数据时要求四字节对齐,地址的bits[1:0]=0b00;存取“半字(Halfwords)”时要求两字节对齐,地址的bit[0]=0b0;存取“字节(Byte)”数据时要求该数据按其自然尺寸边界(Natural Size Boundary)定位。

ARM编译程序通常将全局变量对齐到自然尺寸边界上,以便通过使用 LDR和STR指令有效地存取这些变量。

这种内存访问方式与多数CISC(Complex Instruction Set Computing)体系结构不同,在CISC体系结构下,指令直接存取未对齐的数据。因而,当需要将代码从CISC体系结构向 ARM处理器移植时,内存访问的地址对齐问题必须予以注意。在RISC体系结构下,存取未对齐数据无论在代码尺寸或是程序执行效率上,都将付出非常大的代价。

注意

在ARM11处理器上,新增加了支持非内存对齐数据访问的硬件,此结构在本章中不作讨论。

下面将从4个方面详细讨论在ARM体系结构下的程序设计:

· 未对齐指针;

· 结构体中的未对齐字段;

· 用于半字存取的Load指令;

· 移植代码并检测非对齐存取。

13.1.1 未对齐的数据指针

C和C++编程标准规定,指向某一数据类型的指针,必须和该类型的数据地址对齐方式一致,所以ARM编译器期望程序中的C指针指向存储器中字对齐地址,因为这可使编译器生成更高效的代码。

比如,如果定义一个指向int数据类型的指针,用该指针读取一个字,ARM 编译器将使用LDR指令来完成此操作。如果读取的地址为4的倍数(即在一个字的边界)即能正确读取。但是,如果该地址不是4的倍数,那么,一条LDR指令返回一个循环移位结果,而不是执行真正的未对齐字载入。循环移位结果取决于该地址相对于字的边界的偏移量和系统所使用的端序(Endianness)。例如,如果代码要求从指针指向的地址0x8006载入数据,即要载入0x8006、0x8007、0x8008和0x8009 4个字节的内容。但是,在ARM处理器上,这个存取操作载入了0x8004、0x8005、0x8006和0x8007字节的内容。这就是在未对齐的地址上使用指针存取所得到的循环移位结果。

因而,如果想将指针定义到一个指定地址(该地址为非自然边界对齐),那么在定义该指针时,必须使用__packed限定符来定义指针:

例如:

__packed int *pi; // 指针指向一个非字对其内存地址

使用了__packed限定符限定之后,ARM编译器将产生字节存取命令(LDRB或STRB指令)来存取内存,这样就不必考虑指针对齐问题。所生成的代码是字节存取的一个序列,或者取决于编译选项、跟变量对齐相关的移位和屏蔽。但这会导致系统性能和代码密度的损失。

值得注意的是,不能使用__packed限定的指针来存取存储器映射的外围寄存器,因为ARM编译程序可使用多个存储器存取来获取数据。因而,可以对实际存取地址附近的位置进行存取,而这些附近的位置可能对应于其他外部寄存器。当使用了位字段(Bitfield)时,ARM程序将访问整个结构体,而非指定字段。

13.1.2 结构体中未对齐字段

与全局变量位于其自然尺寸边界相同,结构体(Structure)中的域字段(Filed)也如此。也就是说编译程序经常要在字段间插入填充字节(Padding)来确保域字段对齐。当编译程序插入填充字节时,编译器将产生以下警告信息。

#1301-D: padding inserted in struct mystruct

可以使用-remark编译选项使编译器产生备份信息,或使用-diag_warning选项选择编译器产生的备份信息。

如果不希望编译器产生填充字节,可以使用__packed限定符来创建字段之间没有填充字节的结构,且这些结构需要非对齐存取。

如果ARM编译器能够确定所访问结构体的对齐方式,那么它就可以自动识别所存取结构体中的字段的对齐方式。在这些情况下,编译程序尽可能地采用更有效的对齐字或半字存取方式。否则,编译器将使用多个对齐存储器存取(LDR、STR、LDM和STM)与固定移位和屏蔽相结合来存取存储器中的字节。

对非对齐元素的存取是通过内联还是通过调用一个函数来完成,由编译程序-Ospace(默认,调用一个函数)和-Otime(执行非对齐存取内联)选项来控制。

例如:

创建一个名为foo.c源文件。

__packed struct mystruct {

int aligned_i;

short aligned_s;

int unaligned_i;

};

struct mystruct S1;

int foo (int a, short b)

{

S1.aligned_i=a;

S1.aligned_s=b;

return S1.unaligned_i;

}

使用armcc -c -Otime foo.c编译。所生成的代码为:

MOV r2,r0

LDR r0,|L1.84|

MOV r12,r2,LSR #8

STRB r2,[r0,#0]

STRB r12,[r0,#1]

MOV r12,r2,LSR #16

STRB r12,[r0,#2]

MOV r12,r2,LSR #24

STRB r12,[r0,#3]

MOV r12,r1,LSR #8

STRB r1,[r0,#4]

STRB r12,[r0,#5]

ADD r0,r0,#6

BIC r3,r0,#3

AND r0,r0,#3

LDMIA r3,{r3,r12}

MOV r0,r0,LSL #3

MOV r3,r3,LSR r0

RSB r0,r0,#0x20

ORR r0,r3,r12,LSL r0

BX lr

其中,“|L1.84|”为结构体mystruct在内存中的地址。

从上例可以看出,所有对结构体域成员的访问都是通过字节访问实现的,所以这种不对齐内存访问无论从代码占用的存储器空间,还是代码的执行时间上都要付出一定的代价。

然而,开发者可以给编译器提供更多的信息,使其知道结构体内哪个字段是对齐的,哪个字段不是。为此,必须将未对齐字段声明为__packed,并从struct本身除去__packed属性。通过这种方法可以保证对struct中自然对齐成员的快速访问。而且,哪个字段是未对齐的也更清楚,但这样就增加了访问struct结构的难度,当用户从结构中增加或删除字段时需要特别小心。

修改上例中结构体的定义,来减少访问结构体的开销。具体代码如下所示。

struct mystruct {

int aligned_i;

short aligned_s;

__packed int unaligned_i;

};

struct mystruct S1;

对修改后的程序进行编译,产生的汇编代码如下所示。

MOV r2,r0

LDR r0,|L1.32|

STR r2,[r0,#0]

STRH r1,[r0,#4]

LDMIB r0,{r3,r12}

MOV r0,r3,LSR #16

ORR r0,r0,r12,LSL #16

BX lr

从编译后的汇编代码不难看出,对结构体内符号自然边界对齐的域,编译器直接使用相应的Load/Store指令进行访问,而只有那些非自然边界对齐的域,编译器才进行附加处理。这样,从时间和空间两方面减小了程序的开销。

同一原理也适应于联合体结构(unions)。使用在存储器中未对齐的联合组件的__packed属性。

13.1.3 用于半字存取的非对齐 LDR指令

一些特殊情况下,ARM编译程序可以生成非对齐LDR指令。特别是编译程序从存储器中载入半字时将使用该方法。这是因为,通过使用相应地址,所需的半字可以载入到寄存器的高半段(bits[31:16]),然后通过移位,将有效数据移到寄存器的低半段(bits[15:0])。这样做的目的是通过减少内存访问次数来减少程序的执行时间。通过上面的方法,程序只需要一次存储器的访问,而使用LDRB指令做同样的操作需要两次存储器的存取,而且还要为将这两个字节合并在一起添加特殊的代码。在ARM体系结构v3和其早期版本中,通常使用该方法进行所有的半字载入。但在ARMv4及其以后版本中,出现了专门的半字载入指令,这种方法逐渐被取代。但是,非对齐LDR指令仍可能会出现,比如在一个充填结构中存取一个非对齐short域类型。

注意

在RVCT中已经不再支持ARMv3架构。

13.1.4 移植代码并检测非对齐内存访问

在非RISC体系结构的处理器上执行的代码中,可能会存在使用指针访问非自然边界对齐的数据类型。这种操作,在ARM体系结构中是不允许的。这就给代码的移植带来很大困难。用户必须识别并更改此类内存访问代码才能使其在RISC体系结构的处理器上正确执行。

识别非对齐存取可能会很困难,因为使用非对齐地址进行的载入或存储操作会产生不正确的动作。追踪到底是哪部分的C源程序造成了这个问题是很困难的。

具有完整存储器管理单元(MMUs)的ARM处理器,例如ARM920TTM,支持内存对齐检测功能,用户可以通过设置MMU使处理器检测每一次的内存访问以确保其被正确地对齐。如果出现非对齐内存访问,MMU将产生数据中断。这样就给追踪出错代码带来了很大的方便。

对于一些简单的没有MMU的内核,如ARM7TDMI,最好的方法是在ASIC(Application Specific Integrated Circuit)/ASSP(Application Specific Standard Product)内部实现对齐检测。可以增加专门的ARM内核扩展硬件,由其监控每次数据的访问的内存大小和存取地址总线的最低有效位。在非对齐存取的情况下,可以通过配置ASIC/ASSP产生中断信号(ABORT)。ARM公司建议在需要运行移植代码设备中包含这样的ASIC/ASSP逻辑。

如果在设计系统时,将系统设计成为当出现非对齐的内存访问时产生异常,则必须安装数据中断异常处理程序(Data Abort Handler)。出现非对齐存取时,程序进入数据中断处理程序,并由此识别位于返回地址(在LR中保存的地址)减8(r14-8)的出错数据存取指令。

一旦出现数据中断异常,必须通过改变C源程序来修复非对齐的数据访问。使用下列指令可有条件地完成修复:

#ifdef __arm

#define PACKED __packed

#else

#define PACKED

#endif

:

PACKED int *pi;

:

由于代码大小和性能上的开销,最好尽可能少采用存取非对齐数据。

ARM编译器支持--pointer_alignment和--min_array_alignment与内存对齐相关的编译选项,详见ARM相关文档。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

2024年4月18日,国民技术第四代可信计算芯片NS350 v32/v33系列产品正式发布并开始量产供货。NS350 v32/v33是一款高安全、高性能、超值可信密码模块2.0 (TCM 2.0)安全芯片,适用于PC、服...

关键字: PC 服务器平台 嵌入式系统

2024年,嵌入式系统将走向何方?如何才能走在趋势的前沿?从工厂到家电,从医院里昂贵的医疗设备,到随处可见的可穿戴设备,我们身边的联网设备越来越多,生活更加绿色低碳,嵌入式系统功不可没。ST于3月19日成功举办STM32...

关键字: 嵌入式系统 可穿戴设备

随着嵌入式计算设备基础硬件性能的提升,在通信、工业制造、交通运输等领域,嵌入式系统逐渐承担起更加综合化和关键的任务,这也导致嵌入式软件在结构愈加复杂的同时,其安全性问题也越来越受到重视。堆栈是嵌入式软件中的重要存储结构,...

关键字: 嵌入式软件 堆栈

在嵌入式系统开发、调试和测试过程中,J-Link作为一种高效的调试工具,为开发者提供了极大的便利。然而,要想充分发挥J-Link的功能,首先需要正确安装其驱动程序。本文将详细介绍J-Link驱动的安装过程,并深入解析其中...

关键字: jlink 嵌入式系统 嵌入式开发

嵌入式开发是一种专门针对特定硬件平台设计和实现软件系统的工程实践,它涵盖了从需求分析、系统设计、编程实现、调试测试直到产品部署及维护的全过程。本文将深入探讨嵌入式开发的主要阶段,分解其流程并阐述每个步骤的关键要点,以便于...

关键字: 嵌入式开发 嵌入式软件

随着科技的飞速发展,单片机和嵌入式系统在现代电子设备中的应用越来越广泛。它们不仅提高了设备的智能化水平,还推动了各行各业的创新与发展。在单片机和嵌入式系统的开发中,编程语言的选择至关重要。本文将深入探讨单片机和嵌入式系统...

关键字: 单片机 嵌入式系统 电子设备

Windows Embedded Compact 7(简称WinCE)是一种专为嵌入式系统设计的操作系统,具有体积小、效率高、可定制性强的特点。在WinCE中设置自动运行软件,通常是为了满足设备在启动后自动执行特定任务的...

关键字: 嵌入式系统 软件 操作系统

【2024年3月25日,德国慕尼黑和瑞典瓦尔贝格讯】不同汽车的独特性给汽车零部件供应商和OEM厂商等带来了挑战,因为每辆车的驾驶方式、驾驶地点、驾驶者、设计、用途以及道路和交通状况都是独一无二的。为保证每辆汽车都能正常运...

关键字: AI 机器学习 嵌入式系统

GD32F303作为一款先进的微控制器,在嵌入式系统领域有着广泛的应用。本文旨在深入探究GD32F303的发布时间,并分析其背后的技术背景和市场环境。通过对相关资料的梳理和分析,本文揭示了GD32F303发布的历史背景、...

关键字: GD32F303 微控制器 嵌入式系统

物联网控制模块作为连接物理世界与数字世界的桥梁,在现代科技领域扮演着至关重要的角色。本文将详细探讨物联网控制模块的定义、功能、应用领域以及未来发展趋势,旨在为读者提供全面而深入的了解,并展望其在未来物联网产业中的广阔前景...

关键字: 物联网 控制模块 嵌入式系统
关闭
关闭