note/stm32-dev-env

STM32 开发环境

ARM 开发总是有着太多的工具可以选择。因为种种原因,这里不涉及 IAR、KEIL MDK 等商业开发工具。

代码工具

GCC

主要的工具链有:arm-none-eabi-gcc, arm-none-eabi-binutils, arm-none-eabi-newlib, arm-none-eabi-gdb

由于 ARM 的诸多坑,一开始就直接使用 GCC 可能会有些棘手。主要的坑有这些:

  • Linker script。不使用 linker script 的话 GCC 会这样报错:

    ld: libg.a(lib_a-exit.o): in function `exit'
    exit.c:(.text.exit+0x16): undefined reference to `_exit‘

    如果你这样搜索,搜索引擎也许会告诉你加个 --specs=nosys.specs 参数。这样的确可以链接了,但是链接后的程序将巨大无比。一个只有一个死循环的程序可能就要用去 67kB 的 flash。

  • 库。要给 STM32 编程,你有很多库可以选择。ARM 的 CMSIS 库、ST 的 HAL 库、ST 的 Peripheral 库。

    不像 AVR,GNU 没有提供 ARM 的 Libc。同时因为 ARM 的复杂性,不使用抽象库来对 STM32 编程会非常困难。

你会遇到这几种文件:

  • .elf :编译和链接后的文件,包含了变量名和程序内容。可用于调试。使用 arm-none-eabi-objcopy 转化为 .bin.hex 文件。
  • .hex:Intel HEX 文件,不包含变量名,包含程序和地址。可用于烧写。由于文件已经包含地址的信息,烧写至 STM32 时不用指定起始地址。
  • .bin:二进制文件,只包含程序,可用于烧写。文件没有包含地址的信息,所以烧写时要指定起始地址。

STM32CubeMX

STM32CubeMX 可用于生成工程初始代码,可在 ST 官网获取邮件下载。这些代码包括 ST 的 HAL 库和 CMSIS,也可生成许多商业工具的工程文件。通过设置还可以生成 LL 库,不过这仅限 L1, L4, F2, F4, F7 系列

https://www.st.com/en/development-tools/stm32cubemx.html

现在的版本已经支持生成可用于 gcc 的 Makefile 和 linker script,新建工程后选择 Project Manager > Project > Toolchain / IDE 选择 Makefile 就可以了。

Screenshot_20190710_111046.png

~/STM32Cube/Repository/STM32Cube_FW_F1_V1.7.0/Projects/STM32F103RB-Nucleo/Examples (类似于这样的)路径下可以找到实例程序。

STM32CubeIDE

STM32CubeIDE 是 ST 推出的免费的 STM32 集成开发环境,支持 Linux, Mac, Windows。可在 ST 官网输入个人信息,获取邮件后下载。

https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-ides/stm32cubeide.html

AUR 上也有这个包。不过需要注意,由于授权是私有的,其他人不能再分发 STM32CubeIDE。所以从 AUR 安装时,你需要手动从 ST 网站上下载下来,放在你克隆下来的 AUR 仓库路径下(如果你使用 yay 就是 ~/.cache/yay/stm32cubeide/),然后再运行 makepkg -sci

CMSIS

早期的 ARM 各式各样,彼此之间互不兼容。为了统一乱象,ARM 开发了 CMSIS 库标准。CMSIS 同时也指 ARM 开发的一个满足 CMSIS 标准的库,比较底层。

HAL

ST 的库,基于 CMSIS,可用 STM32CubeMX 生成。头文件名类似于 stm32f1xx_hal.h stm32f1xx_hal_flash.h 这样。使用 STM32CubeMX 生成的话它的路径是 Drivers/STM32F1xx_HAL_Driver

除了官方文档(如 UM1850)外这个库的资料较少。如果你使用 STM32CubeMX 的话,在 ~/STM32Cube/Repository/STM32Cube_FW_F1_V1.7.0/Projects/STM32F103RB-Nucleo/Examples (类似于这样的)路径下可以找到实例程序。

标准外设库 / Standard Peripherals Library / SPL

ST 的库,基于 CMSIS。头文件名类似于 stm32f10x.h stm32f10x_flash.h 这样。现已被 ST 抛弃,取而代之的是 Low Layer Library。(然而大多数 STM32 中文书籍使用的仍是 SPL 😂)

Low Layer Library / LL

ST 的库,基于 CMSIS,可用 STM32CubeMX 生成。在 Advanced Settings 中将 HAL 改为 LL 就可以了,不过这仅限 L1, L4, F2, F4, F7 系列。其他系列就需要手动下载库了。

