2、开发环境搭建:Keil MDK / STM32CubeIDE安装、ARM GCC工具链配置、串口调试工具准备
好,咱们正式开始动手了。
做单片机深度学习推理,说白了就是让一颗Cortex-M内核的芯片去跑神经网络。你想想看,这活儿对工具链的要求其实挺高的——既要能编译C/C++,又要能链接浮点库,还得方便调试。我个人习惯把环境分成三块:IDE(集成开发环境)、编译器工具链、以及串口调试工具。这三样配齐了,后面写代码、调bug才能顺风顺水。
2.1 Keil MDK 安装与配置
Keil MDK,老牌工具了。我在项目中用过很多次,尤其是做STM32F4/F7系列的时候。它的编译器效率高,调试器也好用。
2.1.1 下载与安装
去ARM官网或者Keil官网下载MDK-ARM。注意版本——我个人建议用5.38或更新的版本,对Cortex-M7和M33支持更好。安装时一路Next就行,但有个坑:安装路径不要有中文。我曾经因为路径带了个“项目”二字,结果编译死活报错,查了半天才发现是路径编码问题。
2.1.2 Pack包管理
Keil的Pack包是灵魂。打开Pack Installer,搜索你的芯片型号。比如我用STM32F407,就搜“STM32F4xx_DFP”。下载安装后,才能在Device列表里选到具体型号。
嗯,这里要注意:Pack版本不是越新越好。我遇到过某个新版本Pack改了外设寄存器地址映射,导致老项目跑飞。所以,如果项目稳定,就别轻易升级Pack。
2.1.3 工程模板配置
新建工程时,选好芯片后,会弹出一个Manage Run-Time Environment窗口。这里我一般只勾选:
- CMSIS-CORE:必须的,Cortex-M内核抽象层
- Device-Startup:启动文件,芯片上电第一段代码
- Compiler-I/O:如果你要用printf串口输出,这里选“STDERR”和“STDIN”
其他像USB、文件系统之类的,等用到再勾,别一股脑全选上——编译慢,还容易冲突。
2.2 STM32CubeIDE 安装与配置
如果你喜欢开源、免费,或者做HAL库开发,那STM32CubeIDE是首选。它基于Eclipse,集成了CubeMX图形化配置工具。说白了,你点点鼠标就能生成初始化代码,省去手写寄存器配置的麻烦。
2.2.1 下载与安装
去ST官网下载。注意区分Windows版和Linux版。安装时同样注意路径无中文。我第一次用CubeIDE时,直接默认路径装在了C盘,结果后来项目多了,C盘爆红……建议装到D盘或E盘。
2.2.2 首次启动与工作空间
启动时会让你选Workspace(工作空间)。我习惯把每个大项目单独建一个Workspace,比如“STM32_AI_Project”。这样不同项目的配置不会互相干扰。
进入界面后,点“Help -> Install New Software”,可以装一些插件。不过说实话,做嵌入式深度学习,默认的就够了。别装太多花里胡哨的插件,容易卡。
2.2.3 导入CubeMX工程
CubeIDE可以直接打开.ioc文件。双击.ioc文件,会自动启动图形化配置界面。配置好时钟、外设后,点“Generate Code”,代码就生成了。
这里有个小技巧:生成代码时,把“Generate peripheral initialization as a pair of .c/.h files per peripheral”勾上。这样每个外设单独一个文件,后期维护方便。我刚开始做项目时没勾,所有外设初始化挤在一个main.c里,那叫一个乱……
2.3 ARM GCC 工具链配置
Keil和CubeIDE都自带编译器,但有时候我们需要用ARM GCC。为什么?因为GCC是开源的,而且可以精细控制编译优化选项。比如做量化推理时,我经常用GCC的“-O3 -ffast-math”来压榨性能。
2.3.1 下载ARM GCC
去ARM官网下载“GNU Arm Embedded Toolchain”。选最新稳定版就行。我目前用的是10.3-2021.10版本,稳定且对Cortex-M7支持好。
下载后解压到一个目录,比如:C:\arm-gcc-toolchain。然后把这个目录下的bin文件夹路径加到系统环境变量PATH里。
arm-none-eabi-gcc --version。如果显示版本号,说明配置成功。
2.3.2 在Keil中使用GCC
Keil默认用ARMCC(ARM自家的编译器)。但你可以切换成GCC。方法:
- 打开工程选项(Project -> Options for Target)
- 在“Target”标签页,把“ARM Compiler”改成“Use GCC”
- 在“C/C++”标签页,设置GCC的路径和编译选项
不过说实话,我很少在Keil里用GCC。因为Keil的ARMCC对STM32优化更好。GCC更适合在命令行下用,配合Makefile做自动化构建。
2.3.3 在CubeIDE中配置GCC
CubeIDE默认用的是自带的GCC。如果你想换版本,可以在“Window -> Preferences -> C/C++ -> Build -> Settings”里,找到“Global Tools Paths”,把“GCC ARM”路径改成你自己的。
嗯,这里要注意:不同版本的GCC生成的浮点ABI可能不兼容。比如你用GCC 9编译的库,链接时用GCC 10,可能会报“conflicting CPU architectures”错误。所以,整个项目统一用一个版本的GCC。
2.4 串口调试工具准备
做嵌入式开发,串口就是你的眼睛。没有串口,你都不知道程序跑到哪一步了。我习惯用串口打印调试信息,尤其是打印神经网络的中间层输出——看看激活值是不是正常范围。
2.4.1 常用串口工具
| 工具名称 | 特点 | 推荐指数 |
|---|---|---|
| PuTTY | 轻量、稳定,支持SSH和串口 | ⭐⭐⭐⭐ |
| SecureCRT | 功能强大,支持脚本、日志记录 | ⭐⭐⭐⭐⭐ |
| 串口助手(野火/正点原子) | 国产、免费、界面友好 | ⭐⭐⭐⭐ |
| MobaXterm | 集成串口、SSH、SFTP,功能全面 | ⭐⭐⭐⭐⭐ |
我个人最常用的是MobaXterm。因为它不仅能看串口,还能直接传文件、开SSH隧道。调试时一个窗口搞定所有。
2.4.2 串口参数配置
不管用哪个工具,参数必须和单片机端一致。常见的配置:
- 波特率:115200(常用)或921600(高速调试)
- 数据位:8
- 停止位:1
- 校验位:无
- 流控:无
我曾经犯过一个低级错误:单片机端设的是115200,串口工具设的是9600,结果打印出来全是乱码。查了半小时才发现……所以,先确认波特率一致,这是最基本的。
2.4.3 串口打印重定向
在STM32上,我们通常用printf来打印。但printf默认输出到stdout,需要重定向到串口。方法是在代码里实现fputc函数:
#include <stdio.h>
int fputc(int ch, FILE *f) {
// 假设串口1已经初始化
while (!(USART1->SR & USART_SR_TXE)); // 等待发送缓冲区空
USART1->DR = (uint8_t)ch; // 发送一个字节
return ch;
}
这样,你直接写printf("Hello, AI!\n");,数据就会从串口发出来。
2.5 环境验证:跑一个Hello World
工具都装好了,咱们跑个最简单的程序验证一下。写一个main.c,内容如下:
#include "main.h"
int main(void) {
HAL_Init();
SystemClock_Config(); // 配置系统时钟,比如168MHz
MX_USART1_UART_Init(); // 初始化串口1
printf("STM32 AI Inference Framework Ready!\n");
printf("System Clock: %d MHz\n", HAL_RCC_GetSysClockFreq() / 1000000);
while (1) {
// 空循环,后面会在这里跑神经网络
}
}
编译、下载、打开串口工具。如果看到打印信息,说明环境搭建成功。
嗯,这里要注意:第一次下载时,记得检查BOOT0引脚电平。如果BOOT0拉高,芯片会进入系统存储器模式,你下载的程序不会运行。我刚开始学STM32时就被这个坑过,折腾了一下午。
2.6 小结
环境搭建这一步,说白了就是磨刀。刀磨好了,砍柴才快。Keil和CubeIDE各有优劣,我建议你两个都装——Keil做性能优化,CubeIDE做快速原型。ARM GCC作为备选,当你需要精细控制编译选项时再用。串口工具选一个顺手的,后面调试全靠它。
下一章,咱们开始搭建工程模板,把CMSIS-NN库集成进来。到时候,你就可以在STM32上跑一个真正的神经网络了。