从 Arm Compiler 5 迁移到 Arm Compiler 6

在开始之前,建议先备份你的工程代码。

迁移条件

要使用 ARM Compiler 6,建议MDK的版本至少为:

  • MDK版本5.23或更高版本

MDK版本5.23提供两个编译器,分别是 ARM Compiler 5.06 和 ARM Compiler 6.6。

软件包也需要支持 ARM Compiler 6,以下是支持 ARM Compiler 6 的最低软件包版本:

  • Keil MDK-Middleware包: 版本7.4.0及以上
  • Keil ARM Compiler Support 包: 版本1.3.0及以上
  • ARM CMSIS 包: 版本5.0.1及以上

切换编译器

  1. 使用MDK打开工程。

  2. 选择 Project - Options for Target from the menu

  3. 点击 Target 选项卡,找到 ARM Compiler: 下拉列表。

  4. 设置ARM编译器为 Version 6

  5. 点击 OK 键确认更改。

切换后的ARM Compiler 6所有设置都为默认值。

设置警告级别

ARM Compiler 6 提供的警告级别比 ARM Compiler 5 多,如果你习惯 ARM Compiler 5 的警告级别,选择AC5-like Wamings

可以通过在参数前面加上-Wno-来禁用特定诊断组的警告。

例如,通过选项-Wno-missing-noreturn禁用了–Wmissing-noreturn
Misc Controls

在迁移的第一步中,建议将级别切换为“无警告”。 这将使您可以专注于错误消息。

解决所有错误信息后,选择AC5-like Wamings,设置-Wno-invalid-source-encoding选项:禁用源代码编码检测,因为LCD和打印信息有中文,编译器认为这些是无效编码。

如果想测试下代码是否规范,可以选择All wamings

设置优化级别

选择-Os babanced级别,平衡代码大小和性能。
如果想代码执行速度快,可以选择-O2-O3-Ofast级别,优化性能(速度),优化依次提升,但生成的代码大小可能会变大。
如果想减少代码大小,可以选择-Os babanced-Oz image size级别,代码大小优化依次提升。
比如我的工程,使用-Oz image size级别编译出的code大小为103026、使用-Os babanced级别编译出的code大小为115848字节、使用-O3级别编译出的code大小为160536。差别很大。

-O0级别没有做任何优化。注意ARM Compiler 5的-O0实际上是有优化的,所以ARM Compiler 6的-O1级别与ARM Compiler 5的-O0级别最为相似,都可以获取良好的调试体验,在调试阶段可以选用。

不兼容的语言扩展

