Keil5配置GCC编译器编译STM32工程

版权声明:本文为博主原创文章,转载注明:转载自 https://blog.csdn.net/weixin_39871788/article/details/78858791

Keil一般使用ARMCC编译MCU工程代码。偶然听说Keil也是支持内嵌GCC编译器的。于是尝试了网上博客所述的一些方法,最终找到了一篇博客

http://blog.csdn.net/lan120576664/article/details/46806991

按照文中所述,发现仍存在一些其他错误,后来又查找了其他相关资料,在这作以总结

一、下载GCC编译器

https://launchpad.net/gcc-arm-embedded/

二、安装GCC

GCC解压到keil的安装目录下面。如下图
这里写图片描述

三、配置Keil

如下图所示进行相关设置:

  • Prefix:arm-none-eabi-
  • Folder:D:\keil_MDK\Keil_v5\ARM\GCC\ (注:这里是刚刚安装的GCC所在位置)

这里写图片描述

四、配置工程设置

1.配置CC编译规则

注意勾选一下选项,填写规则

  • Misc Controls : -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections
    注:
    1.这里我用的cortex-m3,如果你是m4内核就改成4)
    2.-mthumb的意义是:使用这个编译选项生成的目标文件是Thumb的
    3.-fdata-sections和-ffunction-sections和下文连接规则一起说

这里写图片描述

2.配置Assembler编译规则

类似前一项

  • Misc Controls : -mcpu=cortex-m3 -mthumb

这里写图片描述

3.配置Linker连接规则

这里要添加连接脚本,一般可以在官方提供的固件库包找到类似的

  • Misc Controls : -Wl,–gc-sections
    注:
    1.注意这个gc前面是两个短小的“–”,由于博客的问题直接复制会出错
    2.-wl, 表示后面的参数 –gc-sections 传递给链接器
    3.-fdata-sections和-ffunction-sections和–gc-sections的说明如下

-ffunction-sections和-fdata-sections会使编译器为每个function和data item分配独立的section。 –gc-sections会使连接器删除没有被使用的section。
连接操作以section作为最小的处理单元,只要一个section中有某个符号被引用,该section就会被放入output中。这些选项一起使用会从最终的输出文件中删除所有未被使用的function和data, 只包含用到的unction和data。

具体细节可以参考另一位博主的文章http://blog.csdn.net/pengfei240/article/details/55228228

这里写图片描述

4.stm32f10x_flash_extsram.ld内容

/*
Default linker script for STM32F10x_1024K_1024K
Copyright RAISONANCE S.A.S. 2008
*/

/* include the common STM32F10x sub-script */

/* Common part of the linker scripts for STM32 devices*/


/* default stack sizes. 

These are used by the startup in order to allocate stacks for the different modes.
*/

__Stack_Size = 1024 ;

PROVIDE ( _Stack_Size = __Stack_Size ) ;

__Stack_Init = _estack  - __Stack_Size ;

/*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/
PROVIDE ( _Stack_Init = __Stack_Init ) ;

/*
There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 0x100 ;


/* include the memory spaces definitions sub-script */
/*
Linker subscript for STM32F10x definitions with 1024K Flash and 1024K External SRAM */

/* Memory Spaces Definitions */

MEMORY
{
  RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 1024K
  FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
  FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
}

/* higher address of the user mode stack */
_estack = 0x68100000;



/* include the sections management sub-script for FLASH mode */

/* Sections Definitions */