调试器 / Dongle

调试协议有两种:JTAG 和 SWD。JTAG 支持调试和边界扫描,而 SWD 只支持调试。

调试器分很多类,基于 J-LINK 的、基于 CMSIS-DAP 的、基于 ST-LINK 的。

调试协议指的是 dongle 和芯片连接的协议。虽然上面提及的几类 dongle 都实现了同样的 JTAG 或 SWD 调试协议,但是这几类 dongle 与计算机通讯的方式却完全不同。他们需要不同的驱动和不同的调试软件支持。

J-LINK 是 SEGGER 的私有技术。由于 J-LINK 技术发展得早,SEGGER 凭借 J-LINK 技术已经形成了垄断,基于 J-LINK 的调试器价格不菲。

J-LINK 有 v8, v9, v10 之分。v8 采用的是 AT91SAM7S64 作为主控芯片,据说很容易掉固件;v9 采用的是 STM32F205RC 作为主控芯片,没有了上一代容易掉固件的缺点;v10 采用的是 NXP 的 LPC4322 作为主控芯片,速度较上一代有很大的提升。

SEGGER 的 J-LINK 还分 Base, Edu 版本。Edu 和 Base 没有显著的差别,价格相对便宜许多,但不允许商业使用。Base 的价格在 2000 元左右,Edu 的价格在 500 元左右。

当然使用 J-LINK 自然有这样做的好处。由于垄断、使用的人更多,J-LINK 在多数 ARM 开发和调试平台上都是被列为主要支持对象的,如 KEIL MDK, OpenOCD。

淘宝上售卖的 J-LINK 多为盗版(或者称作兼容版?Clone?),盗版 v8 的价格在 40 元左右,v9 的价格在 100 元左右,v10 的价格在 280 元左右。这些 clone 要么采用官方的外壳(但没有 Base, Pro, Edu 等标识),要么采用的是一个黑色的写着 “ARM 仿真器” 字样的外壳。

还有个版本称作 J-LINK OB,这个版本阉割掉了 JTAG 接口,只保留 SWD 协议。这个版本在驱动以及调试软件支持上都和其他版本无异,只是要记得选择使用 SWD 接口。

基于 CMSIS-DAP 的

和库的乱象一样,为了统一调试器的乱象、避免厂商重复造轮子,ARM 开发了 CMSIS-DAP 协议,并且基于 CMSIS-DAP 开发了 DAPLink 调试器固件。与 J-LINK 不同,这项技术是开源的。

使用 DAPLink 固件的调试器有个显著的优点:不需要驱动(Windows 10, macOS, Linux)。连接上计算机后它将被识别为一个储存装置,只需要将文件写入那个装置就可以进行烧录(所谓 “拖拽烧录”)。

市面上的 DAPLink 常常会标 “迷你版” 或 “高速版” 这样的字样。“迷你版” 通常采用的是闪存较小的芯片,无法支持 DAPLink 的全部功能,不是阉割掉了 JTAG 就是阉割掉了 “拖拽烧录”。而高速版的外观常常和 J-LINK 相似,是一个 “黑色砖头”。高速版采用闪存更大的芯片,可以保留全部 DAPLink 的功能,并且常常会有 J-LINK 那样的更完善的外围电路。

ST-LINK 只支持 ST 的芯片。ST-LINK, ST-LINK/V2 和 ST-LINK-V3 的协议是不同的,需要完全不同的驱动。官方的 ST-LINK/V2 长这样:

official st-link/v2

市场上还有着许多 U 盘大小的铝壳的廉价的 ST-LINK/V2 兼容版,它们常常是一颗 STM32F103C8T6,几乎没有外围电路,没有 JTAG 接口。它们采用的固件和官方的一致,所以如果只使用 SWD 的话使用起来应该也是没有问题的。

不过我买到了几个主控为 CS32F103C8T6 的铝壳 ST-LINK/V2,使用 ST 官方提供的烧录工具没有问题,但无法用于 texane/stlink 烧录,也无法用于 OpenOCD 调试。报错不认识这个 idcodecoreid详见这里。

Black Magic Probe / BMP

https://github.com/blacksphere/blackmagic/wiki/

一个开源的调试解决方案。最大的特点是内置 GDB server,连接上电脑后会被识别为一个串口设备。这样只需在 GDB 中 target extended-remote /dev/ttyACM0 就可以开始调试了。不需要再用其他软件与 dongle 通讯,作为 GDB 和 dongle 之间的中间层才能调试,少了很多麻烦。

OpenOCD 只支持 ULINK v1,不支持 ULINK v2。

