技术宅的结界

 找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 478|回复: 2
收起左侧

【嵌入式】搭建一个基于gcc编译器的STM32F10x程序编译环境

[复制链接]

993

主题

2190

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16175 个
贡献
31494 次
宅之契约
0 份
在线时间
1544 小时
注册时间
2014-1-26
发表于 2017-11-22 12:34:16 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有帐号?立即注册→加入我们

x
需要的东西:
1、gcc arm toolchain
2、gnu make
3、notepad++(不喜欢的话你可以选择记事本开发。其实用Office Word也不是不行,但要记得保存为纯文本)
4、STM32F10x的官方头文件声明定义PDF
5、ST-LINK Utility负责完成单片机程序的下载,但你可能需要一个USB接口的ST-LINK来完成此事。

ST-Util下载:https://pan.
bai
du.com/s/11bQ7K
27hhFxzPnFP
ES3cjw
(访问密码:c556)
SHA256:6A200CEAACCBE99B3014F5E61204C40BD550D9E03184BA2988536FAB90D363F3

gcc ARM Toolchain是用于跨平台编译bin的一系列工具,包裹gcc ld objcopy等。我们开发STM32F10x的程序的过程,就是先写好源码,然后用gcc将源码编译为中间文件.o,再用ld把我们的.o链接为elf文件。这elf文件你可以理解为“Linux的exe”。完成链接后,再用objcopy把elf里面的纯代码部分提取出来,也就是纯二进制指令。我们要的是这个纯二进制指令,因为STM32F10x它是单片机,它并不是天生就知道如何识别elf、exe这些复杂的格式的。

为什么gcc不直接把源代码编译为二进制指令呢?这是为了便于模块化编程。当你有多个源码文件的时候,gcc把每个源码文件编译为.o,然后链接器负责把这些多个的源码文件组装到一起,完成互相之间的依赖关系的处理。这也是编译原理的基础。

gcc arm toolchain的下载地址:
https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads


打开链接后你会看到它提供了很多种版本的下载方式。其中Windows 32bit的版本有三个,其中有一个带了个“sha1”的后缀,另一个带了“sha2”的后缀。这个是因为这个exe安装器是带了数字签名的,而sha1和sha2是它的数字签名加密算法。使用数字签名是为了保证你下载它的时候黑客不能轻易往里面植入病毒。你可以按照自己的喜好选择其中一个,然后下载下来安装。

gnu make这玩意儿就是Linux里面常见的makefile脚本执行工具,使用它配置编译过程非常方便。它有Windows版本可以给你用。

gnuwin32make的下载地址:
http://gnuwin32.sourceforge.net/packages/make.htm


把gcc arm toolchain和gnuWin32 make安装好以后我们就可以开始搭建编译环境了。
首先我们假定以后就在D盘上保存我们的源码了。我在D盘建立了stm32_proj文件夹用于存储所有和stm32f10x开发相关的东西。
我们以后就打算用makefile来设置编译过程了。为了让makefile能调用gcc arm toolchain里面的工具,我们需要配置一下环境变量。不过我并不想修改我这个系统的全局的环境变量。所以我在D:\stm32_proj里面创建了一个名为env.bat的新的cmd脚本用于调用gnu arm toolchain里面的工具和make。
[Patch] 纯文本查看 复制代码
@echo off
set TL_PATH=C:\Program Files (x86)\GNU Tools ARM Embedded\6 2017-q2-update\bin\
set GNU_MAKE=C:\Program Files (x86)\GnuWin32\bin
set PATH=%TL_PATH%;%GNU_MAKE%;%PATH%
cmd /K cd /d %~dp0
其中的“6 2017-q2-update”是我的gcc arm toolchain的版本,你要换成你自己的版本。执行完这个脚本后你就会看到CMD的窗口了。在这个里面你就可以调用gcc的工具和makefile了。

20171122060513.png

这“症状”就是环境变量配置成功了的标志,也就是这个cmd脚本里面的环境变量是OK的,可以调用各种编译工具了。
接下来我们需要的是STM32F10x的官方头文件定义。

点击这里进去下载stsw-stm32054.zip:
http://www.st.com/en/embedded-software/stsw-stm32054.html


懒得去官网下载stsw-stm32054.zip的话,我这里提供下载。但处于各种各样的原因,请回帖再下载。(所以如果是我就去官网下载了,又不难)
游客,如果您要查看本帖隐藏内容请回复
这玩意儿提供了STM32F10x系列全套的外设的驱动,包括ADC、BKP、CAN、CEC、CRC、DAC、调试工具、DMA、EXTI、FLASH、FSMC、GPIO、I2C、IWDG、电源控制、RCC、实时时钟、SDIO、SPI、计时器、USART、WWDG等。
但它提供的这些外设的驱动写得不咋地,设置一个GPIO针的电平所需的代码就超过了1页,各种程度上都还是自己直接写寄存器比较好。
而为了便于轻松地访问它的寄存器,使用它提供的头文件声明就好。也就是它的stm32f10x.h。
这个stm32f10x.h就在刚才下载的stsw-stm32054.zip里面的STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x目录下。
stm32f10x.h依赖core_cm3.h和system_stm32f10x.h。
core_cm3.h在STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\CoreSupport这里。
我在D:\stm32_proj里面创建了一个叫“common”的目录用来存储每次都可能用到的东西。我在common目录里创建了include目录,然后把刚才提到的stm32f10x.h、core_cm3.h和system_stm32f10x.h都存进去。

