一、前言
为什么写这一篇博客呢,主要是大学时期搞单片机两年,手头上有开发板两个,各种小型板好几个,放着浪费。现在工作这么多年,已经对编译、环境、linux等很熟悉了。想着将这个技能重新拾起来,顺便给后代铺条路。
本文是基于linux上使用stm32cubemx生成工程,使用jlink烧写stm32,开发环境是vscode(宇宙第一编辑器),语言C/C++,可能扩展一下使用golang开发更方便。
二、环境搭建
我用的archlinux,不过其他系统都一样。需要安装下面的几个软件。
1. stm32cubemx 图形化配置stm32芯片生成hal库
这个东西官网有linux版,可以直接到官网搜索下载。因为用的是arch,所以直接aur安装就好了
yay -S stm32cubemx
2. arm-none-eabi-gcc 交叉编译工具
这个肯定有linux版,也是直接官网下载就好了。这个也有官方的包,pacman就能下载,不用aur,其他linux应该apt或yum也能安装
# arm-none-eabi-newlib 一些c标准库文件
sudo pacman -S arm-none-eabi-gcc arm-none-eabi-gdb arm-none-eabi-newlib
3. JLinkExe jlink下载工具
为什么是这个不使用openocd,主要是openocd对于jlink的支持不太完整(也可能是我不会用,但是我研究了好久没成功)。我烧写的时候发现如果我配置stm32的时候没有将debug信息配置好jtag,烧写就成了一次性工程,烧完之后再也连不上了。但是使用官方jlink就每这个问题,就算不配置debug也可以强行烧写。
同样的,官网直接下载linux版,我使用aur
yay -S jlink-software-and-documentation
4. 其他软件
看自己需要哈,我装了下面几个
- vscode用来写代码,也可以vim、kate、notepad啥的
- make用来编译使用makefile
- cmake也可以替代make命令使用CMakeLists.txt编译
三、上手开发(先点个灯)
打开stm32cubemx,选芯片配置
我使用的是stm32f103zet6的开发板,所以选择这个芯片
第一步先配置一下时钟晶振,因为开发板默认外置了一个8MHz的晶振,所以我配置一个高速时钟选晶体/陶瓷共振器(crystal/ceramic resonator)
在时钟配置界面选择好HSE和PLLCLK,然后将时钟设置到最大的72MHz回车自动计算前面的参数就配置好了
开发板上面的8个灯对应的是PC0-PC7,那么就回到芯片界面配置一下gpio用来点灯,可以搜索PC0,找到芯片上闪光的那个,单击选择GPIO Output
就可以了。我选了8个引脚都打开。
开始生成代码,为了看懂编译过程和命令,我先使用makefile搞,后面搞懂之后用cmake会更方便
选好后点击右上角的GENERATE CODE
生成代码就好了。找到生成目录,用vscode打开这个目录。
目录结构如上,test.loc是stm32cubemx的工程文件,其他都是代码文件相关,有一个汇编的s文件,一个链接用的ld文件。
改改代码,在main.c
中找到while(1)
,在里面输入点灯的操作,要写在USER CODE BEGIN x
里面,否则重新配置芯片之后会将代码给覆盖了
// Core/Src/main.c
int main(void)
{
...
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_5, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
}
/* USER CODE END 3 */
}
然后打开终端直接make就可以输出一个build/test.bin
文件,可以用来烧写了
注:stm32cubemx的6.12.1版本有bug,报错STM32F103ZETx_FLASH.ld:56: synax error
修改很简单,在这个文件里面按照下面的方式修改
_estack = ORIGIN() + LENGTH(); /* end of RAM */
// 改成
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
...
} > AT> FLASH
// 改成
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
...
} >RAM AT> FLASH // 加上RAM
.bss :
{
...
} >
// 改成
.bss :
{
...
} >RAM // 加上RAM
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
...
} >RAM
// 改成
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
...
} >RAM // 加上RAM
然后再make就不会报错了
四、烧写stm32
1. jlink使用jtag烧写
直接上脚本吧,看着清晰一点
#!/bin/bash
jlink_script="flash.jlink"
rm -f "$jlink_script"
# 生成jlink脚本
# connect 连接设备
# h 暂停cpu
# loadfile "$1" 下载二进制
# r reset
# g 开始运行
# exit 断开连接
cat << EOF > "$jlink_script"
device STM32F103ZE
si JTAG
speed 4000
jtagconf -1,-1
connect
h
loadfile "$1"
r
g
exit
EOF
JLinkExe -commanderscript "$jlink_script"
使用JLinkExe执行脚本进行烧录,命令行只需要执行命令bash flash.sh build/test.bin
就可以烧到单片机里面,然后就能看到效果了
五、调试stm32
1. jlink使用jtag调试
想要调试需要在stm32cubemx上选好调试的方式,把引脚配置好,否则会调试不起来。这里使用jtag-5调试
然后在vscode里面安装一个插件Cortex-Debug
,之后在生成一个launch.json,选择Cortex Debug
需要加一些东西的改动,配置gdb路径,二进制路径,设备型号,调试方式等
F5开始调试就好了