SECTIONS
{
    /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
    .isr_vector :
    {
    . = ALIGN(4);
        KEEP(*(.isr_vector))            /* Startup code */
    . = ALIGN(4);
    } >FLASH

    /* for some STRx devices, the beginning of the startup code is stored in the .flashtext section, which goes to FLASH */
    .flashtext :
    {
    . = ALIGN(4);
        *(.flashtext)            /* Startup code */
    . = ALIGN(4);
    } >FLASH


    /* the program code is stored in the .text section, which goes to Flash */
    .text :
    {
        . = ALIGN(4);

        *(.text)                   /* remaining code */
        *(.text.*)                   /* remaining code */
        *(.rodata)                 /* read-only data (constants) */
        *(.rodata*)
        *(.glue_7)
        *(.glue_7t)

        . = ALIGN(4);
     _etext = .;
        /* This is used by the startup in order to initialize the .data secion */
     _sidata = _etext;
    } >FLASH



    /* This is the initialized data section
    The program executes knowing that the data is in the RAM
    but the loader puts the initial values in the FLASH (inidata).
    It is one task of the startup to copy the initial values from FLASH to RAM. */
    .data  : AT ( _sidata )
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data secion */
        _sdata = . ;

        *(.data)
        *(.data.*)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data secion */
     _edata = . ;
    } >RAM



    /* This is the uninitialized data section */
    .bss :
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss secion */
        _sbss = .;

        *(.bss)
        *(COMMON)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss secion */
     _ebss = . ;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );

    /* This is the user stack section 
    This is just to check that there is enough RAM left for the User mode stack
    It should generate an error if it's full.
     */
    ._usrstack :
    {
        . = ALIGN(4);
        _susrstack = . ;

        . = . + _Minimum_Stack_Size ;

        . = ALIGN(4);
        _eusrstack = . ;
    } >RAM



    /* this is the FLASH Bank1 */
    /* the C or assembly source must explicitly place the code or data there
    using the "section" attribute */
    .b1text :
    {
        *(.b1text)                   /* remaining code */
        *(.b1rodata)                 /* read-only data (constants) */
        *(.b1rodata*)
    } >FLASHB1

    /* this is the EXTMEM */
    /* the C or assembly source must explicitly place the code or data there
    using the "section" attribute */

    /* EXTMEM Bank0 */
    .eb0text :
    {
        *(.eb0text)                   /* remaining code */
        *(.eb0rodata)                 /* read-only data (constants) */
        *(.eb0rodata*)
    } >EXTMEMB0

    /* EXTMEM Bank1 */
    .eb1text :
    {
        *(.eb1text)                   /* remaining code */
        *(.eb1rodata)                 /* read-only data (constants) */
        *(.eb1rodata*)
    } >EXTMEMB1

    /* EXTMEM Bank2 */
    .eb2text :
    {
        *(.eb2text)                   /* remaining code */
        *(.eb2rodata)                 /* read-only data (constants) */
        *(.eb2rodata*)
    } >EXTMEMB2

    /* EXTMEM Bank0 */
    .eb3text :
    {
        *(.eb3text)                   /* remaining code */
        *(.eb3rodata)                 /* read-only data (constants) */
        *(.eb3rodata*)
    } >EXTMEMB3



    /* after that it's only debugging information. */

    /* remove the debugging information from the standard libraries */
    DISCARD :
    {
     libc.a ( * )
     libm.a ( * )
     libgcc.a ( * )
     }

    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /* DWARF debug sections.
       Symbols in the DWARF debugging sections are relative to the beginning
       of the section so we begin them at 0.  */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }
}

五、启动代码,使用GCC专用的.S文件

使用GCC编译器需要的启动代码不同与AMRCC,不过官方已经有提供了相关代码,如下图:
这里写图片描述

六、编译运行

1.core_cm3.c错误

这里写图片描述
出现两个错误,经过在搜索发现原来是官方提供的core_cm3.c有bug造成的
将其中
736行改为:

   __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

753行改为:

   __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

这样就不会有错误了。

2.标准的C 库函数错误

这里写图片描述
如上图所示出现两个错误,根据原文所述如果有使用标准的C 函数,如sprintf,则要包含syscall.c 这个文件。于是我查找了标准库文件发现没有提供,后来又查找了HAL库的文件,找到了syscall.c如下图
这里写图片描述
添加后只剩下一个错误
这里写图片描述
如下:

ld.exe: section .ARM.exidx loaded at [080053dc,080053e3] overlaps section .data loaded at [080053dc,08005d83]

这里发现.ARM.exidx与.data段重叠了,但是.ARM.exidx段究竟是什么?
在这篇文章中找到了答案http://www.cnblogs.com/tfanalysis/p/3652788.html
最终,我的解决办法是在stm32f10x_flash_extsram.ld连接脚本文件第75行添加以下代码

    /* 添加.ARM.exidx段 */
    .ARM.exidx : {
    . = ALIGN(4);
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    . = ALIGN(4);
    } >FLASH

修改后再次编译发现没有错误。
注:
1.连接脚本规则可以参考这篇博客http://blog.csdn.net/cat_lover/article/details/50727988
2.个人理解连接脚本类似用ARMCC,ARMLINK编译连接时写的.sct格式分散加载文件

七、编译成功

这里写图片描述
注:采用GCC编译器后无法使用“Go To Definition Of ”跳转到相应的函数这个功能。
附上工程:http://download.csdn.net/download/weixin_39871788/10166971

猜你喜欢

转载自blog.csdn.net/weixin_39871788/article/details/78858791