使用xmake配合arm-none-eabi-gcc构建stm32工程
构建编译使用HAL库的STM32程序
环境搭建
xmake-io/xmake下载:
https://github.com/xmake-io/xmake/releases/tag/v2.6.9
arm-none-eabi-gcc 下载:
Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer
https://developer.arm.com/downloads/-/gnu-rm
安装都是一路next下去就可以了。
安装记得勾选添加到环境变量。
xmake入门,构建项目原来可以如此简单
https://zhuanlan.zhihu.com/p/35051214
xmake新增智能代码扫描编译模式,无需手写任何make文件
https://tboox.org/cn/2017/01/07/build-without-makefile/
准备工作
对比MDK开发STM32:
- MDK开发STM32工程必然有个启动文件
(汇编.s)
,没有启动文件无法设置栈跳转到C语言世界 - MDK通过UI界面直观地设置内存分配,加载地址、链接地址等,本质也是MDK根据设置生成
散列文件(.sct)
,在GNU那里这种叫链接文件(.ld)
或链接脚本
如何得到链接文件和启动文件:
- 自己编写,太麻烦。
- 安装完arm-none-eabi工具链后 根目录的
share\gcc-arm-none-eabi\samples
下有链接文件和启动文件的模板 - 从ST提供的固件库中copy
- 通过STM32CubeMx生成STM32工程,选择
Toolchain / IDE的方式为Makefile
,生成的工程就带有启动文件和链接文件
为了方便选择STM32CubeMx 的方式生成工程,还可以方便参照生成的makefile来设置编译链接选项
。
编写xmake的构建文件xmake.lua文件
-- 设置工程名
set_project("stm32-xmake")-- 设置工程版本
set_version("1.0.0")add_rules("mode.debug", "mode.release")-- 自定义工具链
toolchain("arm-none-eabi")-- 标记为独立工具链set_kind("standalone")-- 定义交叉编译工具链地址set_sdkdir("C:\\gcc-arm-none-eabi\\10 2021.10")--set_bindir("C:\\Program Files (x86)\\GNU Arm Embedded Toolchain\\10 2021.10\\bin")
toolchain_end()target("demo")-- 编译为二进制程序set_kind("binary") -- 设置使用的交叉编译工具链set_toolchains("arm-none-eabi") -- 设置平台set_plat("cross")-- 设置架构set_arch("m3")set_filename("demo.elf")add_defines("USE_HAL_DRIVER","STM32F103xE")-- 添加链接库add_links("c", "m", "nosys", "rdimon");-- 添加启动文件add_files("startup_stm32f103xe.s");-- 源文件和头文件路径local src_path = {"./Core/","./Drivers/STM32F1xx_HAL_Driver/",}-- 特殊头文件目录,不方便递归遍历的local inc_path = {"Drivers/CMSIS/Include","Drivers/CMSIS/Device/ST/STM32F1xx/Include"}-- 排除的文件,不参与编译 模板文件可以直接删除remove_files("./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_timebase_tim_template.c")remove_files("./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_timebase_rtc_alarm_template.c")remove_files("./Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_msp_template.c")-- 添加启动文件add_files("startup_stm32f103xe.s");for _, index in ipairs(src_path) do -- 遍历 src_pathfor _, dir in ipairs(os.dirs(index.."/**")) do -- 递归搜索子目录add_files(dir.."/*.c"); add_includedirs(dir);endend-- 添加头文件路径for _, inc in ipairs(inc_path) doadd_includedirs(inc);endif is_mode("debug") then add_cflags("-g", "-gdwarf-2")endadd_cflags("-Og","-mcpu=cortex-m3","-mthumb","-Wall","-fdata-sections","-ffunction-sections","-g -gdwarf-2",{force = true})add_asflags("-Og","-mcpu=cortex-m3","-mthumb","-x assembler-with-cpp","-Wall","-fdata-sections", "-ffunction-sections","-g -gdwarf-2",{force = true})add_ldflags("-Og","-mcpu=cortex-m3","-TSTM32F103ZETx_FLASH.ld","-Wl,--gc-sections","--specs=nosys.specs","-u _printf_float", {force = true})after_build(function(target)cprint("Compile finished!!!")cprint("Next, generate HEX and bin files.")os.exec("arm-none-eabi-objcopy -O ihex ./build/cross/m3/release/demo.elf ./build/demo.hex")os.exec("arm-none-eabi-objcopy -O binary ./build/cross/m3/release/demo.elf ./build/demo.bin")print("Generate hex and bin files ok!!!")print(" ");print("********************储存空间占用情况*****************************")os.exec("arm-none-eabi-size -Ax ./build/cross/m3/release/demo.elf")os.exec("arm-none-eabi-size -Bx ./build/cross/m3/release/demo.elf")os.exec("arm-none-eabi-size -Bd ./build/cross/m3/release/demo.elf")--print("heap-堆, stack-栈, .data-已初始化的变量全局/静态变量, .bss-未初始化的data, .text-代码和常量")--os.run("arm-none-eabi-objdump -D ./build/cross/m3/release/demo.elf > demo.s")end)
add_defines( "USE_HAL_DRIVER", "STM32F103xE")
设置宏,类似MDK以下设置- 终端根目录执行xmake编译
错误解决
arm-none-eabi-gcc 报错 undefined reference to `_exit’解决方案_Pz_mstr的博客-CSDN博客
https://blog.csdn.net/qq_35544379/article/details/104805295
工具链已经设置到环境变量测试已经生效,但在Vscode上的终端还是无法生效的解决办法:
windows 修改环境变量后在 vscode 的终端不生效的解决方法 | 码农家园
https://www.codenong.com/jsf9a5c0fed195/
参考
stm32-xmake: 使用xmake来编译cubemx生成的项目
https://gitee.com/luodeb/stm32-xmake
GNU(gcc-arm-none-eabi)编译stm32代码,重定向printf问题_一个逍遥怪的博客-CSDN博客_gcc printf 重定向
https://blog.csdn.net/qq_42704360/article/details/102853340
使用xmake构建使用标准库的实际项目程序
编写xmake文件
-- 设置工程名
set_project("stm32-xmake")-- 设置工程版本
set_version("1.0.0")add_rules("mode.debug", "mode.release")-- 自定义工具链
toolchain("arm-none-eabi")-- 标记为自定义独立工具链set_kind("standalone")-- 定义交叉编译工具链地址set_sdkdir("C:\\gcc-arm-none-eabi\\10 2021.10")
toolchain_end()target("LED_DRV.elf")-- 编译为二进制程序set_kind("binary") -- 设置使用的交叉编译工具链set_toolchains("arm-none-eabi") -- 设置平台 表示交叉编译程序set_plat("cross")-- 设置架构set_arch("m3")add_defines("USE_STDPERIPH_DRIVER", -- 表示使用标准库"STM32F10X_MD" -- 中容量 根据芯片容量选择)-- 添加链接库add_links("c", "m", "nosys", "rdimon"); -- 链接选项添加 :-lc -lm -lnosys -lrdimon -- 添加启动文件add_files("startup_stm32f10x_md.s");add_cflags("-Og","-mcpu=cortex-m3","-mthumb","-Wall","-fdata-sections","-ffunction-sections","-g -gdwarf-2",{force = true})add_asflags("-Og","-mcpu=cortex-m3","-mthumb",-- "-x assembler-with-cpp","-Wall","-fdata-sections", "-ffunction-sections","-g -gdwarf-2",{force = true})add_ldflags("-Og","-mcpu=cortex-m3","-TSTM32F103C8Tx_FLASH.ld", -- 不同芯片需要修改链接脚本"-Wl,--gc-sections","--specs=nosys.specs","-u _printf_float", {force = true})-- 源文件和头文件路径local src_path = {"USER/","Common/src","./MqEvent/","Lib/Fwlib","Lib/Fwlib/src","./Lib/CMSIS/","USER/app/src","USER/bsp/src"}-- 头文件路径local inc_path = {"./MqEvent/","./Lib/CMSIS/","Lib/Fwlib/inc","Common/inc","USER/app/inc","USER/bsp/inc"}-- 排除的文件,不参与编译remove_files("Common\\src\\meanFilter.c")remove_files("USER\\bsp\\src\\VirtualCOM.c")for _, dir in ipairs(src_path) do -- 遍历 src_pathadd_files(dir.."/*.c"); end-- 添加头文件路径for _, inc in ipairs(inc_path) doadd_includedirs(inc);endif is_mode("debug") then add_cflags("-g", "-gdwarf-2")endafter_build(function(target)cprint("Compile finished!!!")cprint("Next, generate hex and bin files.")os.exec("arm-none-eabi-objcopy -O ihex ./build/cross/m3/release/LED_DRV.elf ./build/LED_DRV.hex")os.exec("arm-none-eabi-objcopy -O binary ./build/cross/m3/release/LED_DRV.elf ./build/LED_DRV.bin")print("Generate hex and bin files ok!!!")print(" ");print("********************储存空间占用情况*****************************")os.exec("arm-none-eabi-size -Ax ./build/cross/m3/release/LED_DRV.elf")os.exec("arm-none-eabi-size -Bx ./build/cross/m3/release/LED_DRV.elf")os.exec("arm-none-eabi-size -Bd ./build/cross/m3/release/LED_DRV.elf")--print("heap-堆, stack-栈, .data-已初始化的变量全局/静态变量, .bss-未初始化的data, .text-代码和常量")-- os.run("arm-none-eabi-objdump.exe -D ./build/cross/m3/release/LED_DRV.elf > LED_DRV.s")end)
在终端中切换到工程根目录执行
xmake
编译,如果使用的是Vscode,可以在编辑器内就可以打开终端,默认就是根路径;如果使用的编辑器无此功能,则可以打开powershell或bash等shell终端编译。
使用Vscode内打开终端编译,在window下实际上打开的也是powershell:
如果是想单独打开powershell编译,一个实用技巧就是在当前目录路径输入powershell回车就会打开一个powershell终端并且已经切换到工程根路径。如果xmake.lua是拷贝另一个工程,编译此工程可能会还是编译上一个工程的程序,这样可能会出问题,这时候可以执行
xmake -P .
,表示强制使用当前目录下的xmake.lua
编译工程。startup_stm32f10x_md.s
从标准库标准库固件包中获取,也可以用STM32CubeMx生成的。STM32F103C8Tx_FLASH.ld
链接脚本使用STM32CubeMx生成的,也可以从标准库固件包中获取。Vscode添加源码头文件路径的技巧:对文件目录树的文件或目录右键选择复制相对路径,就可以快速添加目录。
解决编译错误
1、解决内联汇编错误
C:\Users\opto\AppData\Local\Temp\cc3sKKIq.s:619: Error: registers may not be the same -- `strexb r0,r0,[r1]'
C:\Users\opto\AppData\Local\Temp\cc3sKKIq.s:650: Error: registers may not be the same -- `strexh r0,r0,[r1]'
stack traceback:
参考HAL库头文件Drivers\CMSIS\Core_A\Include\cmsis_gcc.h
, 对core_cm3.c
做以下修改:
uint32_t __STREXB(uint8_t value, uint8_t *addr)
{uint32_t result=0;//__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );__ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) );return(result);
}uint32_t __STREXH(uint16_t value, uint16_t *addr)
{uint32_t result=0;//__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );__ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) );return(result);
}
2、解决 sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk’ 等问题
error: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-sbrkr.o): in function `_sbrk_r':
sbrkr.c:(.text._sbrk_r+0xc): undefined reference to `_sbrk'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-writer.o): in function `_write_r':
writer.c:(.text._write_r+0x14): undefined reference to `_write'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-closer.o): in function `_close_r':
closer.c:(.text._close_r+0xc): undefined reference to `_close'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-fstatr.o): in function `_fstat_r':
fstatr.c:(.text._fstat_r+0xe): undefined reference to `_fstat'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-isattyr.o): in function `_isatty_r':
isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-lseekr.o): in function `_lseek_r':
lseekr.c:(.text._lseek_r+0x14): undefined reference to `_lseek'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-readr.o): in function `_read_r':
readr.c:(.text._read_r+0x14): undefined reference to `_read'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-abort.o): in function `abort':
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-signalr.o): in function `_kill_r':
signalr.c:(.text._kill_r+0xe): undefined reference to `_kill'
c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld.exe: c:/gcc-arm-none-eabi/10 2021.10/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp\libc.a(lib_a-signalr.o): in function `_getpid_r':
signalr.c:(.text._getpid_r+0x0): undefined reference to `_getpid'
collect2.exe: error: ld returned 1 exit status
- 解决:加上链接选项:
--specs=nosys.specs
STM32标准库修改Flash起始地址
修改中断向量
- 修改文件:
Lib\CMSIS\system_stm32f10x.c
:
128 #define VECT_TAB_OFFSET 0xB000 /*!< Vector Table base offset field. 264 #ifdef VECT_TAB_SRAM
265 SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
266 #else
267 SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
268 #endif
- 将
VECT_TAB_OFFSET
从0x0修改为0xB000
- 也可以调用
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0xB000)
; 设置
修改链接地址
修改链接地址也就是修改链接文件
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x800B000, LENGTH = 64K
}
- 将链接地址从
0x8000000
改为0x800B000
修改了地址后要执行xmake clean
清除先前地址编译的obj文件,因为当前obj文件是未修改前的地址生成的obj,直接执行xmake地址还是原来的地址,所以要先清除后再执行xmake
编译。
然后可以通过生成反汇编文件
查看程序链接地址修改是否正常
反汇编:
Disassembly of section .isr_vector:0800b000 <.isr_vector>:800b000: 20005000 andcs r5, r0, r0800b004: 0800c541 stmdaeq r0, {r0, r6, r8, sl, lr, pc}800b008: 0800d4d1 stmdaeq r0, {r0, r4, r6, r7, sl, ip, lr, pc}800b00c: 0800d4d3 stmdaeq r0, {r0, r1, r4, r6, r7, sl, ip, lr, pc}
可以看到中断向量地址已经从0800b000
开始,说明设置成功。
printf实现
1、重定向printf
usart_printf.c:
#include "stm32f1xx_hal.h"
#include "usart.h"int _write(int fd, char *buf, int size)
{for (int i = 0; i < size; i++){while ((USART1->SR & 0X40) == 0); /* wait finised */USART1->DR = (uint8_t)buf[i]; /* send data */}return size;
}
2、自己编写printf
void myprintf(const char *format, ...)
{char str[256] = {0};va_list v_args;va_start(v_args, format);(void)vsnprintf((char *)&str[0],(size_t ) sizeof(str),(char const *) format,v_args);va_end(v_args);usart1Write((char *)str, strlen(str));
}
重定向串口发现bin程序尺寸已经涨了58KB,后经过搜索解决:
- 加入链接选项
--specs=nano.specs
,编译器会使用newlib_nano
库,newlib_nano
应该是类似MDK micro Lib的一个东西,编译完bin文件尺寸已经降到40KB。
测试
除了构建APP工程,还构建了Bootloader工程,测试从Bootloader程序跳转到APP程序都没问题。
总结
- 使用这种方式开发适用于所有Cortex-M的芯片,不必受限于某个芯片的专用IDE,如STM32CubeIDE似乎只能用于STM32?STM32CubeIDE似乎也不太好用。
- 所用涉及的软件全为开源免费的软件。
- 不用编写修改Makefile,构建项目容易。
- 可以使用任意编辑器,可以是Vscode、source insight,甚至是记事本。推荐使用Vscode,Vscode内就可以打开终端执行编译,用其他编辑器可能就要另外打开powershell或bash之类的进行编译了。
使用arm-none-eabi-gcc的缺点:
- 由于MDK armcc工具针对性做了优化,编译出来的代码尺寸相对较小;arm-none-eabi-编译出来的代码尺寸相比armcc编译的偏大的。
使用xmake配合arm-none-eabi-gcc构建stm32工程相关推荐
- VisualGDB+Visual Studio 2019+CubeMX构建STM32工程问题记录(持续更新)
CubeMX Toolchain IDE中没有 Other Toolchains(GPDSC)选项. cubemx在6.6.0以上的时候去掉了这个工具链选项.最后的版本是6.5.0. 使用ST-Lin ...
- ARM架构Docker镜像构建-基础知识
介绍ARM版本的Docker镜像的构建,包括ARM机器上Docker的安装,在ARM机器上构建镜像,及在amd64机器上使用buildx交叉构建arm版本镜像. 前言 现在很多地方都对服务的国产化适配 ...
- Windows下使用MinGw和gcc构建第一个C程序、g++构建第一个C++程序
gcc与g++都gnu的编译器:gcc是c语言的编译器:g++是c++的编译器:gdb 是调试工具. 看着有些面生:都是Linux的东西: MinGw 是 Minimal GNU on Windows ...
- ARM汇编与GCC汇编
ARM汇编与GCC汇编 /** 您忘记正确设置程序集.要解决此问题,请在文件开头发出这些指令: */ .syntax unified .cpu cortex-m3 .fpu softvfp .thum ...
- Centos上使用Jenkins配合Gradle进行Android APK构建和分发
Centos上使用Jenkins配合Gradle进行Android APK构建和分发 很多时候,测试人员和后台人员需要我们将各个环境APK包发给他们进行测试和调试,但是呢,我们不是时时都能响应他们的需 ...
- buntu linux下建立stm32开发环境: GCC安装以及工程Makefile建立
之前在e络盟的意法半导体掏了一个STM32开发板挺好的,却不想在window下开发,也不想用那么占内存的IAR MDK等软件,所以决定在ubuntu下建立该开发环境,像之前avr linux一样,找了 ...
- Ubuntu下使用GCC开发STM32的环境的搭建
注:从ubuntu linux下建立stm32开发环境: GCC安装以及工程Makefile建立转载. 1.STM 32 GCC 安装 stm32 属于arm cortex-m系列thumb指令集,所 ...
- Ubuntu下使用VS Code构建CMake工程
1.下载Visual Studio Code 编译器 可以去Ubuntu自带的应用商店下载,或者使用你命令行下载 2.设置中文显示 直接下载的是英文版本,需要设置成中文显示 先去VS Code自带的商 ...
- 使用vscode + gcc进行 STM32 单片机开发(三)DMA读写SD卡,移植FATFS文件系统
背景 在本系列的前两篇文章( 使用vscode + gcc进行 STM32 单片机开发(一)编译及调试 使用vscode + gcc进行 STM32 单片机开发(二)gcc环境 移植rtthread) ...
最新文章
- google nexus 5 刷机 卡刷 救砖教程
- xman的思维导图快捷键_这个良心好用的思维导图软件,居然不用氪金充钱
- 滥用static_沉思滥用:“强力使用,破坏滥用”
- tukey检测_回到数据分析的未来:Tukey真空度的整洁实现
- 汇编语言ax=0c58ch,第4章89C5汇编语言程序设计.ppt
- 高通计划通过多层级骁龙5G移动平台 加速5G商业化
- Node.js 14 发布,改进了诊断功能
- 《Django实战系列》
- java实现二叉树遍历
- matplotlib—matplotlib绘图中出现□的解决办法
- python中列表的嵌套是指列表的元素是另一个列表_Python实现嵌套列表去重方法示例...
- paip.log4j 日志系统 参数以及最佳实践
- 数字电路基础知识——CMOS门电路 (与非门、或非、非门、OD门、传输门、三态门)
- 阿里云CTO王坚当选院士,高手的人生都是如此雷同:生命的信仰
- 理解复数域上的向量空间
- 基于MATLAB的语音去噪处理系统
- C语言怎么才能让末尾没有多余的空格_C语言干货分享
- 术语FXO和FXS的含义是什么?
- 有声读物探索高速公路和英语的小路
- 仿乐享微信源码分享,微信管家升级版最新版本