主要是代码中的__align(x)__packed__weak等编译器扩展语言。解决方法是使用CMSIS定义的相关宏。

  1. 替换CMSIS头文件,这里使用的是5.6.0版本的CMSIS。
    如果安装了较新的Keil,可以在路径.\Keil_v5\ARM\PACK\ARM\CMSIS目录中找到合适的CMSIS版本。
    .\Keil_v5\ARM\PACK\ARM\CMSIS\5.6.0\CMSIS\Core\Include内的文件替换到工程code_cm3.h所在的文件夹。

  2. 修改lwip协议栈的cc.h文件,因为lwip使用到了编译器的扩展语言,比如取消结构体的对齐优化、指定变量对齐方式等,这些扩展语言 ARM Compiler 5 和 ARM Compiler 6 并不相同。
    cc.h文件中引用CMSIS提供的cmsis_compiler.h文件,然后修改结构体封装与对齐宏代码为:

    /* Arm Compiler 4/5 */
    #if   defined ( __CC_ARM )
        #define PACK_STRUCT_BEGIN __packed
        #define PACK_STRUCT_STRUCT
        #define PACK_STRUCT_END
        #define PACK_STRUCT_FIELD(fld) fld
    	#define ALIGNED(n)  __ALIGNED(n)
    
      /* Arm Compiler above 6.10.1 (armclang) */
    #elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100)
        #define PACK_STRUCT_BEGIN
        #define PACK_STRUCT_STRUCT __PACKED
        #define PACK_STRUCT_END
        #define PACK_STRUCT_FIELD(fld) fld
    	#define ALIGNED(n)  __ALIGNED(n)
    
    /* GNU Compiler */
    #elif defined ( __GNUC__ )
        #define PACK_STRUCT_BEGIN
        #define PACK_STRUCT_STRUCT __PACKED
        #define PACK_STRUCT_END
        #define PACK_STRUCT_FIELD(fld) fld
    	#define ALIGNED(n)  __ALIGNED(n)
    	
    #else
        #error "Unsupported compiler"
    #endif
    
  3. 程序中使用了__packed__align(n)__inline__weak的地方分别用CMSIS提供的宏__PACKED__ALIGNED(n)__INLINE__WEAK代替。

    注意__packed__attribute__((packed))的使用区别:

    ARM Compiler 5 使用__packed

    typedef __packed struct
    {
        char x;           
        int y;
    } X; 
    

    ARM Compiler 6 使用__attribute__((packed))

    typedef struct __attribute__((packed))
    {
        char x;                   
        int y;
    } X; 
    
  4. 如果使用ARM Compiler 5 时习惯使用typedef __packed struct {}X; 句法,推荐改为CMSIS提供的宏句法:typedef __PACKED_STRUCT {}X;

    当使用ARM Compiler 5 时会自动扩展为:typedef __packed struct {}X;

    当使用ARM Compiler 6 时会自动扩展为:typedef struct __attribute__((packed)) {}X;

  5. 如果使用内联函数建议按照以下格式:

    __STATIC_INLINE func_name(arg)
    {
        //函数体
    }
    

    防止ARM Compiler 6在-O0-O1级别设置下,链接时出现未定义符号的错误。(在这种优化级别下__INLINE可能并不会内联)

不兼容的语言扩展总结如下:

ARM Compiler 5ARM Compiler 6CMSIS(推荐)
__align(x)__attribute__((aligned(x)))__ALIGNED(x)
__alignof____alignof__
__ALIGNOF____alignof__
__asm汇编迁移__ASM
__const__attribute__((const))
__forceinline__attribute__((always_inline))
__global_reg不支持
__inline__inline__ 此功能使用取决于语言模式__INLINE
__STATIC_INLINE
__int64没有对等选项.使用 long longint64_t
__irq__attribute__((interrupt))Cortex-M ISR不需要此关键字
__packed
__packed x struct
__attribute__((packed))
struct x attribute((packed))
__PACKED
__PACKED_STRUCT x
__pure__attribute__((const))
__smc不支持,使用内联汇编或等效程序
__softfp__attribute__((pcs(“aapcs”)))
__svc不支持,使用内联汇编或等效程序
__svc_indirect不支持,使用内联汇编或等效程序
__thread__thread
__value_in_regs__attribute__((value_in_regs))
__weak__attribute__((weak))__WEAK
__writeonly不支持

提示:可以使用uVision IDE的查找功能来查找上述关键字,然后做迁移处理。

不兼容的属性扩展:

Arm Compiler 5 属性Arm Compiler 6 属性描述
__attribute__((at(address)))__attribute__((section(".ARM.__at_address")))Arm Compiler 6 中的 armlink 仍然支持以 .ARM.__at_address 的形式放置段
__attribute__((at(address), zero_init))__attribute__((section(".bss.ARM.__at_address")))Arm Compiler 6 中的 armlink 支持以 .bss.ARM.__at_address 的形式放置零初始化段。 .bss 前缀区分大小写,并且必须全部小写。
__attribute__((section(name), zero_init))__attribute__((section(".bss.name")))name 是你选择的名字。 .bss 前缀区分大小写,并且必须全部小写。
__attribute__((zero_init))不支持
默认将零初始化变量放在.bss 段。
如果变量具有初始值设定项,则 Arm Compiler 5 会生成错误。 否则,它将零初始化变量放在 .bss段。

