1.1 安装GCC
1、stm32 属于arm cortex-m系列thumb指令集,所以给arm用的arm-none-eabi就可以了,下载地址:
https://launchpad.net/gcc-arm-embedded/+download
下载其中的gcc-arm-none-eabi-version-linux.tar.bz2
解压到你知道的目录会产生 gcc-arm-none-eabi的文件夹
2、设置环境变量
把该编译器添加到你的环境中:
# sudo gedit ~/.bashrc 最后一行添加
export PATH=$PATH:/your_stm_gcc_dir/gcc-arm-none-eabi-4_8-2013q4/bin
3、测试
# arm-none-eabi-gcc -v
1.2 建立工程
1、下载官方的库
2、将文件分类放在文件下,然后写makefile进行编译
1.3 Makefile解析
makefile是所有的重点,由于我对makefile并不是很熟料,我在这里参考过很多github相关的makefile,在这里整理出一份我比较喜欢,简洁明了、通用性移植性强的:
注意使用官方库的时候,选择的启动文件不一样,keil的是arm编译,我们使用的gcc编译。
BUILDDIR = build
BINNAME = STM32F103forLinux
STM32FlashDIR =/home/jimy/work/sources/stm32flash/stm32flash
TTYUSB = /dev/ttyUSB0
ELF = $(BUILDDIR)/$(BINNAME).elf
HEX = $(BUILDDIR)/$(BINNAME).hex
BIN = $(BUILDDIR)/$(BINNAME).bin
TC = arm-none-eabi-
CC = $(TC)gcc
LD = $(TC)gcc
AR = $(TC)ar
OBJCOPY = $(TC)objcopy
#----------Object dir----------#
STM32LIBS_DIR = stm32lib/STM32_USB-FS-Device_Lib_V4.0.0
USER_DIR = user
BSP_DIR = bsp
TEMP_DIR = temp
MYLIB_DIR = mylib
MODULE_DIR1 = module
MODULE_DIR2 = module/mpu_core_lib
MODULE_DIR3 = module/mpu_core_lib/include
MODULE_DIR4 = module/mpu_core_lib/mllite
#----------Object .C file----------#
#wildcard:扩展通配符
SOURCES += $(STM32LIBS_DIR)/Libraries/CMSIS/Device/ST/STM32F10x/Source/Templates/system_stm32f10x.c
SOURCES += $(STM32LIBS_DIR)/Libraries/CMSIS/Device/ST/STM32F10x/Source/Templates/gcc_ride7/startup_stm32f10x_hd.s
SOURCES += $(wildcard $(STM32LIBS_DIR)/Libraries/STM32F10x_StdPeriph_Driver/src/*.c)
SOURCES += $(wildcard $(USER_DIR)/*.c)
SOURCES += $(wildcard $(BSP_DIR)/*.c)
SOURCES += $(wildcard $(TEMP_DIR)/*.c)
SOURCES += $(wildcard $(MYLIB_DIR)/*.c)
SOURCES += $(wildcard $(MODULE_DIR1)/*.c)
SOURCES += $(wildcard $(MODULE_DIR2)/*.c)
SOURCES += $(wildcard $(MODULE_DIR3)/*.c)
SOURCES += $(wildcard $(MODULE_DIR4)/*.c)
#----------Object .O file----------#
#basename:去掉每个单词的前缀、后缀
#addsuffix:添加后缀,addprefix:添加前缀
OBJECTS = $(addprefix $(BUILDDIR)/, $(addsuffix .o, $(basename $(SOURCES))))
#----------Object .h file---------#
INCLUDES += -I$(STM32LIBS_DIR)/Libraries/CMSIS/Include \
-I$(STM32LIBS_DIR)/Libraries/CMSIS/Device/ST/STM32F10x/Include \
-I$(STM32LIBS_DIR)/Libraries/STM32F10x_StdPeriph_Driver/inc \
-I$(USER_DIR) \
-I$(BSP_DIR) \
-I$(MYLIB_DIR) \
-I$(TEMP_DIR) \
-I$(MODULE_DIR1) \
-I$(MODULE_DIR2) \
-I$(MODULE_DIR3) \
-I$(MODULE_DIR4) \
-I$(MODULE_DIR2)/mpl
#----------Object LD extern static lib file and dir----------#
LDLIBS += -lc -lgcc -lm
LDLIBS += -L $(MODULE_DIR2)/mpl
LDLIBS += -llibmplmpu
#----------build Object .c to .O file----------#
CFLAGS = -O0 -g -c -Wall -s -I. -mcpu=cortex-m3 -mthumb \
$(INCLUDES) -DUSE_STDPERIPH_DRIVER -DSTM32F10X_HD
#----------LD Objecd .O to elf file----------#
LDSCRIPT = link.lds
LDFLAGS += -T$(LDSCRIPT) -s -mthumb -mcpu=cortex-m3 -specs=nosys.specs $(LDLIBS)
#----------make start----------#
all : $(BIN) $(HEX)
$(BIN): $(ELF)
$(OBJCOPY) -O binary $< $@
$(HEX): $(ELF)
$(OBJCOPY) -O ihex $< $@
$(ELF): $(OBJECTS)
@echo "**********Linking...**********"
$(LD) $(OBJECTS) $(LDFLAGS) -o $@
@echo "*******Linking Finished!*******"
$(BUILDDIR)/%.o: %.c
mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $< -o $@
$(BUILDDIR)/%.o: %.s
mkdir -p $(dir $@)
$(CC) -c $(CFLAGS) $< -o $@
flash: $(HEX)
sudo chmod +666 $(TTYUSB)
$(STM32FlashDIR) -b 115200 -v -w ./$(HEX) $(TTYUSB)
clean:
rm -rf build
1.4 gcc参数解析
编译过程:预处理-编译-汇编-链接
注:当静态库和动态库同名时, gcc命令将优先使用动态库。
注:链接库的参数不能放到-o参数后面,否则可能会报错。
下载列部分常用的gcc参数,makefile看不太懂的可以参考下面的参数列表
选项 | 含义 |
--help | 显示 gcc 帮助说明。‘target-help’是显示目标机器特定的命令行选项。 |
--version | 显示 gcc 版本号和版权信息 。 |
-o outfile | 输出到指定的文件。 |
-xlanguage | 指明使用的编程语言。允许的语言包括:c c++ assembler none 。 ‘none’意味着恢复默认行为,即根据文件的扩展名猜测源文件的语言。 |
-v | 打印较多信息,显示编译器调用的程序。 |
-### | 与 -v 类似,但选项被引号括住,并且不执行命令。 |
-E | 仅作预处理,不进行编译、汇编和链接。如上图所示。 |
-S | 仅编译到汇编语言,不进行汇编和链接。如上图所示。 |
-c | 编译、汇编到目标代码,不进行链接。 |
-pipe | 使用管道代替临时文件。 |
-combine | 将多个源文件一次性传递给汇编器。 |
-l library(小写L) | 进行链接时搜索名为library的库。 |
-Idir(大写i) | 把dir加入到搜索头文件的路径列表中。 |
-Ldir | 把dir加入到搜索库文件的路径列表中。 |
-Dname | 预定义一个名为name的宏,值为1。 |
-Dname=definition | 预定义名为name,值为definition的宏。 |
-ggdb | 为调试器 gdb 生成调试信息。level可以为1,2,3,默认值为2。 |
-g | 生成操作系统本地格式的调试信息。-g 和 -ggdb 并不太相同, -g 会生成 gdb 之外的信息。level取值同上。 |
-s | 去除可执行文件中的符号表和重定位信息。用于减小可执行文件的大小。 |
-M | 告诉预处理器输出一个适合make的规则,用于描述各目标文件的依赖关系。对于每个源文件,预处理器输出 一个make规则,该规则的目标项(target)是源文件对应的目标文件名,依赖项(dependency)是源文件中 `#include引用的所有文件。生成的规则可以是单行,但如果太长,就用`/'-换行符续成多行。规则 显示在标准输出,不产生预处理过的C程序。 |
-C | 告诉预处理器不要丢弃注释。配合`-E'选项使用。 |
-P | 告诉预处理器不要产生`#line'命令。配合`-E'选项使用。 |
-static | 在支持动态链接的系统上,阻止连接共享库。该选项在其它系统上无效。 |
-nostdlib | 不连接系统标准启动文件和标准库文件,只把指定的文件传递给连接器。 |
Warnings |
|
-Wall | 会打开一些很有用的警告选项,建议编译时加此选项。 |
-W | 打印一些额外的警告信息。 |
-w | 禁止显示所有警告信息。 |
-Wshadow | 当一个局部变量遮盖住了另一个局部变量,或者全局变量时,给出警告。很有用的选项,建议打开。 -Wall 并不会打开此项。 |
-Wpointer-arith | 对函数指针或者void *类型的指针进行算术操作时给出警告。也很有用。 -Wall 并不会打开此项。 |
-Wcast-qual | 当强制转化丢掉了类型修饰符时给出警告。 -Wall 并不会打开此项。 |
-Waggregate-return | 如果定义或调用了返回结构体或联合体的函数,编译器就发出警告。 |
-Winline | 无论是声明为 inline 或者是指定了-finline-functions 选项,如果某函数不能内联,编译器都将发出警告。如果你的代码含有很多 inline 函数的话,这是很有用的选项。 |
-Werror | 把警告当作错误。出现任何警告就放弃编译。 |
-Wunreachable-code | 如果编译器探测到永远不会执行到的代码,就给出警告。也是比较有用的选项。 |
-Wcast-align | 一旦某个指针类型强制转换导致目标所需的地址对齐增加时,编译器就发出警告。 |
-Wundef | 当一个没有定义的符号出现在 #if 中时,给出警告。 |
-Wredundant-decls | 如果在同一个可见域内某定义多次声明,编译器就发出警告,即使这些重复声明有效并且毫无差别。 |
Optimization |
|
-O0 | 禁止编译器进行优化。默认为此项。 |
-O | 尝试优化编译时间和可执行文件大小。 |
-O2 | 更多的优化,会尝试几乎全部的优化功能,但不会进行“空间换时间”的优化方法。 |
-O3 | 在 -O2 的基础上再打开一些优化选项:-finline-functions, -funswitch-loops 和 -fgcse-after-reload 。 |
-Os | 对生成文件大小进行优化。它会打开 -O2 开的全部选项,除了会那些增加文件大小的。 |
-finline-functions | 把所有简单的函数内联进调用者。编译器会探索式地决定哪些函数足够简单,值得做这种内联。 |
-fstrict-aliasing | 施加最强的别名规则(aliasing rules)。 |
ARM |
|
-mthumb | 指令集 |
-mcpu=cortex-m3 |
|
-T | 指定链接文件 |
1.5 ld链接文件解析
主要设置系统flash/arm的起始地址和大小,还有堆栈的结束地址
这个也是跟keil有所不一样的,keil使用的是链接文件和启动文件时一起的,但是在makefile使用gcc编译时,启动文件时是定义向量并初始化,并没有定义堆栈的大小和地址等,而是在链接文件中定义,这里主要声明了堆栈的地址、flash和ram的大小,其他的相对并不太需要修改。
/*
*****************************************************************************
**
** File : stm32_flash.ld
**
** Abstract : Linker script for STM32F103ZE Device with
** 512KByte FLASH, 64KByte RAM
*****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x20010000; /* end of 64K RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x200; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
.ARM : {
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.ARM.attributes : { *(.ARM.attributes) } > FLASH
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(.fini_array*))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = .;
/* Initialized data sections goes into RAM, load LMA copy after code */
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss secion */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(4);
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(4);
} >RAM
/* MEMORY_bank1 section, code must be located here explicitly */
/* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */
.memory_b1_text :
{
*(.mb1text) /* .mb1text sections (code) */
*(.mb1text*) /* .mb1text* sections (code) */
*(.mb1rodata) /* read-only data (constants) */
*(.mb1rodata*)
} >MEMORY_B1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
}
1.6 串口下载程序
1、stm32flash
https://sourceforge.net/p/stm32flash/wiki/Home/
https://github.com/ARMinARM/stm32flash
下载之后make编译,插上串口,设置一下usb的权限为666,即可使用串口下载程序。
下载是github的简单使用说明:
Usage: ./stm32flash [-bvngfhc] [-[rw] filename] /dev/ttyS0
-b rate Baud rate (default 57600)
-r filename Read flash to file
-w filename Write flash to file
-u Disable the flash write-protection
-e n Only erase n pages before writing the flash
-v Verify writes
-n count Retry failed writes up to count times (default 10)
-g address Start execution at specified address (0 = flash start)
-s start_page Flash at specified page (0 = flash start)
-f Force binary parser
-h Show this help
-c Resume the connection (don't send initial INIT)
*Baud rate must be kept the same as the first init*
This is useful if the reset fails
好了,eclipse的安装比较单一,在这里就不详述了,到此搞定。但是发现有一些问题:
1、gcc编译出来的目标文件在同等优化等级的情况下会大%30左右,这个很让然头痛。
2、在使用优化的时候发现以前在keil下写的一些代码出现了bug,特别是关于Volatile的疏忽,才发现keil是会自动完善这些代码bug,这里是小弟写的代码风格不严谨,惭愧惭愧。
3、flash下载的速度实在跟stlink等工具没法比,下载得据需搞搞stlink的下载才行。