3. 开发环境搭建:MDK/AC6安装、CMSIS-Pack配置、CMSIS-NN源码获取、第一个示例工程编译
做嵌入式AI开发,环境搭建是第一道坎。很多人觉得装个IDE有什么难的?但我在带团队时发现,80%的编译问题都出在环境配置上——要么Pack版本不对,要么编译器路径没指对。这一章,咱们就把这些坑一个个填平。
3.1 开发工具链概览
先看看我们这一章要搭什么。说白了,就是三样东西:
- IDE:MDK(Keil uVision)——ARM Cortex-M的事实标准
- 编译器:AC6(Arm Compiler 6)——MDK内置,基于LLVM,优化能力强
- 软件包:CMSIS-Pack + CMSIS-NN源码——ARM官方的神经网络加速库
下面这张图,把整个环境的结构和流程画清楚了:
嗯,这张图你看懂了,整个环境就清晰了。MDK负责管理工程,AC6负责编译,CMSIS-Pack提供底层支持,CMSIS-NN才是我们真正要调优的对象。
3.2 MDK与AC6安装
3.2.1 获取安装包
去Keil官网下载MDK-ARM最新版。我个人习惯用5.38或更高版本,因为内置的AC6版本比较新,对CMSIS-NN的优化支持更好。
3.2.2 安装步骤
- 双击安装包,一路Next。注意安装路径不要有中文和空格。
- 选择组件时,确保勾选「Arm Compiler 6」。我记得有次帮同事排查问题,发现他编译报错,就是因为没装AC6,用的还是老旧的AC5。
- License管理:安装完成后打开uVision,菜单栏 File → License Management,添加你的License。
- 验证安装:新建一个空工程,在Project → Manage → Project Components中,确认编译器显示为「Arm Compiler 6.x」。
3.3 CMSIS-Pack配置
CMSIS-Pack是ARM官方提供的软件包管理机制。说白了,就是帮你把CMSIS-Core、CMSIS-DSP、CMSIS-NN这些组件一键装好,不用自己手动去GitHub扒拉源码。
3.3.1 安装Pack
有两种方式:
| 方式 | 操作 | 适用场景 |
|---|---|---|
| 在线安装 | uVision → Pack Installer → 搜索「ARM::CMSIS」→ Install | 网络通畅,推荐 |
| 离线安装 | 从Keil官网下载 .pack 文件 → 双击安装 | 内网开发,或需要固定版本 |
我建议用离线安装。为什么?因为在线安装经常因为网络问题中断,而且版本会跟着官网更新——你今天装的5.9.0,下周可能就变成6.0.0了,团队里版本不一致,代码一同步就炸。
3.3.2 确认Pack版本
安装完成后,在uVision的Project → Manage → Pack Installer中,你应该能看到类似这样的信息:
ARM::CMSIS 5.9.0
├── CMSIS-Core 5.9.0
├── CMSIS-DSP 1.14.0
└── CMSIS-NN 4.1.0
arm_convolve_s8的参数结构变了,编译不报错,但运行结果全错。
3.4 CMSIS-NN源码获取
Pack安装后,CMSIS-NN的源码其实已经在你电脑里了。默认路径是:
C:\Users\你的用户名\AppData\Local\Arm\Packs\ARM\CMSIS\5.9.0\CMSIS\NN
但这个路径藏得深,而且每次更新Pack版本,路径都会变。我个人习惯把源码复制一份到工程目录下,这样版本可控,也方便修改调试。
3.4.1 源码结构
我们看看CMSIS-NN源码里都有什么:
| 目录/文件 | 说明 |
|---|---|
Include/ |
头文件,定义API接口和数据结构 |
Source/ |
算子实现,按功能分文件夹(Convolution、Pooling、Activation等) |
Source/Softmax/ |
Softmax算子的各种实现(纯C、带DSP指令、带MVE指令) |
Source/NNSupportFunctions/ |
辅助函数,比如数据重排、量化转换 |
你想想看,这么多文件,我们真正要优化的其实就Source/下面那几个核心算子。后面的章节,我们会一个一个拆开来看。
3.5 第一个示例工程编译
理论说完了,咱们动手。我准备了一个最小工程,就做一件事:调用CMSIS-NN的卷积算子,在模拟器上跑通。
3.5.1 创建工程
- uVision → Project → New uVision Project,选择你的目标芯片(比如STM32F407)。
- 在Manage Run-Time Environment中,勾选:
- CMSIS → CORE
- CMSIS → NN
- 添加一个main.c文件到工程。
3.5.2 编写测试代码
下面这段代码,就是一个最简单的CMSIS-NN卷积调用:
#include "arm_nnfunctions.h"
#include "arm_nnsupportfunctions.h"
#define INPUT_CH 3
#define OUTPUT_CH 8
#define KERNEL_DIM 3
#define INPUT_DIM 32
int8_t input_data[INPUT_DIM * INPUT_DIM * INPUT_CH];
int8_t output_data[INPUT_DIM * INPUT_DIM * OUTPUT_CH];
int8_t kernel_data[KERNEL_DIM * KERNEL_DIM * INPUT_CH * OUTPUT_CH];
int32_t bias_data[OUTPUT_CH];
int main(void)
{
arm_convolve_s8(input_data,
INPUT_DIM, INPUT_DIM, INPUT_CH,
kernel_data,
OUTPUT_CH, KERNEL_DIM, KERNEL_DIM,
1, 1, // stride
0, 0, // padding
NULL, // 量化参数(简化示例传NULL)
NULL,
output_data,
NULL);
while(1);
return 0;
}
conv_params、quant_params)必须正确初始化,否则结果完全不可用。我们会在第5章「量化参数详解」中专门讲这个。
3.5.3 编译与调试
按F7编译。如果一切顺利,你应该看到:
Build Output:
compiling main.c...
assembling startup_stm32f407xx.s...
linking...
Program Size: Code=1232 RO-data=320 RW-data=8 ZI-data=1024
".\Objects\test.axf" - 0 Error(s), 0 Warning(s).
看到「0 Error(s)」了吗?恭喜,你的第一个CMSIS-NN工程编译成功了。
如果报错,99%是以下原因:
- 找不到头文件:检查工程选项中C/C++的Include Paths,确保包含了CMSIS-NN的Include目录。
- 链接错误:检查是否添加了CMSIS-NN的库文件或源文件路径。
- AC6版本问题:确认编译器选的是AC6,不是AC5。
3.6 本章小结
这一章,我们把开发环境从头搭了一遍:MDK安装、AC6配置、CMSIS-Pack部署、源码获取、第一个工程编译。看起来步骤多,但做熟了其实就十分钟的事。