2. 开发环境搭建:MDK/STM32CubeIDE安装、CMSIS-NN软件包获取、工程模板创建

好,咱们正式开始动手。这一章说白了就是“把家伙事儿备齐”。我见过不少新手,兴致勃勃想跑神经网络,结果卡在环境配置上大半天,最后连个LED都没点着。咱们别走弯路,一步到位。

2.1 选择你的武器:MDK 还是 STM32CubeIDE?

先聊个实在问题:用哪个IDE?我个人习惯是两套都备着,但根据项目场景选主工具。下面这张表能帮你快速决策:

对比项 MDK (Keil μVision) STM32CubeIDE
编译器 ARM Compiler 6 (基于Clang) GCC for ARM
调试器 ULINK / J-Link 支持好 ST-Link 原生集成
CMSIS-NN 优化 ARM Compiler 6 对 CMSIS-NN 内联汇编支持极佳 GCC 下部分内联汇编需手动调整
许可证 商用收费(32KB代码限制免费版) 完全免费
上手难度 传统,资料多 Eclipse风格,现代
我的建议: 如果你刚入门,用 STM32CubeIDE 起步,零成本、开箱即用。等做到性能调优阶段,再切到 MDK + ARM Compiler 6,你会发现推理速度能再快个 10%-15%。我在一个口罩检测项目里实测过,同样代码,MDK 编译出来的二进制比 GCC 小 8%,推理帧率高了 12%。

2.2 安装与验证:别光点“下一步”

2.2.1 MDK 安装要点

  1. 下载:去 Keil 官网下最新版 MDK-Arm。别下成旧版,CMSIS-NN 5.9.0 以上才完整支持。
  2. 安装路径:我个人习惯装到 C:\Keil_v5,别带中文和空格。
  3. Pack Installer:装完后打开,搜索你的芯片型号。比如 STM32F407,点 Install。这里有个坑——一定要装 CMSIS 包,版本选 5.9.0 或更高。
  4. 验证:新建一个空工程,编译通过就算成了。
我曾经踩过的坑: 装完 MDK 后直接打开旧工程,结果编译器报错说找不到 arm_math.h。后来发现是 CMSIS 包版本太老,CMSIS-NN 的头文件路径没被包含。解决办法:在 Pack Installer 里把 CMSIS 更新到最新,然后在工程选项的 C/C++ Include Paths 里手动加上 CMSIS\NN\Include。

2.2.2 STM32CubeIDE 安装要点

  1. 下载:ST官网,选对应操作系统版本。注意区分安装版和绿色版,我推荐安装版,省心。
  2. 首次启动:会提示选工作空间(Workspace)。路径同样不要中文。
  3. 安装固件包:在 Help → Manage Embedded Software Packages 里,找到你的 MCU 系列,比如 STM32F4,点 Install。这一步会下载 HAL 库和 CMSIS 包。
  4. 验证:新建一个 STM32 工程,选芯片,生成代码,编译通过。

2.3 获取 CMSIS-NN 软件包

CMSIS-NN 不是单独下载的,它藏在 CMSIS 这个大包里。你想想看,ARM 把 DSP、NN、Core 这些库都打包在一起了。获取方式有三种:

  • 方式一(推荐):通过 IDE 的 Pack Manager 直接装。MDK 的 Pack Installer 里搜 CMSIS,选 5.9.0+;STM32CubeIDE 的固件包管理器里自带。
  • 方式二:去 GitHub 上搜 ARM-software/CMSIS_5,下载 Releases 里的 zip。解压后把 CMSIS\NN 文件夹拷出来。
  • 方式三:如果你用 STM32CubeMX 生成工程,在 Middleware 里勾选 CMSIS,会自动包含 NN 库。
关键文件清单: 拿到 CMSIS-NN 包后,确认以下文件存在:
  • Include/arm_nnfunctions.h —— 主头文件
  • Include/arm_nnsupportfunctions.h —— 辅助函数
  • Source/ 下的所有 .c 文件 —— 实现代码
缺一不可,否则编译会报 undefined reference。

2.4 工程模板创建:从零搭一个 CMSIS-NN 项目

这一步我手把手带你走一遍。咱们以 STM32F407 + STM32CubeIDE 为例,MDK 的步骤大同小异。

2.4.1 新建基础工程

  1. 打开 STM32CubeIDE,File → New → STM32 Project。
  2. 选芯片:STM32F407VGT6,Next。
  3. 工程名:cmsis_nn_template,Finish。
  4. 初始化代码生成后,你会看到一堆 .c 和 .h 文件。别慌,这是 HAL 库的骨架。

2.4.2 添加 CMSIS-NN 源码

