stm32F103(HAL库)+keil5.20+gcc(gcc-arm-none-eabi-9-2019-q4-major-win32)编译器编译工程(详细步骤)

序:

偶然的因素看到网上有keil设置arm gcc的编译器,于是想自己尝试一下。mdk5.15之后就可以按照此文的方案去设置,也可以参考keil官网文档,

这个文章过了好多年,圈中大佬,真正的大佬(GorgonMeducer 傻孩子 裸机思维),在他的公众号中,写了一个手把手的教程——《【教程】如何用GCC“零汇编”白嫖MDK》,温故知新,好记性不如烂笔头~~~

1、安装

gcc-arm-none-eabi-9-2019-q4-major-win32.exe,这个在arm公司官网下载,是免费的,不同于armcc,armcc是要注册的。

(之前的老版本下载网址:https://launchpad.net/gcc-arm-embedded/)基本上不使用了。

2、安装使用默认路径。

3、keil使用我原来的hal工程,工程下设置如下。这个和keil的文档上面是一样的。

 PS:选择了第3步,会把之前的设置全部清空,因此最好是保留一份工程。

4、工程设置

4.1、把时钟设置正确,有木有和以前的armcc完全不一样。

4.2、out设置,没有了broswer information了。还可以该大小端,当然stm32f103默认是小端,我们不去改动大端。

4.3、c语言设置,划线的都要根据实际来设置。

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

4.5、汇编设置

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

 4.6、链接设置,注意划线部分

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。

有点类似armcc的elf设置

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

 4.6、debug设置,和armcc一样,不细讲。

5、stm32_flash.ld文件,我是从标准外设库里拷贝的,如下搜索:

 具体的作用如下:

 6、启动代码,使用GCC专用的.S文件,这个要从cubef1的库中去拷贝。

 7、编译

编译后很多错误,首先是标准库的错误。类似于:

d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-sbrkr.o): In function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'
d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-writer.o): In function `_write_r':
writer.c:(.text._write_r+0x10): undefined reference to `_write'
d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-closer.o): In function `_close_r':
closer.c:(.text._close_r+0xc): undefined reference to `_close'
d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0xe): undefined reference to `_fstat'
d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-isattyr.o): In function `_isatty_r':
isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty'
d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-lseekr.o): In function `_lseek_r':
lseekr.c:(.text._lseek_r+0x10): undefined reference to `_lseek'
d:/gcc-arm-none-eabi-4_9/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/armv7-m\libc_nano.a(lib_a-readr.o): In function `_read_r':

 如上图所示出现两个错误,根据原文所述如果有使用标准的C 函数,如sprintf,则要包含syscall.c 这个文件。于是我查找了标准库文件发现没有提供,后来又查找了HAL库的文件,找到了syscall.c如下图,找到一个文件拷贝到工程目录中。

 其次是undefined reference to `_init'错误,网上参考了文章如下:

今天利用CDT 的eclipse调试程序,遇到下面的问题:

d:/plugin/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/lib/armv7-m\libg_s.a(lib_a-init.o): In function `__libc_init_array':
init.c:(.text.__libc_init_array+0x1c): undefined reference to `_init'
collect2.exe: error: ld returned 1 exit status
make: *** [gg.elf] Error 1

图片格式如下:

查询良久,在与非网上(http://www.infineonic.org/module/forum/thread-601371-1-1.html)发现问题所在:

在工程->property->C/C++ builder->settings->Cross ARM C++ linker->general中的设置是这样的:

将第一个√去掉就可以了

这个在linker设置之前是会出错的,因此在上一步的linker设置中,按照我的配置即可编译通过。意思是我们这个工程是需要标准的启动文件的。如下两点,其中我们也使用标准库的文件的。

 最后,重定义标准库的函数,当我们需要重定向到usart 到pc com调试打印时候,需要重新实现_write() 和 _read() 。

我的实现_write() 如下:

int _write(int fd, char *pBuffer, int size)
{
    for (int i = 0; i < size; i++)
    {
		HAL_UART_Transmit(&huart1, (uint8_t*)pBuffer++, 1, 0xFFFF);
		//HAL_UART_Transmit(&huart1, pBuffer++, 1, 0xFFFF);
    }
    return size;
}
HAL_UART_Transmit(&huart1, pBuffer++, 1, 0xFFFF);这个语句是编译不能通过的:

 最后编译结果如下:

说明gcc的编译语法等级比较高。

注:采用GCC编译器后无法使用“Go To Definition Of ”跳转到相应的函数这个功能。

8、仿真:仿真设置好以前的armcc一样的。仿真结果:

 9、总结,使用arm gcc编译器来编译,应该可以避免keil编译器盗版的情况。可以学习到更多的gcc方面的知识,以后linux下更多的也是arm gcc编译器。

网上资源很多,需要自己根据实际情况来判断是否是有用的。

附件:

-mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections
-mcpu=cortex-m3 -mthumb 
-Wl,--gc-sections

注意点:

--gc是两个--

参考网站:
https://blog.csdn.net/weixin_42559298/article/details/98769671 ——主要讲述预定义
https://blog.csdn.net/weixin_39871788/article/details/78858791 ——这个文章很好,基本参考这个
https://blog.csdn.net/lan120576664/article/details/46806991——STM32F4的工程
https://blog.csdn.net/daxiebao/article/details/52653657——解决串口重映射
https://www.cnblogs.com/quray/p/4724506.html——解决undefined reference to `_init'的编译问题

http://www.keil.com/arm/gnu.asp——keil使用gcc编译器

 https://blog.csdn.net/weixin_39871788/article/details/78858791——Keil5配置GCC编译器编译STM32工程

https://blog.csdn.net/Cui_Hongwei/article/details/104108044——STM32 GCC编译器 .ld & .s文件详细解析

posted @ 2020-01-06 10:47  wdliming  阅读(3901)  评论(0编辑  收藏  举报