之前一直在做Linux应用层相关的工作,使用ubuntu编译代码。最近的项目中需要用到stm32,stm32的编译环境为keil5。在一台电脑上装两个编译器总数觉得麻烦,故而想能不能直接使用ubuntu来编译stm32的程序。在网上搜索“使用ubuntu编译stm32程序”,发现有很多教程,但是都不太全面,自己试着编译一下,在编译过程中也遇到了一些问题,现在将编译过程和遇到的问题总结如下。
1、首先,需要配置一个交叉编译环境,这里提供一个最新的交叉编译器的百度云连接:https://pan.baidu.com/s/1Y8dKZEU3cQcY7eatONF8og ,密码:ttsh。将该编译器添加到ubuntu系统环境中即可。执行命令 arm-none-eabi-gcc -v,能够查看到版本信息就,说明安装成功。
2、交叉编译环境配置成功以后,需要建立一个工程文件,我使用的是hal库,直接将hal库源码拷贝至工程文件中即可。特别注意:不同的编译器startup文件会有所不同,一定要找对应编译器所支持的startup文件。我建立的工程文件目录结构如下:
├── build
├── Library
│ ├── CMSIS
│ │ ├── core_cm3.c
│ │ ├── core_cm3.h
│ │ ├── stm32f10x.h
│ │ ├── system_stm32f10x.c
│ │ └── system_stm32f10x.h
│ └── FWLIB
│ ├── inc
│ │ ├── misc.h
│ │ ├── stm32f10x_adc.h
│ │ ├── stm32f10x_bkp.h
│ │ ├── stm32f10x_can.h
│ │ ├── stm32f10x_cec.h
│ │ ├── stm32f10x_crc.h
│ │ ├── stm32f10x_dac.h
│ │ ├── stm32f10x_dbgmcu.h
│ │ ├── stm32f10x_dma.h
│ │ ├── stm32f10x_exti.h
│ │ ├── stm32f10x_flash.h
│ │ ├── stm32f10x_fsmc.h
│ │ ├── stm32f10x_gpio.h
│ │ ├── stm32f10x_i2c.h
│ │ ├── stm32f10x_iwdg.h
│ │ ├── stm32f10x_pwr.h
│ │ ├── stm32f10x_rcc.h
│ │ ├── stm32f10x_rtc.h
│ │ ├── stm32f10x_sdio.h
│ │ ├── stm32f10x_spi.h
│ │ ├── stm32f10x_tim.h
│ │ ├── stm32f10x_usart.h
│ │ └── stm32f10x_wwdg.h
│ └── src
│ ├── misc.c
│ ├── stm32f10x_adc.c
│ ├── stm32f10x_bkp.c
│ ├── stm32f10x_can.c
│ ├── stm32f10x_cec.c
│ ├── stm32f10x_crc.c
│ ├── stm32f10x_dac.c
│ ├── stm32f10x_dbgmcu.c
│ ├── stm32f10x_dma.c
│ ├── stm32f10x_exti.c
│ ├── stm32f10x_flash.c
│ ├── stm32f10x_fsmc.c
│ ├── stm32f10x_gpio.c
│ ├── stm32f10x_i2c.c
│ ├── stm32f10x_iwdg.c
│ ├── stm32f10x_pwr.c
│ ├── stm32f10x_rcc.c
│ ├── stm32f10x_rtc.c
│ ├── stm32f10x_sdio.c
│ ├── stm32f10x_spi.c
│ ├── stm32f10x_tim.c
│ ├── stm32f10x_usart.c
│ └── stm32f10x_wwdg.c
├── Makefile
├── startup
│ ├── startup_stm32f103xb.S
│ └── STM32F103XB.ld
└── User
├── main.c
├── stm32f10x_conf.h
├── stm32f10x_it.c
└── stm32f10x_it.h
3、如何编译工程:在编译Linux应用层文件时,若编译的文件较多,则使用一个Makefile脚本,一个make命令即可编译完成。编译stm32程序也不例外,在此,我们需要编写一个Makefile脚本。我从网上找了一个Makefile脚本,编译时发现有问题,做了部分修改以后的Makefile脚本如下。
#读取当前工作目录
TOP=$(shell pwd)
BUILD_DIR = build
TARGET = stm32_test
#设定包含文件目录
INC_FLAGS += -I $(TOP)/Library/CMSIS
INC_FLAGS += -I $(TOP)/Library/FWLIB/inc
INC_FLAGS += -I $(TOP)/User
CROSS_COMPILE=arm-none-eabi-
ASM=$(CROSS_COMPILE)as
CC=$(CROSS_COMPILE)gcc
CPP=$(CROSS_COMPILE)cpp
LD=$(CROSS_COMPILE)ld
HEX=$(CROSS_COMPILE)objcopy
OBJCOPY=$(CROSS_COMPILE)objcopy
OBJDUMP=$(CROSS_COMPILE)objdump
#######################################
# ASM sources
# 注意,如果使用.c的startup文件,请把下面两句注释掉,避免编译出现错误
#######################################
ASM_SOURCES = startup/startup_stm32f103xb.S
#######################################
# CFLAGS
#######################################
# debug build?
DEBUG = 1
# 代码优化级别
OPT = -Os
# cpu
CPU = -mcpu=cortex-m3
# fpu
# NONE for Cortex-M0/M0+/M3
# float-abi
# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
# C defines
# 这个地方的定义根据实际情况来,如果在代码里面有定义(如#define STM32F10X_HD),这里可以不写
C_DEFS = \
-D USE_STDPERIPH_DRIVER \
-D STM32F10X_HD
# PreProcess
CFLAGS = -g $(MCU) $(C_DEFS) $(INC_FLAGS) $(OPT) -std=gnu99 -W -Wall -fdata-sections -ffunction-sections
#ifeq ($(DEBUG), 1)
#CFLAGS += -g -gdwarf-2
#endif
# 在$(BUILD_DIR)目录下生成依赖关系信息,依赖关系以.d结尾
CFLAGS += -MMD -MP -MF"$(addprefix $(BUILD_DIR)/, $(notdir $(@:%.o=%.d)))"
#######################################
# LDFLAGS
#######################################
# LD文件
LDSCRIPT = startup/STM32F103XB.ld
# libraries
LIBS = -L/usr/local/arm/gcc-arm-none-eabi-8-2018-q4-major/arm-none-eabi/lib/ -lc -lm -lnosys
LIBDIR =
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
#######################################
# C/CPP源代码
#######################################
C_SRC = $(shell find ./ -name '*.c')
C_SRC += $(shell find ./ -name '*.cpp')
C_OBJ = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SRC:%.c=%.o)))
vpath %.c $(sort $(dir $(C_SRC)))
#C_OBJ += $(ASM_SOURCES)
C_OBJ += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.S=.o)))
vpath %.S $(sort $(dir $(ASM_SOURCES)))
.PHONY: all clean update
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
# 从vpath中读取所有的.c文件,编译成.o文件
$(BUILD_DIR)/%.o: %.c | $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) -o $@ $<
# 从vpath中u读取所有的.s文件,编译成.o文件
$(BUILD_DIR)/%.o: %.S | $(BUILD_DIR)
$(ASM) -c $< -o $@
# 将所有的.o文件依据.ld文件,编译组成.elf文件
$(BUILD_DIR)/$(TARGET).elf: $(C_OBJ)
$(LD) -Tstartup/STM32F103XB.ld $(LIBS) $(C_OBJ) -o $@
# $(SZ) $@
# 将.elf文件转为.hex格式
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf
$(OBJCOPY) -O ihex $< $@
# 将.elf文件转为.bin格式
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf
$(OBJCOPY) -O binary $< $@
# 用于生成BUILD_DIR目录
$(BUILD_DIR):
mkdir $@
clean:
rm -rf $(BUILD_DIR)
4、开始编译,执行 make 命令即可进行编译。第一次编译报错“registers may not be the same -- `strexh r0,r0,[r1] ”,修改core_cm3.c文件第736行和753行
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
为
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) ); 即可;
在startup_stm32f103xb.S 文件中无_start函数,编译时报错,将它改为main即可。
编译成功以后,在build目录下会有stm32_test.bin和stm32_test.hex文件,可将这两个文件中的一个文件下载到stm32中去。
5、下载程序:网上关于使用ubuntu下载stm32程序的教程有很多,需要装各种驱动,我个人认为这些比较麻烦,正巧在Windows下有一个下载stm32程序的工具,该工具简单方便,不必要在ubuntu中下载文件。Windows下的下载工具连接为链接:https://pan.baidu.com/s/1nCHWd1Bhse4o8GhGQyyYFA ,提取码:jee7 。
6、目前暂未找到较为简单方便的方法进行调试,我使用的一个调试串口进行调试程序,网上也有其他的调试程序的方法,各位看官可自行选择调试方法。