STM32 Development For Linux

独白:使用STM32也快三年了,最近正在从windows转移到linux下,系统装好后大致的环境和软件都调的差不多,接下来就是开发一类的工具转移,今天要吸血的是STM32,准备使用GCC编译、eclipse编写,依然使用官方的库。测试型号是STM32F103RC,我并不打算捣鼓一个最简洁的工程做测试一了了之,在这里我将我的平时整理的整个STM32的工程移过来。

1.1 安装GCC

1stm32 属于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 
--target-help

显示 gcc 帮助说明。‘target-help’是显示目标机器特定的命令行选项。

--version

显示 gcc 版本号和版权信息 。

-o outfile

输出到指定的文件。

-xlanguage

指明使用的编程语言。允许的语言包括:c c++ assembler none 。 ‘none’意味着恢复默认行为,即根据文件的扩展名猜测源文件的语言。

-v

打印较多信息,显示编译器调用的程序。

-###

与 -v 类似,但选项被引号括住,并且不执行命令。

-E

仅作预处理,不进行编译、汇编和链接。如上图所示。

-S

仅编译到汇编语言,不进行汇编和链接。如上图所示。

-c

编译、汇编到目标代码,不进行链接。

-pipe

使用管道代替临时文件。

-combine

将多个源文件一次性传递给汇编器。


-l library(小写L)
-llibrary

进行链接时搜索名为library的库。
例子: $ gcc test.c -lm -o test

-Idir(大写i)

dir加入到搜索头文件的路径列表中。
例子: $ gcc test.c -I../inc -o test

-Ldir

dir加入到搜索库文件的路径列表中。
例子: $ gcc -I/home/foo -L/home/foo -ltest test.c -o test

-Dname

预定义一个名为name的宏,值为1
例子: $ gcc -DTEST_CONFIG test.c -o test

-Dname=definition

预定义名为name,值为definition的宏。

-ggdb 
-ggdblevel

为调试器 gdb 生成调试信息。level可以为123,默认值为2

-g 
-glevel

生成操作系统本地格式的调试信息。-g 和 -ggdb 并不太相同, -g 会生成 gdb 之外的信息。level取值同上。

-s

去除可执行文件中的符号表和重定位信息。用于减小可执行文件的大小。

-M

告诉预处理器输出一个适合make的规则,用于描述各目标文件的依赖关系。对于每个源文件,预处理器输出 一个make规则,该规则的目标项(target)是源文件对应的目标文件名,依赖项(dependency)是源文件中 `#include引用的所有文件。生成的规则可以是单行,但如果太长,就用`/'-换行符续成多行。规则 显示在标准输出,不产生预处理过的C程序。

-C

告诉预处理器不要丢弃注释。配合`-E'选项使用。

-P

告诉预处理器不要产生`#line'命令。配合`-E'选项使用。

-static

在支持动态链接的系统上,阻止连接共享库。该选项在其它系统上无效。

-nostdlib

不连接系统标准启动文件和标准库文件,只把指定的文件传递给连接器。

 

Warnings

 

-Wall

会打开一些很有用的警告选项,建议编译时加此选项。

-W 
-Wextra

打印一些额外的警告信息。

-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 
-O1

尝试优化编译时间和可执行文件大小。

-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的下载才行。


 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值