点击这里查看迁移详细例程。

内嵌汇编

ARM Compiler 6 完全改变了处理汇编代码的策略。

汇编语法现在兼容GNU风格而不是ARM风格。 汇编也是由C编译器完成, 无需单独的汇编器。

  1. FreeRTOS的移植层由..\FreeRTOS\Source\portable\RVDS\ARM_CM3目录下的port.cportmacro.h文件改为..\FreeRTOS\Source\portable\GCC\ARM_CM3目录下的port.cportmacro.h文件。

    这是因为这两个文件会涉及内嵌汇编。

  2. 自定义的内嵌汇编函数。

    ARM Compiler 5:

    __asm  uint32_t __get_flash_base(void) 
    {
       IMPORT |Image$$ER_IROM1$$RO$$Base|;
        
        ldr r0,=|Image$$ER_IROM1$$RO$$Base|;
        bx lr;
    }
    

    ARM Compiler 6:(看了下帮助手册,也可以不使用汇编)

    uint32_t get_flash_base(void)
    {
        extern uint32_t Image$$ER_IROM1$$RO$$Base;
        
        return (uint32_t)&Image$$ER_IROM1$$RO$$Base;
    }
    

语法更严格

  1. 比如某个函数之前要对外开放,.c和.h中定义和声明都相同。后来在.c文件中将该函数定义为本地函数,使用static修饰,但.h中忘记删除也没有做相应修改。这种情况下,ARM Compiler 5 不会报错,ARM Compiler 6 会报错:

    ../file_name.c(10): error: static declaration of 'func_name' follows non-static declaration

  2. 如下代码:

    for(i=0; i<0x7E-0x20; i++)
    

    ARM Compiler 5 不会报错,ARM Compiler 6 会报错:

    ../file_name.c(332): error: invalid suffix '-0x20' on integer constant

    需要将代码改为:

    for(i=0; i<0x7E - 0x20; i++)
    

优化问题

以下代码在 ARM Compiler 5 中,正常执行,但在 ARM Compiler 6 中,只要不是-O0级别,整个函数因为空循环问题,都被优化掉。也就是延时没有起作用。

void delay_us (uint32_t ul_time)
{
    ul_time *= 30; 
	while(--ul_time != 0);
}

这个函数不会修改自己范围之外的资源,所以编译器认为这段是无副作用(no side-effect)的代码,可以通俗的理解为没什么作用的代码。对于这样的代码,编译器有可能会优化掉他们。

有副作用的函数的特点:

  • 修改了全局变量
  • 修改了参数引用的变量
  • 调用其它有副作用的函数
  • 操作了 volatile 修饰的变量
  • 内嵌了汇编或 __NOP()指令

所以当升级到 ARM Compiler 6 出现使用软延时的外设不工作,比如软件IIC出错、软件SPI出错、LCD黑屏等问题,可以检查是否有类似的代码。

需要改成:

void delay_us (uint32_t ul_time)
{
    ul_time *= 30; 
	while(--ul_time != 0)
        __nop();
}

Keil编译器保证__nop()必定会插入一个NOP指令,在这里可以阻止编译器优化。当然,延时的初始值也要做相应的调整。

或者改成:

void delay_us (volatile uint32_t ul_time)
{
    ul_time *= 30; 
	while(--ul_time != 0);
}

通过关键字 volatile 来禁止编译器优化。

