为摒弃在接受keil邮件,研究了下gun编译,以STM32F407为例,简单记录
1. 软件包准备
- Git
选择对应版本直接安装即可https://git-scm.com/download/win - make
- gcc
1)将上述软件包放置于C盘根目录
2)添加环境变量
3)cmd命令行测试环境
分别输入
make -v
gcc -v
2. 编写makefile
# ------------------------------------------------
#
# @file Makefile (based on gcc)
# @author urien
# @version v1.0.0
#
# ChangeLog :
# 2023-10-20
# ------------------------------------------------
######################################
# target
######################################
TARGET = update
######################################
# building variables
######################################
# debug build?
DEBUG = 1
# optimization
OPT = -Og
#######################################
# paths
#######################################
# Build path
BUILD_DIR = build
######################################
# source
######################################
# C sources
C_DIRS += ../Libraries/FreeRTOS
C_DIRS += ../Libraries/FreeRTOS/portable/GCC/ARM_CM4F
C_DIRS += ../Libraries/CMSIS/Device/ST/STM32F4xx/Source
C_DIRS += ../Libraries/STM32F4xx_StdPeriph_Driver/src
C_DIRS += ../User/app
C_DIRS += ../User/bsp
C_DIRS += ../User/mid
C_DIRS += ../User/misc
C_DIRS += ../User/gui/app
C_DIRS += ../User/gui/lib
C_DIRS += ../User/usb
C_DIRS += ../Libraries/FATFS/source
C_DIRS += ../Libraries/STM32_USB_HOST_Library/Core/src
C_DIRS += ../Libraries/STM32_USB_HOST_Library/Class/MSC/src
C_DIRS += ../Libraries/PDF
SRC_OBJS_DIRS += $(foreach DIR, $(C_DIRS), $(wildcard $(DIR)/*.c))
C_SOURCES = $(SRC_OBJS_DIRS) \
../Libraries/FreeRTOS/portable/MemMang/heap_4.c \
../Libraries/STM32_USB_OTG_Driver/src/usb_core.c \
../Libraries/STM32_USB_OTG_Driver/src/usb_hcd.c \
../Libraries/STM32_USB_OTG_Driver/src/usb_hcd_int.c \
# Core/Src/main.c \
# Core/Src/fr
# ASM sources
ASM_SOURCES = \
startup_stm32f407xx.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 = \
-DSTM32F407xx \
-DSTM32F40_41xxx \
-DUSE_STDPERIPH_DRIVER \
-DUSE_USB_OTG_FS \
-DUSER_VECT_TAB_ADDRESS \
# -D__FPU_PRESENT \
# -D__FPU_USED \
# AS includes
AS_INCLUDES =
# C includes
C_INCS += ../Libraries/CMSIS/Include
C_INCS += ../Libraries/CMSIS/Core/Include
C_INCS += ../Libraries/CMSIS/Device/ST/STM32F4xx/Include
C_INCS += ../Libraries/STM32F4xx_StdPeriph_Driver/inc
C_INCS += ../Libraries/FreeRTOS/include
C_INCS += ../Libraries/FreeRTOS/GCC/ARM_CM4F
C_INCS += ../Libraries/FreeRTOS/portable/GCC/ARM_CM4F
C_INCS += ../Libraries/PDF
C_INCS += ../User/app
C_INCS += ../User/bsp
C_INCS += ../User/mid
C_INCS += ../User/misc
C_INCS += ../User/gui/app
C_INCS += ../User/gui/lib
C_INCS += ../User/usb
C_INCS += ../Libraries/STM32_USB_OTG_Driver/inc
C_INCS += ../Libraries/STM32_USB_HOST_Library/Class/MSC/inc
C_INCS += ../Libraries/STM32_USB_HOST_Library/Core/inc
C_INCS += ../Libraries/FATFS/source
INCS_OBJS_DIR = $(foreach DIR2, $(C_INCS), $(wildcard $(DIR2)/*.h))
INCS_OBJS_PATH = $(sort $(dir $(INCS_OBJS_DIR)))
C_INCLUDES = $(addprefix -I,$(INCS_OBJS_PATH)) \
# 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 = STM32F407VGTx_FLASH.ld
# libraries
LIBS = -lc -lm -lnosys
LIBDIR =
# LDFLAGS += -lc -lrdimon -u _printf_float
# LDFLAGS += -specs=nano.specs
LDFLAGS += $(MCU) -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)
#######################################
# download .hex/.bin by jlink
#######################################
#Your JLink installation directory
PATH_WINPC = 'C:/Program Files (x86)/SEGGER/JLink/'
#PATH_LINUX = /opt/SEGGER/JLink_V640b/JLinkExe
JK_DPATH = $(PATH_WINPC)
#Jlink script store directory
JKS_DIR = .
#Chip type
CHIP_TYPE = STM32F407VG
flash:
@$(JK_DPATH)JLink.exe -device $(CHIP_TYPE) -if SWD -speed 4000 -autoconnect 1 -CommanderScript $(JKS_DIR)/flash.jlink
@echo "Download Completed!"
debug:
@$(JK_DPATH)JLinkGDBServer.exe -select USB -device $(CHIP_TYPE) -if SWD -speed auto -noir -LocalhostOnly
# *** EOF ***
3. __CC_ARM转__GUNC__注意
启动文件及LD文件
通过CubeMx工具生成即可
目录路径表示问题
// __CC_ARM环境
#define DBG_PATH_DIR '\\' // 目录结构
// __GUNC__环境
#define DBG_PATH_DIR '/' // 目录结构
字节对齐及指定位置存储问题
// __CC_ARM环境
__align(32) unsigned char ucaMemPool[MEM_MAX_SIZE]; // 内存池(32字节对齐)
// __GUNC__环境
#pragma pack(32) // 内存池(32字节对齐)
unsigned char ucaMemPool[MEM_MAX_SIZE];
#pragma pack()
// __CC_ARM环境
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ] __attribute__((at(0X10000000)));
// __GUNC__环境
static uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__ ((section(".ccmram")));
/**
其中.ccmram在LD中定义,如果没有则需要自定义
*/
.ccmram :
{
. = ALIGN(4);
_sccmram = .; /* create a global symbol at ccmram start */
*(.ccmram)
*(.ccmram*)
. = ALIGN(4);
_eccmram = .; /* create a global symbol at ccmram end */
} >CCMRAM AT> FLASH
FreeRTOS兼容问题
底层接口RVDS替换为GCC
const功能接口注册问题
// __CC_ARM环境
#define REGISTER_CMD(cmd, handler, desc) \
const char _register_##cmd##_cmd[] = #cmd; \
const char _register_##cmd##_desc[] = #desc; \
CMD_USED cmd_t _register_##cmd SECTION("CMDS") = \
{ \
_register_##cmd##_cmd, \
_register_##cmd##_desc, \
(unsigned int)CMD_HASH, \
(cmd_handler)&handler};
void cmd_get_time(void *param)
{
CALENDAR_T struCal;
if_rtc_get(&struCal);
__printf("%d-%d-%d %d:%d:%d %d\r\n", struCal.year, struCal.month, struCal.day,
struCal.hour, struCal.minute, struCal.second, struCal.week);
}
REGISTER_CMD(get_time, cmd_get_time, get_time);
// __GUNC__环境需要实现功能注册必须建表。
// 屏蔽原先接口
#define REGISTER_CMD(...)
// 新建关联表
cmd_t cmd_table[] =
{
{"set_time", "set_time[ymdhmsw]", 0, cmd_set_time},
{"get_time", "get_time", 0, cmd_get_time},
{"get_sensor", "get_sensor", 0, cmd_get_sensor},
{"set_tp", "set_tp[tp1 tp2]", 0, cmd_set_target},
...
{0, 0, 0, 0},
};
USB_OTG问题
移植是需要删除一下文件:
usbh_msc_fatfs.c
usb_conf_template.h
特殊函数替换
__CC_ARM环境
// THUMB指令不支持汇编内联
// 采用如下方法实现执行汇编指令WFI
__asm void WFI_SET(void)
{
WFI;
}
// 关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{
CPSID I
BX LR
}
// 开启所有中断
__asm void INTX_ENABLE(void)
{
CPSIE I
BX LR
}
// 设置栈顶地址
// addr:栈顶地址
__asm void MSR_MSP(u32 addr)
{
MSR MSP, r0 // set Main Stack value
BX r14
}
__GUNC__环境
/**
* @brief 执行: WFI指令(执行完该指令进入低功耗状态, 等待中断唤醒)
* @param 无
* @retval 无
*/
void sys_wfi_set(void)
{
__ASM volatile("wfi");
}
/**
* @brief 关闭所有中断(但是不包括fault和NMI中断)
* @param 无
* @retval 无
*/
void sys_intx_disable(void)
{
__ASM volatile("cpsid i");
}
/**
* @brief 开启所有中断
* @param 无
* @retval 无
*/
void sys_intx_enable(void)
{
__ASM volatile("cpsie i");
}
/**
* @brief 设置栈顶地址
* @note 左侧的红X, 属于MDK误报, 实际是没问题的
* @param addr: 栈顶地址
* @retval 无
*/
void sys_msr_msp(uint32_t addr)
{
__set_MSP(addr); /* 设置栈顶地址 */
}
IAP相关问题
bootloader工程flash最好也修改限制自身的大小限制
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}
bootloader跳转问题
// __GUNC__环境编译后得到的hex及bin文件无法满足以下条件
if ((tmp & 0x2FFE0000) == 0x20000000) // 检查栈顶地址是否合法.
目前没有找到更好的办法,做注释处理。
u32 tmp = 0;
s8 iap_load_app(u32 appxaddr)
{
// if ((tmp & 0x2FFE0000) == 0x20000000) // 检查栈顶地址是否合法.
{
jump2app = (iapfun) * (vu32 *)(appxaddr + 4); // 用户代码区第二个字为程序开始地址(复位地址)
__set_MSP(appxaddr); /* 设置栈顶地址 */
// MSR_MSP(*(vu32 *)appxaddr); // 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
jump2app(); // 跳转到APP.
}
return 1;
}
application需要修改三处
// 第一处 LD文件
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 960K
}
// 第二处 makefile文件
// 增加USER_VECT_TAB_ADDRESS宏定义
C_DEFS = \
-DUSER_VECT_TAB_ADDRESS \
// 第三处 system_stm32f4xx.c文件
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS SRAM_BASE /*!< Vector Table base address field. \
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. \
This value must be a multiple of 0x200. */
#else
#define VECT_TAB_BASE_ADDRESS FLASH_BASE /*!< Vector Table base address field. \
This value must be a multiple of 0x200. */
#define VECT_TAB_OFFSET 0x00010000U /*!< Vector Table base offset field. \
This value must be a multiple of 0x200. */
#endif /* VECT_TAB_SRAM */
#endif /* USER_VECT_TAB_ADDRESS */
关于下载
下载可以借用sergger - jlink驱动,在makefile文件添加如下:
#######################################
# download .hex/.bin by jlink
#######################################
#Your JLink installation directory
PATH_WINPC = 'C:/Program Files (x86)/SEGGER/JLink/'
#PATH_LINUX = /opt/SEGGER/JLink_V640b/JLinkExe
JK_DPATH = $(PATH_WINPC)
#Jlink script store directory
JKS_DIR = .
#Chip type
CHIP_TYPE = STM32F407VG
flash:
@$(JK_DPATH)JLink.exe -device $(CHIP_TYPE) -if SWD -speed 4000 -autoconnect 1 -CommanderScript $(JKS_DIR)/flash.jlink
@echo "Download Completed!"
debug:
@$(JK_DPATH)JLinkGDBServer.exe -select USB -device $(CHIP_TYPE) -if SWD -speed auto -noir -LocalhostOnly
主要注意两个地方:
1)驱动的安装位置
2)JKS_DIR定义的位置,这个直接索引编译后的hex文件
浮点数打印及格式化问题
makefile文件中去除-specs=nano.specs
# LDFLAGS += -specs=nano.specs
注意:去除后编译大小将增加40K代码空间
关于VSCODE编写代码高亮、索引、宏定义关联问题
在.vscode文件夹下根据需要添加目录索引及相关宏定义即可
4. 关于二次开发
二次开发新建的文件,存放于user对应的目录下即可,无需修改makefile文件。
4. 编译、下载、清除
urien@urien MINGW64 /d/work/prj_sealer/05软件/biolink-m4/source/application/Project (branch_sealer_gcc)
$ make -j20
....
-mfloat-abi=hard -TSTM32F407VGTx_FLASH.ld -lc -lm -lnosys -Wl,-Map=build/update.map,--cref -Wl,--gc-sections -o build/update.elf
arm-none-eabi-size build/update.elf
text data bss dec hex filename
243772 60912 113784 418468 662a4 build/update.elf
arm-none-eabi-objcopy -O ihex build/update.elf build/update.hex
arm-none-eabi-objcopy -O binary -S build/update.elf build/update.bin
urien@urien MINGW64 /d/work/prj_sealer/05软件/biolink-m4/source/application/Project (branch_sealer_gcc)
$
urien@urien MINGW64 /d/work/prj_sealer/05软件/biolink-m4/source/application/Project (branch_sealer_gcc)
$ make flash
...
Script processing completed.
Download Completed!
urien@urien MINGW64 /d/work/prj_sealer/05软件/biolink-m4/source/application/Project (branch_sealer_gcc)
$
urien@urien MINGW64 /d/work/prj_sealer/05软件/biolink-m4/source/application/Project (branch_sealer_gcc)
$ make clean
rm -fR build