LLVM-embedded-toolchain-for-Arm 是一个 ARM 公司开源的适用于 32 位ARM芯片的工具链,支持多种ARM指令集架构,包括最新的 CM85 内核。由于是基于 LLVM 和 picolibc构建出的工具链,因此在代码体积和执行效率上都很有竞争力,甚至可以和商用闭源的工具链进行 PK。
支持的架构
Armv6-M
Armv7-M
Armv7E-M
Armv8-M Mainline
Armv8.1-M Mainline
Armv4T (experimental)
Armv5TE (experimental)
Armv6 (experimental, using the Armv5TE library variant)
AArch64 armv8.0 (experimental)
这篇文章教大家,如何在 RT-Thread 上,使用最新发布的 LLVM-embedded-toolchain-for-Arm-17.0.1 版本开发stm32,以星火1号为例。
适配LLVM工具链
由于RT-Thread内核和构建工具已经支持了这款工具链,因此只需要修改我们当前使用的BSP即可。
主要工作就是修改rtconfig.py 添加llvm-arm的编译参数
由于目前RT-Thread主仓库已经有两个BSP支持了这个工具链,我们可以参考现有的。
打开星火1号对应的BSP,目录为:bsp/stm32/stm32f407-rt-spark。然后使用文本编辑工具(如:VSCode)打开rtconfig.py文件。
1.在CROSS_TOOL配置的地方添加 llvm-arm 相关信息:
cross_tool provides the cross compiler
EXEC_PATH is the compiler execute path, for example, CodeSourcery, Keil MDK, IAR
if CROSS_TOOL == 'gcc':
PLATFORM = 'gcc'
EXEC_PATH = r'C:UsersXXYYZZ'
elif CROSS_TOOL == 'keil':
PLATFORM = 'armcc'
EXEC_PATH = r'C:/Keil_v5'
elif CROSS_TOOL == 'iar':
PLATFORM = 'iccarm'
EXEC_PATH = r'C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.3'
elif CROSS_TOOL == 'llvm-arm': # 新添加的部分
PLATFORM = 'llvm-arm'
EXEC_PATH = r'D:ProgremLLVMEmbeddedToolchainForArm-17.0.1-Windows-x86_64bin'
2.完善具体的编译参数
if PLATFORM == 'gcc':
toolchains ...
elif PLATFORM == 'armcc':
toolchains ...
elif PLATFORM == 'armclang':
toolchains ...
elif PLATFORM == 'iccarm':
toolchains ...
elif PLATFORM == 'llvm-arm': # 新添加的部分
toolchains
PREFIX = 'llvm-'
CC = 'clang'
AS = 'clang'
AR = PREFIX + 'ar'
CXX = 'clang++'
LINK = 'clang'
TARGET_EXT = 'elf'
SIZE = PREFIX + 'size'
OBJDUMP = PREFIX + 'objdump'
OBJCPY = PREFIX + 'objcopy'
DEVICE = ' --target=arm-none-eabihf -mfloat-abi=hard -march=armv7em -mfpu=fpv4-sp-d16'
DEVICE += ' -ffunction-sections -fdata-sections -fno-exceptions -fno-rtti'
CFLAGS = DEVICE
AFLAGS = ' -c' + DEVICE + ' -Wa,-mimplicit-it=thumb ' ## -x assembler-with-cpp
LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rt-thread.map,-u,Reset_Handler -lcrt0 -T board/linker_scripts/link.lds'
CPATH = ''
LPATH = ''
if BUILD == 'debug':
CFLAGS += ' -O0 -gdwarf-2 -g'
AFLAGS += ' -gdwarf-2'
else:
CFLAGS += ' -O2'
CXXFLAGS = CFLAGS
POST_ACTION = OBJCPY + ' -O binary **TARGET rtthread.binn' + SIZE + ' **TARGET n'
编译工程
使用 env 工具打开当前 bsp,设定要使用的工具链和对应的路径。
set RTT_CC=llvm-arm
set RTT_EXEC_PATH=D:ProgremLLVMEmbeddedToolchainForArm-17.0.1-Windows-x86_64bin
然后运行 scons 命令,执行编译
scons
发现编译报错了,看起来是原来的链接脚本不太规范,llvm检测比较严格。
我们打开对应的文件,在 = 后面加一个空格,再次编译。
又出现了一个错误。
这次是提示 .eh_frame 和 .data 两个段的地址发生了冲突。对比了下stm32l475-atk-pandora 和星火1号bsp的链接脚本文件。
发现星火1号的链接脚本缺少了.eh_frame 段的定义。
我们添加是缺少的定义,继续编译。编译成功!
然后拖入到星火1号的 U 盘,咦!没下载成功,提示下载失败了。。。
然后,尝试了下使用gcc编译出来的bin文件,咦!下载成功了。这说明我们LLVM的工具链编译出来的文件缺少有问题!
使用比较工具,比较这两个bin文件,一打开就发现了不对劲的地方。LLVM编译出来的bin文件,前面缺少了一块。
仔细一看,这不是前面的中断向量表吗,原来是LLVM编译的工具少了这一部分,这样就好办了,问题肯定出来启动文件这里。看了下控制启动文件是否参与编译的脚本,发现,确实缺少了针对llvm-arm这个工具链的处理。
添加上之后,继续编译,成功了,果然固件大小也变大了很大,达到了和gcc一样的量级。
这次下载成功了,而且程序也正常的运行起来了!
代码优化对比
比较一下代码体积(text段大小)
设计资源 培训 开发板 精华推荐
- LTC3119HFE 5V、500kHz 宽输入稳压器的典型应用电路
- R_154_V10基于IPS2电机换向传感器的设计
- 用于完整 3V、12 位、1MHz 模数转换系统的 AD8604ARZ-REEL7 运算放大器的典型应用
- ESP32便携点焊机
- 萝丽接收电调一体机(6CH+9110)
- LT3973IMSE-3.3 2.5V 降压转换器的典型应用
- 消费电子 MCU 开发系统
- DC678A,用于 LT5517EUF、40MHz 至 900MHz 直接转换正交解调器的演示板
- TAR5SB35 点稳压器(低压降稳压器)的典型应用
- ADR445B 5 Vout 超低噪声、LDO XFET 电压基准的典型应用,带电流吸收器和电流源