编译时间和大小

  • -O0:Program Size: Code=200360 RO-data=20576 RW-data=96 ZI-data=76316
    Build Time Elapsed: 00:00:25

  • -O1:Program Size: Code=119328 RO-data=16824 RW-data=96 ZI-data=76300
    Build Time Elapsed: 00:00:25

  • -O2:Program Size: Code=153340 RO-data=17100 RW-data=96 ZI-data=76300
    Build Time Elapsed: 00:00:26

  • -O3:Program Size: Code=162292 RO-data=17040 RW-data=96 ZI-data=76308
    Build Time Elapsed: 00:00:27

  • -Ofast:Program Size: Code=161896 RO-data=17040 RW-data=96 ZI-data=76308
    Build Time Elapsed: 00:00:26

  • -Os balanced:Program Size: Code=115628 RO-data=17048 RW-data=96 ZI-data=76300
    Build Time Elapsed: 00:00:28

  • -Oz image size:Program Size: Code=103784 RO-data=17020 RW-data=96 ZI-data=76308
    Build Time Elapsed: 00:00:25

  • -Oz image size LTO:Program Size: Code=85888 RO-data=17064 RW-data=40 ZI-data=75960
    Build Time Elapsed: 00:00:32

与Compiler 5 对比(我的程序-可能不具有一般性):

  • -O2:Program Size: Code=94232 RO-data=16736 RW-data=540 ZI-data=75640
    Build Time Elapsed: 00:00:16

参考文档

  • 《Arm® Compiler Migration and Compatibility Guide》(内容详细)
  • 《Migrate ARM Compiler 5 to ARM Compiler 6》 (AN298)






读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃‘▽’〃)
千金难买知识,但可以买好多奶粉

### 回答1: ARM Compiler 5是一款面向ARM架构微控制器的编译器,可供嵌入式开发者使用。它支持多种编程语言,包括C、C++、汇编语言和FORTRAN,并且可以生成高效的代码,提高应用程序的性能。 该编译器具有灵活的可配置性和可扩展性,可以适应不同的应用需求。它提供了多种优化选项,包括代码大小优化、性能优化和指令选择优化等,可以根据不同的应用场景进行选择。 除了编译器本身,ARM Compiler 5还具有一些有用的工具和库,如调试器、链接器、运行时库和优化库等,可以帮助嵌入式开发者更方便地编写、调试和优化应用程序。 总而言之,ARM Compiler 5是一款可靠且功能强大的编译器,为嵌入式开发者提供了完整的编译和优化工具,有助于提高应用程序的性能和可靠性。 ### 回答2: arm compiler 5是一种专门为ARM架构设计的编译器和开发工具集。在嵌入式系统和移动设备领域,ARM CPU是一种最受欢迎的处理器架构之一。相应的,为该架构设计的工具和库也得到了广泛的应用。 与先前的版本相比,ARM Compiler 5提供了更好的代码生成和优化,支持大量的编译器指令集(如ARM, Thumb和Thumb-2),为开发人员提供了更好的编程体验。 其它值得一提的功能包括: - 对多核处理器的支持 - 带有调试器的全面特性,可与多种IDE集成 - 可以用于各种类型的嵌入式设备的C/C++库 总之,ARM Compiler 5是一种强大的工具,为ARM架构上的开发者提供了极大的帮助和便利。 ### 回答3: ARM Compiler 5是ARM公司开发的一款面向嵌入式系统的编译器,支持多种ARM架构指令集,包括ARMv5、ARMv6、ARMv7和Thumb等。它为开发者提供了一个高效、可靠的编译器,具备优秀的性能、代码大小优化和代码生成的能力。 ARM Compiler 5的主要特点包括: 1. 高效的代码生成。它能够生成高效的代码,减少执行时间和内存占用。 2. 优化代码大小。它能够通过使用优化算法和删除未使用的代码,减小生成文件的大小。 3. 支持多种嵌入式系统。ARM Compiler 5支持多种嵌入式系统的编译,包括Linux、Windows CE和Android等。 4. 内置调试器。ARM Compiler 5内置了调试器,支持多种调试功能,能够提高开发效率。 5. 支持多种编程语言。ARM Compiler 5支持多种编程语言,包括C、C++和汇编语言等。 总之,ARM Compiler 5是一款非常强大的编译器,能够满足开发者对高效、可靠和优化的需求,帮助他们在嵌入式系统开发中获得更好的表现。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值