嗯,这里要注意:CMSIS-NN 的源码需要手动添加到工程里,IDE 不会自动帮你做。

  1. 在工程根目录下新建文件夹:Middlewares/CMSIS/NN。
  2. 把 CMSIS/NN/Include 和 CMSIS/NN/Source 拷进去。
  3. 在 IDE 里右键工程 → Properties → C/C++ General → Paths and Symbols。
  4. 在 Includes 标签页,Add 路径:Middlewares/CMSIS/NN/Include。
  5. 在 Source Location 标签页,Link Folder,选 Middlewares/CMSIS/NN/Source。
小技巧: 如果你嫌手动添加 Source 文件麻烦,可以直接在工程目录下建一个 CMSIS 文件夹,把整个 CMSIS 包(包括 Core、DSP、NN)都放进去。然后在工程设置里一次性 Include 所有路径。我自己的模板就是这么干的,换芯片时只需要改芯片型号,CMSIS 路径不用动。

2.4.3 配置编译器选项

这一步容易忘,但忘了就编译不过。打开工程设置:

  • C/C++ Build → Settings → Tool Settings → MCU GCC Compiler → Optimization:选 -O2 或 -O3。CMSIS-NN 在优化开启下才能发挥性能。
  • MCU GCC Compiler → Preprocessor:添加宏定义 ARM_MATH_CM4(根据你的内核选,CM7 就写 ARM_MATH_CM7)。这个宏告诉 CMSIS-DSP 库你的芯片内核版本。
  • MCU GCC Linker → Miscellaneous:勾选 Use float with printf (-u _printf_float),方便调试时打印浮点结果。

2.4.4 写一个测试函数

模板搭好了,总得跑一下验证吧?在 main.c 里加一段最简单的卷积测试:

#include "arm_nnfunctions.h"
#include "arm_math.h"

// 定义一个简单的 3x3 卷积核,输入 5x5,输出 3x3
#define INPUT_CH  1
#define OUTPUT_CH 1
#define KERNEL_DIM 3
#define INPUT_DIM  5
#define OUTPUT_DIM 3

q7_t input[INPUT_CH * INPUT_DIM * INPUT_DIM];
q7_t kernel[OUTPUT_CH * INPUT_CH * KERNEL_DIM * KERNEL_DIM];
q7_t bias[OUTPUT_CH];
q7_t output[OUTPUT_CH * OUTPUT_DIM * OUTPUT_DIM];

int main(void)
{
    // 初始化数据(略,实际可填随机数)
    // 调用 CMSIS-NN 的卷积函数
    arm_convolve_HWC_q7_basic(input, INPUT_DIM, INPUT_CH,
                              kernel, OUTPUT_CH, KERNEL_DIM,
                              bias, 0, 0,
                              output, 0, 0,
                              OUTPUT_DIM, 0, NULL);

    while(1);
}

编译,下载到板子,用调试器看 output 数组的值。如果非零,恭喜你,环境搭好了!

2.5 知识体系总览

下面这张图帮你理清本章的核心逻辑:从 IDE 选择到工程跑通,每一步的依赖关系。

开发环境搭建知识体系 MDK (Keil) STM32CubeIDE 其他 (IAR等) Pack Installer 固件包管理器 手动下载CMSIS CMSIS-NN 软件包获取 工程模板创建:新建工程 → 添加源码 → 配置编译器 → 测试验证 编译通过 + 调试输出正常 核心原则:IDE选顺手 → 装对Pack → 加对路径 → 开优化 → 跑通测试

2.6 常见问题与避坑

  • 编译报错:arm_math.h 找不到 —— 检查 CMSIS 包是否安装,Include 路径是否添加了 CMSIS/DSP/Include。
  • 链接报错:undefined reference to arm_convolve_HWC_q7_basic —— 确认 NN 的 Source 文件已添加到工程,并且被编译了。在 STM32CubeIDE 里,有时需要手动把 .c 文件拖到 src 文件夹下。
  • 运行死机 —— 检查堆栈大小。CMSIS-NN 的临时缓冲区可能很大,在启动文件里把堆设到 0x2000 以上。
  • 性能不如预期 —— 确认优化等级开了 -O2 或 -O3,并且定义了正确的 ARM_MATH_CMx 宏。
我曾经遇到的诡异问题: 有一次在 STM32CubeIDE 里编译通过,下载后程序跑飞。查了两天,最后发现是 CMSIS-NN 的 Source 文件被 IDE 的“排除构建”选项给勾掉了。右键每个 .c 文件 → Resource Configuration → Exclude from Build,确保没打勾。这种低级错误,犯一次就长记性了。