这个CMSIS是什么呢?它是Cortex Microcontroller Software Interface Standard,翻译过来是“Cortex单片机软件接口标准”,而“Cortex”的翻译是“皮质”……它应该只是个名字而已。
STM32F10x系列单片机用的是ARM Cortex-M3指令集,支持THUMB,所以自然也是要遵守CMSIS标准的。

根据PDF和CMSIS标准,它的ROM flash的开头部分是一个中断向量表,而且这个中断向量表的第0个项是初始栈顶的值。而STM32F10x根据它的规格,有“低密度”(ROM和RAM都比较小)、“中密度”(ROM和RAM大一些)、“高密度”(ROM和RAM很大)、“超高密度”(RAM和ROM更大……)等不同的规格。这些不同规格的单片机在CMSIS钦定的中断表的后面追加了很多自己特色的中段表项,所以我们还得根据情况来填写这个中断表。

stm32f10x.h这个头文件同时支持多个规格的单片机,但你需要在宏定义里面定义自己的编译目标。以下是它的内容的片段:
[C] 纯文本查看 复制代码
/* Uncomment the line below according to the target STM32 device used in your
   application 
  */

#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL) 
  /* #define STM32F10X_LD */     /*!< STM32F10X_LD: STM32 Low density devices */
  /* #define STM32F10X_LD_VL */  /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */  
  /* #define STM32F10X_MD */     /*!< STM32F10X_MD: STM32 Medium density devices */
  /* #define STM32F10X_MD_VL */  /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */  
  /* #define STM32F10X_HD */     /*!< STM32F10X_HD: STM32 High density devices */
  /* #define STM32F10X_HD_VL */  /*!< STM32F10X_HD_VL: STM32 High density value line devices */  
  /* #define STM32F10X_XL */     /*!< STM32F10X_XL: STM32 XL-density devices */
  /* #define STM32F10X_CL */     /*!< STM32F10X_CL: STM32 Connectivity line devices */
#endif
/*  Tip: To avoid modifying this file each time you need to switch between these
        devices, you can define the device in your toolchain compiler preprocessor.

 - Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
   where the Flash memory density ranges between 16 and 32 Kbytes.
 - Low-density value line devices are STM32F100xx microcontrollers where the Flash
   memory density ranges between 16 and 32 Kbytes.
 - Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
   where the Flash memory density ranges between 64 and 128 Kbytes.
 - Medium-density value line devices are STM32F100xx microcontrollers where the 
   Flash memory density ranges between 64 and 128 Kbytes.   
 - High-density devices are STM32F101xx and STM32F103xx microcontrollers where
   the Flash memory density ranges between 256 and 512 Kbytes.
 - High-density value line devices are STM32F100xx microcontrollers where the 
   Flash memory density ranges between 256 and 512 Kbytes.   
 - XL-density devices are STM32F101xx and STM32F103xx microcontrollers where
   the Flash memory density ranges between 512 and 1024 Kbytes.
 - Connectivity line devices are STM32F105xx and STM32F107xx microcontrollers.
  */

#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
 #error "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)"
#endif
我的stm32单片机是STM32F103C8T6,所以根据PDF,我应该定义STM32F10X_MD。

有关中段表的详细内容我们看STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm文件夹里面的几个汇编的文件。
我不想引用这几个汇编文件,我要自己用C造轮子。根据它的汇编的文件的内容我发现:绝大多数中断的处理程序,默认都是死循环。然后它导出了弱符号。也就是说只要你自己实现了同名的中断处理函数,那么链接器就会认你的中断处理函数,用它来取代默认的死循环。
其中第1个中断表项是“重启中断”,事实上它定义了你的整个bin的入口点。

因为中断表必须在整个镜像的开始,所以我们需要想办法让gcc toolchain里面的链接器把中断表放到二进制的最开头的位置。解决办法是借助分段机制,把这种需要固定位置的东西装到特殊的段里面,这样我们就可以让链接器把不同的段按照要求放到不同的位置,再完成各种符号依赖的链接。
所以我在源码里面自己定义了一个段“.isr_vector”用来存储中断表。在中断表的后面,我定义了“.after_vectors”段,用于存放默认中断处理向量的内容:死循环。然后就是.text段了,负责存储源代码。

下面是我写好的startup.c和startup.h,有需要的随便下载。
startup.h (14.83 KB, 下载次数: 2)

0

主题

9

帖子

31

积分

用户组: 初·技术宅

UID
3245
精华
0
威望
2 点
宅币
18 个
贡献
0 次
宅之契约
0 份
在线时间
0 小时
注册时间
2017-12-24
发表于 2017-12-24 03:00:45 | 显示全部楼层
在github上很多单片机的项目都是使用gcc作为编译工具,另外我很想了解 .cc 文件作为测试代码,这个怎么用呢?

993

主题

2190

帖子

5万

积分

用户组: 管理员

一只技术宅

UID
1
精华
197
威望
261 点
宅币
16175 个
贡献
31494 次
宅之契约
0 份
在线时间
1544 小时
注册时间
2014-1-26
 楼主| 发表于 2018-1-5 08:59:18 | 显示全部楼层
安拉 发表于 2017-12-24 03:00
在github上很多单片机的项目都是使用gcc作为编译工具,另外我很想了解 .cc 文件作为测试代码,这个怎么用呢 ...

这个“.cc”它应该也就是一个C语言的.c文件改了一下后缀吧……

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|技术宅的结界 ( 滇ICP备16008837号|网站地图

GMT+8, 2018-7-22 18:40 , Processed in 0.090646 second(s), 16 queries , Gzip On, Memcache On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表