之前一直在做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、目前暂未找到较为简单方便的方法进行调试,我使用的一个调试串口进行调试程序,网上也有其他的调试程序的方法,各位看官可自行选择调试方法。

 

Logo

更多推荐