VSCode虽然只是一个代码编辑器,由于开源并提供了易用的插件接口,目前已拥有丰富的第三方插件,可以联合gcc构建一个类似于IDE的开发调试环境。
gcc编译套件
stm32使用了arm的Cortex-M内核,直接上arm官官网下载mcu编译套件:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads,下载arm-none-eabi版本可以编译裸机程序或者RTOS的程序。下载成功后直接解压到本地目录,并添加其bin文件夹到环境变量。安装成功后可通过下面指令进行测试(目前gcc为12.2.1版本):
成功安装了这个gcc编译套件几乎还不能编译哪怕是一个led闪烁的工程,这是由于任何一个工程几乎不太可能只有一个源文件组成,在文件达到一定的规模直接使用gcc命令去编译是一件容易出错且效率极低的工作,这里我们就需要一套建构工具,比如常听说的GNU Make、qmake、namake、pmake、SCons等等。
构建工具
make
make几乎属于构建工具的第一代但是应用较为广泛,从头makefile文件编写对经常使用makefile的工程师也较为困难,但STM32CubeMX生成的工程也提供了较为完善的支持可自动生成基础的makefile文件。
在windows上下载make工具:https://github.com/skeeto/w64devkit/releases,下载成功后将其bin文件添加到环境变量,安装成功后可以通过以下指令进行测试,此时按理说应该能使用make进行编译了,但makefile中可能重新定义了某些绝对路径导致编译失败,这是需要重新定义Makefile中的相关变量,然后就能正常编译了。
安装成功后直接使用STM32CubeMX生成Makefile工具链工程即可,切换到源码目录直接编译:
STM32CubeMX生成了一个基础可直接使用makefile工程,后续仅需要把应用代码添加到其Makefile中即可。代码编写直接使用VSCode即可,编写完成后执行make指令进行编译。
##########################################################################################################################
# File automatically-generated by tool: [projectgenerator] version: [3.17.1] date: [Mon Jul 03 18:35:08 CST 2023]
##########################################################################################################################
# ------------------------------------------------
# Generic Makefile (based on gcc)
#
# ChangeLog :
# 2017-02-10 - Several enhancements + project update mode
# 2015-07-22 - first version
# ------------------------------------------------
######################################
# target
######################################
TARGET = GCC
######################################
# building variables
######################################
# debug build?
DEBUG = 1
# optimization
OPT = -Og
#######################################
# paths
#######################################
# Build path
BUILD_DIR = build
######################################
# source
######################################
# C sources
C_SOURCES = \
Core/Src/main.c \
Core/Src/stm32l4xx_it.c \
Core/Src/stm32l4xx_hal_msp.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c \
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c \
Core/Src/system_stm32l4xx.c
# ASM sources
ASM_SOURCES = \
startup_stm32l412xx.s
#######################################
# binaries
#######################################
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
#######################################
# CFLAGS
#######################################
# cpu
CPU = -mcpu=cortex-m4
# fpu
FPU = -mfpu=fpv4-sp-d16
# float-abi
FLOAT-ABI = -mfloat-abi=hard
# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
# macros for gcc
# AS defines
AS_DEFS =
# C defines
C_DEFS = \
-DUSE_HAL_DRIVER \
-DSTM32L412xx
# AS includes
AS_INCLUDES =
# C includes
C_INCLUDES = \
-ICore/Inc \
-IDrivers/STM32L4xx_HAL_Driver/Inc \
-IDrivers/STM32L4xx_HAL_Driver/Inc/Legacy \
-IDrivers/CMSIS/Device/ST/STM32L4xx/Include \
-IDrivers/CMSIS/Include
# compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif
# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = STM32L412KBUx_FLASH.ld
# libraries
LIBS = -lc -lm -lnosys
LIBDIR =
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(HEX) $< $@
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BIN) $< $@
$(BUILD_DIR):
mkdir $@
#######################################
# clean up
#######################################
clean:
-rm -fR $(BUILD_DIR)
#######################################
# dependencies
#######################################
-include $(wildcard $(BUILD_DIR)/*.d)
# *** EOF ***
cmake
cmake几乎属于构建工具的第三代,使用体验上相比makefile要好得多,但STM32CubeMX并为直接支持cmake,使用cmake去构建开发环境之前需要编写cmake编译脚本(类似于makefile,更加简单和通用)。
首先上cmake官方网站上下载cmake:https://cmake.org/download/,下载后直接安装,安装成功可在命令行中直接测试:
相同的方案使用STM32CubeMX生成一个makefile的工程:
与make的makefile类似,cmake有CMakeList.tx控制各个编译规则:
#cmake 最低版本要求
cmake_minimum_required(VERSION 3.22)
#交叉编译配置
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
#C语言与汇编语言配置
set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
set(CMAKE_ASM_COMPILER "arm-none-eabi-gcc")
set(CMAKE_C_FLAGS " -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Dgcc -Og -gdwarf-2 -g")
set(CMAKE_ASM_FLAGS " -c -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -x assembler-with-cpp -Wa,-mimplicit-it=thumb -gdwarf-2")
set(CMAKE_C_COMPILER_WORKS TRUE)
#C++语言配置
set(CMAKE_CXX_COMPILER "arm-none-eabi-gcc")
set(CMAKE_CXX_FLAGS " -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Dgcc -Og -gdwarf-2 -g")
set(CMAKE_CXX_COMPILER_WORKS TRUE)
#自定义变量
set(CMAKE_OBJCOPY "arm-none-eabi-objcopy")
set(CMAKE_SIZE "arm-none-eabi-size")
#链接配置
SET(CMAKE_EXE_LINKER_FLAGS " -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections -Wl,--gc-sections,-Map=stm32.map,-cref,-u,Reset_Handler -T ${CMAKE_SOURCE_DIR}/STM32L412KBUx_FLASH.ld")
#编程语言版本
SET(CMAKE_CXX_STANDARD 14)
#项目名称、编程语言
project(stm32 C CXX ASM)
#搜索头文件目录
include_directories(
Core/Inc
Drivers/STM32L4xx_HAL_Driver/Inc
Drivers/STM32L4xx_HAL_Driver/Inc/Legacy
Drivers/CMSIS/Device/ST/STM32L4xx/Include
Drivers/CMSIS/Include
)
#全局宏定义
add_definitions(
-DUSE_HAL_DRIVER
-DSTM32L412xx
)
#自定义变量,编译源文件
set(
PROJECT_SOURCES
Core/Src/main.c
Core/Src/stm32l4xx_it.c
Core/Src/stm32l4xx_hal_msp.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_tim_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_uart_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_i2c_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_rcc_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ramfunc.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_gpio.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_dma_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_pwr_ex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_cortex.c
Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_exti.c
Core/Src/system_stm32l4xx.c
startup_stm32l412xx.s
)
在CMakeList.txt相同目录,执行以下指令生成makefile:
cmake . -G “MinGW Makefiles” -B CMakeBuild
切换到CMakeBuild目录,执行make进行编译:
Embedded IDE
make和cmake更多的是将VSCode作为代码编辑工具,Embedded IDE可以将VSCode作为一个较为完整的IDE进行代码编写、编译、下载等功能,Embedded IDE 是VS Code的一个插件,用于搭建mcs51/stm8/cortex-m/riscv的c/c++的集成开发环境,开发体验相比keil/iar等IDE都要好。可直接从现有的IAR/KEIL/Eclipse工程直接导入,支持windows、Linux和macOS操作系统。Embedded IDE支持了keil的编译器、iar的编译,但仍然推荐gcc的编译器。
VSCode中安装Embedded IDE插件:
Embedded IDE支持从MDK、IAR以及Eclipse导入工程,这样就可以使用STM32CubeMX生成一个Eclipse工程后直接导入到Embedded IDE即可完成环境搭建,当然STM32CubeMX的Eclipse配置如下:
导入到Embedded IDE中:
然后进行编译:
编译成功根据硬件实际连接修改选择对应下载器,
此时已能通过Embedded IDE进行代码开发、编译、下载,当然与成熟的IDE相比目前还不能进行代码调试,若需要进行代码仿真调试还需要通过另外一个VSCode插件-Cortex-Debug。
调试
安装Cortex-Debug插件:
默认使用了openocd链接仿真器进行调试(若没有安装需要单独安装openocd),然后选择对应仿真器(一般是stlink或者jlink)和芯片系列型号:
配置完成后就可以启动调试了,可实现与IDE一样的调试功能:
由于openocd对jlink支持不好,若使用了jlink进行仿真调试,需要重新修改lanch.json跨过opnocd直接调用JLinkGDBServer进行仿真调试。