在Linux上使用Makefile编译stm32程序
STM32的Linux开发环境设置
stm32开发常用的IDE开发环境,虽然比较方便使用,但是却有各种不便:
- ~
MDK需要购买~ - ~
MDK不支持Linux~ - TrueStudio启动太慢,启动后太消耗系统资源
- TrueStudio定期弹出广告
- 如果TrueStudio不是焦点窗口,弹广告之后有一个子窗口无法关闭,需要关闭IDE一次再重新打开 ->_->
那么如何使用神器Vim+Gcc来进行自定义开发呢?
arm公司已经提供了现成的arm-none-eabi开发工具链,只需要写好Makefile就可以了。
生成Makefile
由于使用的工程是用TrueStudio的模板来生成的,可以借助TrueStudio来生成Makefile模板,然后再根据实际情况修改一下。
在TrueStudio创建一个新工程,选择新的Embedded C Makefile工程,然后选择对应的MCU。
将生成的模板工程的Makefile复制到需要Makefile的工程源码目录,并修改对应配置,主要是link脚本路径,以及头文件路径:
LINK_SCRIPT="stm32_flash.ld"
ASSEMBLER_FLAGS=-c -g -O0 -mcpu=cortex-m3 -mthumb -D"STM32F10X_HD" -D"USE_STDPERIPH_DRIVER" -x assembler-with-cpp -Isrc -IOtherIncludes
COMPILER_FLAGS=-c -g -mcpu=cortex-m3 -O0 -Wall -ffunction-sections -fdata-sections -mthumb -D"STM32F10X_HD" -D"USE_STDPERIPH_DRIVER" -Isrc -IOtherIncludes
这些编译选项,在IDE中的工程环境配置中也有,直接复制过来即可。
安装编译工具
如果你已经安装了Atollic TrueStudio,可以使用 TrueStudio的arm编译工具链。
默认安装路径是/opt/Atollic_TrueSTUDIO_for_ARM_x86_64_8.0.0
。将Atollic的arm编译工具添加到环境中:
echo "export PATH=/opt/Atollic_TrueSTUDIO_for_ARM_x86_64_8.0.0/ARMTools/bin:\$PATH" > $HOME/.bashrc
如果你没有安装任何Linux上的STM32开发工具,可以安装arm提供的:
sudo apt install binutils-arm-none-eabi gcc-arm-none-eabi gdb-arn-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi
安装编辑器
到这里您就可以使用以下命令来安装Vim了:
sudo apt install vim
如果想要使用现代化一点的图形界面工具,可以使用Visual Studio Code,一款在Github Atom基础上改写的一款文本编辑器,提供了如下好处:
- Team Explorer插件可以用来访问Team Foundation Server上的代码和Task。
- Git Lens插件(基于git blame功能)提供的逐行提交记录可以方便的查阅团队代码。
- 代码高亮,自动补全,代码纠错,等等,安装插件方便。
安装VS Code可以直接去官网下载deb包,或者使用最新版的ubuntu make一键安装。
sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make
sudo apt update
sudo apt install ubuntu-make
umake ide visual-studio-code
下载完成后安装需要的插件,打开源码目录。
配置编辑器
这是一个说不完的主题,简单来说,
- 使用vim请参考官方文档
- 使用VS Code,安装c/C++插件,添加索引目录
安装烧写工具
根据不同的下载接口,安装对应的烧写工具。
串口烧写
通过串口或I2C接口烧写,可以下载stm32flash源码编译,ubuntu 15.04及以上用户可以直接安装:
sudo apt install stm32flash
stm32flash -w filename -v -g 0x0 /dev/ttyS0
ST-Link烧写
使用ST-Link接口的烧写器,可以安装stlink工具:
git clone https://github.com/texane/stlink.git
cd stlink
sudo apt install libusb-1.0-0-dev cmake build-essenial
make release
cd build/Release; make install DESTDIR=$HOME/.local/bin
echo "export PATH=\$HOME/.local/bin:\$PATH" > $HOME/.bashrc
st-flash --format ihex write filename.hex
修改Makefile自动烧写
生成的Makefile模板默认生成的是elf格式的文件,如果想要生成hex或者bin格式,可以在Makefile中添加:
Makefile
CC = arm-none-eabi-gcc
CP = arm-none-eabi-objcopy
OBJECT_DIR = build
BIN_DIR = $(OBJECT_DIR)
PROJ = test
ELF = $(PROJ).elf
HEX = $(PROJ).hex
BIN = $(PROJ).bin
MAP = $(PROJ).map
all: buildelf
buildelf: $(OBJS)
$(CC) -o $(ELF) $(OBJS) $(LINKER_FLAGS)
$(CP) -O ihex $(ELF) $(HEX)
$(CP) -O binary $(ELF) $(BIN)
flash: $(HEX)
st-flash --format ihex write $(HEX)
clean:
$(RM) $(OBJS) $(ELF) $(HEX) $(BIN) $(MAP)
编译并烧写hex文件:
make
make flash
示例
这是一份修改后的示例Makefile:
###############################################################################
#
# File : Makefile
#
# Abstract : Example Makefile for a C Project
#
# Environment : Atollic TrueSTUDIO(R)
#
###############################################################################
# System configuration
CC = arm-none-eabi-gcc
CP = arm-none-eabi-objcopy
RM=rm -rf
# Define output directory
OBJECT_DIR = build
BIN_DIR = $(OBJECT_DIR)
# Output file names
PROJ = test
HEX = $(BIN_DIR)/$(PROJ).hex
BIN = $(BIN_DIR)/$(PROJ).bin
ELF = $(BIN_DIR)/$(PROJ).elf
MAP = $(BIN_DIR)/$(PROJ).map
# Assembler, Compiler and Linker flags and linker script settings
LINKER_FLAGS=-lm -mthumb -mcpu=cortex-m3 -Wl,--gc-sections -T$(LINK_SCRIPT) -static -Wl,--start-group -lc -lm -Wl,--end-group -specs=nosys.specs -Wl,-cref "-Wl,-Map=$(MAP)" -Wl,--defsym=malloc_getpagesize_P=0x1000
LINK_SCRIPT="stm32_flash.ld"
ASSEMBLER_FLAGS=-c -g -O0 -mcpu=cortex-m3 -mthumb -D"STM32F10X_HD" -D"USE_STDPERIPH_DRIVER" -x assembler-with-cpp -Isrc -IOtherIncludes
COMPILER_FLAGS=-c -g -mcpu=cortex-m3 -O0 -Wall -ffunction-sections -fdata-sections -mthumb -D"STM32F10X_HD" -D"USE_STDPERIPH_DRIVER" -Isrc -IOtherIncludes
# Define sources and objects
SRC := $(wildcard */*/*/*/*/*/*/*.c) \
$(wildcard */*/*/*/*/*/*.c) \
$(wildcard */*/*/*/*/*.c) \
$(wildcard */*/*/*/*.c) \
$(wildcard */*/*/*.c) \
$(wildcard */*/*.c) \
$(wildcard */*.c)
SRCSASM := $(wildcard */*/*/*/*/*/*/*/*.s) \
$(wildcard */*/*/*/*/*/*/*.s) \
$(wildcard */*/*/*/*/*/*.s) \
$(wildcard */*/*/*/*/*.s) \
$(wildcard */*/*/*/*.s) \
$(wildcard */*/*/*.s) \
$(wildcard */*/*.s) \
$(wildcard */*.s)
OBJS := $(SRC:%.c=$(OBJECT_DIR)/%.o) $(SRCSASM:%.s=$(OBJECT_DIR)/%.o)
OBJS := $(OBJS:%.S=$(OBJECT_DIR)/%.o)
###############
# Build project
# Major targets
###############
all: buildelf
buildelf: $(OBJS)
$(CC) -o $(ELF) $(OBJS) $(LINKER_FLAGS)
$(CP) -O ihex $(ELF) $(HEX)
$(CP) -O binary $(ELF) $(BIN)
flash: $(HEX)
st-flash --format ihex write $(HEX)
clean:
$(RM) $(OBJS) $(ELF) $(HEX) $(BIN) $(MAP)
##################
# Specific targets
##################
$(OBJECT_DIR)/src/main.o: src/main.c
@mkdir -p $(dir $@) 2> /dev/null
$(CC) $(COMPILER_FLAGS) src/main.c -o $(OBJECT_DIR)/src/main.o
##################
# Implicit targets
##################
$(OBJECT_DIR)/%.o: %.c
@mkdir -p $(dir $@) 2> /dev/null
$(CC) $(COMPILER_FLAGS) $< -o $@
$(OBJECT_DIR)/%.o: %.s
@mkdir -p $(dir $@) 2> /dev/null
$(CC) $(ASSEMBLER_FLAGS) $< -o $@
$(OBJECT_DIR)/%.o: %.S
@mkdir -p $(dir $@) 2> /dev/null
$(CC) $(ASSEMBLER_FLAGS) $< -o $@