调试 / 烧写工具

OpenOCD

这是比较主流的开源调试方案了。OpenOCD 本质上是一个 TCL 语言的执行环境,并且内置了很多用于调试的脚本。这些脚本在 /usr/share/openocd/scripts/ 下。

要启动 OpenOCD,你需要写一个初始化的脚本 openocd.cfg。在这个脚本中你需要用 source 引用 /usr/share/openocd/scripts/ 下的脚本,来指定你的调试器和目标芯片。比如我用 J-LINK 来调试 STM32F103C8

source [find interface/jlink.cfg]
source [find target/stm32f1x.cfg]

Linux 下使用 JLink 与 OpenOCD 配合嵌入式开发

然后在当前路径运行 openocd,这时 OpenOCD 会开启 localhost:4444 端口,使用 telnet localhost 4444 连接上即可进入交互模式。交互模式下使用 OpenOCD 内置的一些 TCL 指令来调试。

下载程序:

> program blinky.bin 0x8000000 verify reset

我买到了几个主控为 CS32F103C8T6 的铝壳 ST-LINK/V2,无法用于 OpenOCD 调试。报错不认识这个 idcode

Warn : UNEXPECTED idcode: 0x2ba01477
Error: expected 1 of 1: 0x1ba01477

有人说可以在 openocd.cfg 中加一句 set CPUTAPID 0x2ba01477,就像这样:

source [find interface/stlink-v2.cfg]
set CPUTAPID 0x2ba01477
source [find target/stm32f1x.cfg]

这样是可以启动了,但是用 telnet 连上后:

> program blinky.bin 0x8000000 verify reset
timed out while waiting for target halted
TARGET: STM32F103C8Tx.cpu - Not halted
in procedure 'program' 
in procedure 'reset' called at file "embedded:startup.tcl", line 500
in procedure 'ocd_bouncer'

embedded:startup.tcl:476: Error: ** Unable to reset target **
in procedure 'program' 
in procedure 'program_error' called at file "embedded:startup.tcl", line 501
at file "embedded:startup.tcl", line 476
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000144 msp: 0x20000400

https://github.com/texane/stlink/

如果你用的下载器是 STLINK 的话,可以用这个工具来下载或调试程序。

下载程序:

$ st-flash write blinky.bin 0x8000000

最后一项是地址,ARM Cortrex-M 的 flash 地址开头是 0x8000000,别忘了。

调试的话是使用 st-util 建立一个 GDB server,然后用 gdb 连上进行调试。

使用盗版 ST-LINK 可能会报错不认识这个 coreid,我目前还没有找到解决方法。

下载地址: STSW-LINK004

上面说的我买到的山寨 ST-LINK 无法用于 texane/st-link 和 OpenOCD,但它们可以用于这个烧写工具。这是 ST 官方的一个 Windows 程序。

STM32CubeProgrammer

https://www.st.com/en/development-tools/stm32cubeprog.html

也是 ST 官方的烧写工具,同样需要邮件验证才能下载。这个工具支持我买到的山寨 ST-LINK,可在 Linux, Windows, macOS 上运行。

Linux 下它依赖于 openjdkopenjfx。我的 OpenJDK 版本是 8,不知道其他版本会不会出问题。

压缩包中的 SetupSTM32CubeProgrammer-x.x.x.linux 即为用于 Linux 的安装向导,可以更改安装路径,默认会安装在你的 $HOME 中,这样就不会弄乱你的根目录。安装向导最后在 ~/.local/share/applications创建的快捷方式拉的屎有点乱。我们删除掉 *.txt.desktop,然后编辑 STM32CubeProgrammer.desktop,删除掉这两行:

Terminal=
TerminalOptions=

这样在开始菜单中启动时就不会显示终端了。

VSCode 插件 Cortex-Debug

支持多种调试工具,包括 stutil, OpenOCD, Black Magic Probe 等。

https://hbfsrobotics.com/blog/configuring-vs-code-arm-development-stm32cubemx

其他解决方案

Mbed 生态

Mbed 是 ARM 主导的开源的嵌入式 OS 以及软件生态。Mbed 官网上有在线的编译器,注册之后就可以用了。这是它的官方文档。

除了 Online Complier 以外,还可以使用 Mbed 提供的 mbed-cli,一个用 Python 写的编译工具。

不过好像还得买他家的开发板?

stm32-rs

用 Rust 写 STM32 的程序。

https://github.com/stm32-rs/stm32-rs

STM32duino

为 Arduino IDE 添加 STM32 支持。库的使用与 Arduino 库类似。

About Me