TinyML 这个词这两年出现的频率越来越高,但很多人对它的理解还停留在"在单片机上跑个神经网络"这种模糊概念上。真到要动手选板子的时候,问题就来了:到底什么样的硬件才能跑得动 AI 模型?是不是随便一块 STM32 就能上手?算力、内存、功耗这三者之间怎么平衡?我前后用过十几块不同定位的开发板做 TinyML 相关的验证,从 Cortex-M4 到 M7,从纯 MCU 到带 NPU 的异构芯片都折腾过,踩的坑不算少。这篇就把"一块能跑 AI 模型的 TinyML 开发板到底需要哪些硬件"这件事拆开讲清楚,从核心计算单元、内存配置、传感器接口到供电与调试,把选型和设计的逻辑讲透。不管你是刚接触 TinyML 的嵌入式新手,还是正在做端侧 AI 硬件方案的老工程师,应该都能从中找到可以直接参考的东西。
1. 先搞清楚 TinyML 到底在硬件上跑什么
1.1 TinyML 模型的实际计算特征
很多人一上来就问"这块板子算力多少 TOPS",这个问题在 TinyML 场景下其实问偏了。TinyML 跑的模型和云端那些动辄几十亿参数的大模型完全是两回事。典型的 TinyML 模型是关键词唤醒(KWS)、手势识别、异常检测、简单图像分类这类任务,模型参数量通常在几十 KB 到几百 KB 之间,运算量在几百万到几千万 MAC(乘累加)级别。
这意味着什么?意味着 TinyML 的核心瓶颈往往不是算力,而是内存带宽和内存容量。一个 200KB 的模型,权重需要常驻内存,中间层的激活值(activation)需要动态分配,输入数据的缓冲区也要占地方。如果你的 MCU 只有 128KB 的 SRAM,光模型权重就吃掉一大半,剩下的根本不够跑推理。所以选板子的第一件事,是算清楚你的模型需要多大的内存 footprint。
我一般会这样估算:模型权重大小约等于参数量乘以量化位宽除以 8。比如一个 100K 参数的模型,用 int8 量化,权重大约 100KB。再加上激活值缓冲,通常需要权重量的 1.5 到 2 倍。所以一个 int8 量化的 100K 参数模型,实际需要 250KB 到 300KB 的 RAM 才能比较舒服地跑起来。这个数字直接决定了你该选什么档次的芯片。
1.2 推理框架对硬件的隐性要求
TinyML 常用的推理框架有 TensorFlow Lite for Microcontrollers(TFLM)、CMSIS-NN、Edge Impulse 导出的 SDK 等。这些框架对硬件有一些隐性但很关键的要求,很多人选板子的时候容易忽略。
TFLM 本身是纯 C++ 实现的,对硬件没有特殊依赖,但它依赖一个"算子库"。如果你用的是 ARM Cortex-M 系列,CMSIS-NN 会针对 M 系列的 DSP 指令和 SIMD 指令做优化,这时候芯片有没有 DSP 扩展、有没有 Helium(M55/M85 上的向量扩展)就直接影响推理速度。同样是 100MHz 的主频,带 DSP 指令的 M4 跑卷积可能比不带 DSP 的 M0 快五到十倍。
另一个隐性要求是浮点单元(FPU)。虽然现在主流做法是 int8 量化推理,但训练后量化(PTQ)过程中有些算子仍然需要浮点运算,如果你的芯片没有硬件 FPU,这些算子会退化成软件浮点,速度慢得让人怀疑人生。所以我的建议是:做 TinyML,芯片至少要有单精度 FPU,最好是带 DSP 扩展的 Cortex-M4F 起步。
1.3 从任务反推硬件档次的实用方法
与其纠结参数,不如从你的实际任务反推。我整理了一个简单的对照表,是我自己在项目里常用的判断依据:
| 任务类型 | 典型模型规模 | 推荐最低配置 | 典型芯片举例 |
|---|---|---|---|
| 关键词唤醒、振动异常检测 | 10K-50K 参数 | M4F,128KB RAM,无 DSP 也可 | STM32L4 系列 |
| 手势识别、简单音频分类 | 50K-150K 参数 | M4F/M7,256KB RAM,带 DSP | STM32F4、STM32H7 |
| 图像分类(小分辨率) | 150K-500K 参数 | M7,512KB+ RAM,带 DSP/Cache | STM32H743、STM32H750 |
| 多模态、实时视觉 | 500K+ 参数 | 带 NPU 或双核异构 | 带 Ethos-U 的 M55、带 NPU 的异构 SoC |
这张表不是绝对的,但能帮你快速定位。比如你要做的是"识别几个关键词",那 STM32L4 这种低功耗 M4F 就够了,没必要上 H7。反过来,如果你要做 96x96 的灰度图像分类,还要求实时帧率,那 H743 这种带 Cache 和 DSP 的 M7 才是合理起点。
2. 核心计算单元:MCU 选型的几个硬指标
2.1 主频不是唯一指标,Cache 和总线架构更关键
拿 STM32H743 举例,它跑 480MHz,Cortex-M7 内核,看起来很美。但如果你把代码放在外部 QSPI Flash 里跑,没有 Cache 的话,取指延迟会让你怀疑这块芯片是不是坏了。H743 有 L1 Cache(I-Cache 和 D-Cache),还有 TCM(紧耦合内存),这些才是它跑 AI 推理时真正的性能保障。
我实测过一个对比:同样的模型,代码和数据都放在 TCM 里跑,和放在外部 SDRAM 里跑,推理时间差了将近 3 倍。原因就是 TCM 是零等待周期的,而外部存储要经过总线矩阵、可能还有 Cache miss 的开销。所以选 MCU 的时候,一定要看它有没有 TCM、TCM 多大、Cache 多大。H743 有 1MB 的 TCM(ITCM + DTCM),这在跑 TinyML 时非常关键——你可以把模型权重和关键算子都塞进 TCM,推理速度会稳定很多。
另一个容易被忽略的是总线矩阵和 DMA。TinyML 推理过程中,传感器数据要通过 DMA 搬进内存,推理结果要通过 DMA 搬出去。如果总线架构设计得不好,CPU 访问内存和 DMA 访问内存会互相抢带宽,导致推理时间抖动。H7 系列的多层 AXI 总线矩阵就是为解决这个问题设计的,这也是它比 F4 系列更适合跑 AI 的原因之一。
2.2 DSP 扩展与 Helium:加速推理的硬件红利
ARM 的 DSP 扩展(在 M4、M7、M33 上都有)提供了一批 SIMD 指令,比如 SIMD 乘加、饱和运算、位反转等。CMSIS-NN 库会把这些指令用起来,卷积和全连接层的速度能提升好几倍。我做过一个测试:在 M7 上跑一个 100K 参数的 CNN,用 CMSIS-NN 优化过的版本比纯 C 实现快了大约 4.5 倍。
Helium 是 ARMv8.1-M 架构引入的向量扩展,M55 和 M85 支持。它相当于给 MCU 加了一个小型的向量单元,能一次处理多个数据。对于 TinyML 来说,Helium 的收益非常明显,尤其是卷积和矩阵乘法。不过目前支持 Helium 的芯片还不多,生态也在完善中,如果你现在就要量产,M7 + DSP 是更稳妥的选择。
这里有个实操经验:不要只看芯片手册上写的"支持 DSP 指令",要确认你的工具链和推理框架真的用上了这些指令。我见过有人用 Keil 编译 TFLM,默认优化等级下 CMSIS-NN 的汇编优化根本没启用,跑出来的速度和没 DSP 差不多。正确做法是在编译选项里打开-mcpu=cortex-m7 -mfpu=fpv5-d16这类参数,并确保 CMSIS-NN 的预编译库被正确链接。
2.3 双核与异构:什么时候需要更复杂的架构
STM32H7 有双核版本(H745、H747),一个 M7 加一个 M4。这种架构在 TinyML 场景下有用吗?有用,但要看你怎么用。常见的做法是 M7 跑推理,M4 负责传感器采集、通信和系统管理。这样推理任务不会被中断打断,实时性更好。
但双核也带来了核间通信的开销和调试复杂度。如果你的任务比较简单,单核 M7 完全够用,没必要为了"看起来更强"上双核。我个人的判断标准是:如果推理任务的 deadline 很紧(比如每 10ms 必须出结果),而且系统还有其他实时任务,那双核值得考虑;否则单核更省心。
再往上就是带 NPU 的异构芯片了,比如带 Ethos-U55/U65 的 M55 组合,或者一些国产的带 NPU 的 SoC。这类芯片的算力能到 0.5 TOPS 甚至更高,能跑更复杂的模型。但代价是开发工具链更复杂,模型部署需要经过额外的编译步骤(比如 Vela 编译器把 TFLite 模型转成 Ethos-U 能执行的格式)。如果你团队里没有专门做模型部署的人,上手门槛不低。
3. 内存配置:TinyML 最容易被低估的瓶颈
3.1 SRAM 容量与模型 footprint 的匹配计算
前面提到了模型 footprint 的估算,这里展开讲一下怎么精确计算。假设你有一个 TFLite 模型文件,大小是 180KB。这个文件里包含了权重、偏置和算子描述。部署到 MCU 上时,权重需要放在 Flash 或者 RAM 里,激活值需要放在 RAM 里。
TFLM 提供了一个MicroInterpreter的 API,你可以通过arena_used_bytes()来查看实际用了多少 RAM。但在这之前,你需要先给 arena 分配一块内存。我的经验是:arena 大小至少要是模型文件大小的 1.5 倍,如果模型里有比较多的中间层,可能要 2 倍。比如 180KB 的模型,arena 至少给 270KB,保险起见给 360KB。
这时候如果你的 MCU 只有 512KB SRAM,看起来够,但别忘了系统本身还要用 RAM——栈、堆、通信缓冲区、传感器驱动缓冲区。实际留给 TFLM arena 的可能只有 300KB 左右。所以选芯片的时候,SRAM 容量要留足余量,我一般建议可用 SRAM 至少是模型文件大小的 3 倍。
3.2 外部存储与内存扩展的取舍
当片上 SRAM 不够时,有几个选择:外挂 SDRAM、外挂 QSPI Flash、或者用带更大片上 RAM 的芯片。
外挂 SDRAM 的好处是容量大、成本相对低,但访问延迟高,而且需要配置 FMC/OctoSPI 控制器。如果你把模型权重放在 SDRAM 里,每次推理都要从 SDRAM 读权重,速度会比片上 RAM 慢不少。我的做法是:权重放外部 Flash,推理时按需加载到片上 TCM 或 SRAM 里,这样兼顾了容量和速度。
STM32H743 支持 OctoSPI,可以外挂 Octal Flash 或 HyperRAM。HyperRAM 是个不错的选择,它比 SDRAM 接口简单,功耗也低,适合做推理时的数据缓冲区。但 HyperRAM 的带宽有限,不适合放频繁访问的权重。
还有一种思路是用带大容量片上 RAM 的芯片,比如有些国产 MCU 带 1MB 甚至 2MB SRAM。这类芯片省去了外挂存储的麻烦,但价格通常更高,而且生态和工具链的成熟度需要评估。
3.3 内存布局对推理速度的实际影响
内存布局这件事,很多人不重视,但它对推理速度的影响可能比主频还大。我举个实际例子:同样的模型,同样的芯片(STM32H743),我把权重放在不同的位置,推理时间如下:
| 权重存放位置 | 推理时间(相对值) | 说明 |
|---|---|---|
| DTCM | 1.0(基准) | 零等待周期,最快 |
| AXI SRAM | 1.3 | 有 Cache,但仍有开销 |
| 外部 SDRAM | 2.8 | 总线延迟高,Cache miss 多 |
| 外部 QSPI Flash(无 Cache) | 5.5 | 取指延迟极大 |
这个表说明什么?说明如果你要做高性能 TinyML,一定要把关键数据放在 TCM 里。H743 的 DTCM 有 128KB,ITCM 有 64KB,加起来 192KB。对于小模型,完全可以把权重和 arena 都放进 TCM。对于大一点的模型,至少把最频繁访问的层放进 TCM。
具体操作上,你可以用链接脚本(linker script)把特定的段分配到 TCM。比如在 GCC 里,可以用__attribute__((section(".dtcmram")))把数组放到 DTCM。TFLM 的 arena 也可以通过自定义内存分配器来指定位置。
4. 传感器与接口:数据从哪来,结果往哪去
4.1 音频、视觉、IMU 三类典型传感器的接口需求
TinyML 的输入数据主要来自三类传感器:麦克风(音频)、摄像头(视觉)、IMU(运动)。每类传感器对硬件接口的要求不同。
音频场景通常用 I2S 接口的数字麦克风(比如 INMP441、ICS-43434)。I2S 需要 MCU 支持 I2S 外设,并且最好有 DMA 支持,这样音频数据可以自动搬进缓冲区,不占 CPU。采样率一般是 16kHz,16bit 位深,单声道。对于关键词唤醒,通常需要 1 秒的音频窗口,也就是 32KB 的缓冲区(16kHz × 2字节 × 1秒)。这个缓冲区大小在选内存时要算进去。
视觉场景用 DCMI(数字摄像头接口)或者 SPI 接口的摄像头。DCMI 是 STM32 上常用的并行摄像头接口,支持 DMA,能直接把手图像数据搬进内存。但 DCMI 的引脚多,PCB 布线麻烦。SPI 摄像头(比如一些国产的低分辨率模块)引脚少,但带宽有限,适合低帧率、低分辨率的场景。如果你要做 96x96 的灰度图,SPI 摄像头勉强够用;如果要做 224x224 的 RGB,那必须上 DCMI 或者更高级的接口。
IMU 通常用 SPI 或 I2C 接口。SPI 速度快,适合高采样率;I2C 引脚少,适合低速场景。做振动异常检测时,采样率可能要几 kHz,这时候 SPI 更合适。做手势识别时,100Hz 左右的采样率,I2C 就够了。
4.2 DMA 通道分配与数据吞吐的实战考量
DMA 在 TinyML 系统里太重要了,但很多人分配 DMA 通道时很随意,结果跑起来发现数据丢包或者推理时间抖动。我的经验是:给每个高速数据源分配独立的 DMA 通道,并且尽量用不同的 DMA 控制器。
STM32H7 有两个 DMA 控制器(DMA1、DMA2)和多个 BDMA 通道。I2S 音频、DCMI 摄像头、SPI 传感器最好各用一个独立的通道。如果通道不够用,至少要把音频和视觉分开,因为这两个数据流对实时性要求最高。
另一个坑是 DMA 和 Cache 的一致性问题。H7 有 D-Cache,DMA 搬运数据时不经过 Cache,会导致 CPU 读到旧数据。解决办法是要么把 DMA 缓冲区放在非 Cache 区域(比如 SRAM4),要么在 DMA 传输前后做 Cache 维护(invalidate/clean)。我一般推荐前者,省事且不容易出错。
4.3 输出执行器与通信接口的选型
推理出结果之后,通常要驱动一些执行器或者把结果发出去。常见的输出包括:GPIO 控制 LED 或继电器、PWM 控制电机或蜂鸣器、UART/CAN 发送结果给上位机或其他节点。
这里有个容易忽略的点:输出动作的延迟也会影响用户体验。比如关键词唤醒后要点亮 LED,如果从推理完成到 GPIO 翻转之间有几十毫秒的延迟,用户会觉得"反应慢"。所以输出路径也要尽量短,最好在推理完成的中断里直接操作 GPIO,不要经过多层任务调度。
通信接口方面,UART 最简单,适合调试和低速数据传输。CAN 适合工业场景,抗干扰强。如果要做无线,可以加 BLE 或 LoRa 模块,但要注意这些模块的功耗和唤醒延迟。做电池供电的 TinyML 设备时,通信模块往往是功耗大头,选型时要特别关注它的休眠电流和唤醒时间。
5. 供电、时钟与调试:那些"不起眼但致命"的细节
5.1 电源域设计与低功耗模式的实际表现
TinyML 设备很多是电池供电的,功耗直接决定续航。但功耗优化不是简单选个 LDO 或者 DC-DC 就行,它涉及到电源域划分、低功耗模式配置和外设时钟管理。
STM32H7 有多个电源域:VDD(主电源)、VDDA(模拟电源)、VBAT(备份电源)、VDDLDO(内部 LDO 输出)等。做低功耗设计时,要把不用的外设时钟关掉,把不用的电源域断开。比如你不用 ADC,就把 VDDA 相关的电路简化;不用 RTC,就不需要 VBAT。
低功耗模式方面,H7 支持 Sleep、Stop、Standby 等模式。TinyML 的典型工作模式是"采集-推理-休眠"循环。在休眠时进入 Stop 模式,电流可以降到几百微安;唤醒后跑推理,电流可能到几十毫安。平均功耗取决于占空比。我做过一个关键词唤醒的 demo,推理时间 20ms,休眠 980ms,平均电流大约 2mA,用 1000mAh 电池能跑 20 天左右。
但这里有个坑:从 Stop 模式唤醒后,系统时钟需要重新配置,外设需要重新初始化。如果你的推理任务对唤醒延迟敏感,这个重新配置的时间要算进去。H7 从 Stop 模式唤醒大约需要几十微秒,还算快,但如果你用的是更慢的时钟源,可能会到毫秒级。
5.2 时钟树配置对推理稳定性的影响
时钟树配置看起来是底层的事,但它对推理稳定性影响很大。H7 的主频可以到 480MHz,但这是通过 PLL 倍频得到的。如果 PLL 配置不稳定,或者电源纹波太大,可能会导致偶发的计算错误。
我的经验是:做 TinyML 时,时钟配置要留余量。比如 H7 标称 480MHz,你可以跑 400MHz,这样功耗更低,稳定性更好,推理速度的损失也在可接受范围内。另外,外部晶振的选择也很重要,尽量用质量好的晶振,负载电容要匹配好,否则 PLL 可能锁不定或者有抖动。
还有一个细节:Cache 和 TCM 的时钟配置。有些芯片的 TCM 和 Cache 可以独立配置时钟,如果配置不当,可能会导致访问延迟增加。这个要看具体芯片的参考手册,不同系列差异很大。
5.3 调试接口与固件烧录的避坑经验
调试接口这块,SWD 是标配,但有些细节要注意。比如 SWD 的引脚要和 GPIO 复用,如果你在代码里把 SWD 引脚配置成了普通 GPIO,下次就烧不进去了。我踩过这个坑,最后是用 BOOT0 拉高进入 DFU 模式才救回来。
另外,做 TinyML 时经常需要看推理时间,这时候DWT(Data Watchpoint and Trace)的周期计数器很好用。你可以在推理前后读 DWT->CYCCNT,算出精确的周期数。但要注意,DWT 在低功耗模式下可能不工作,测出来的时间可能不准。
固件烧录方面,如果你用外部 Flash 存模型,烧录时要确保模型数据也被正确写入。有些 IDE 默认只烧录内部 Flash,外部 Flash 的数据需要单独烧录或者通过 bootloader 加载。我一般会在固件里加一个"模型校验"的步骤,启动时检查外部 Flash 里的模型 CRC 是否正确,不对就报错,避免跑出莫名其妙的结果。
6. 从选型到落地:一套可复用的硬件评估流程
6.1 需求拆解与硬件规格书的形成
说了这么多技术点,最后落到实操上,我一般会按这个流程来评估一块板子能不能用:
第一步,明确任务类型和模型规模。是音频、视觉还是 IMU?模型参数量大概多少?量化方式是 int8 还是 float16?这些决定了内存和算力的底线。
第二步,算内存账。模型文件大小 × 1.5 到 2 倍 = arena 需求。加上系统 RAM、传感器缓冲区、通信缓冲区,得到总 RAM 需求。然后看芯片的 SRAM 够不够,不够的话考虑外挂存储。
第三步,算算力账。根据模型的 MAC 数和目标帧率/实时性要求,估算需要的算力。M4F 大概能跑几十 MOPS,M7 能跑几百 MOPS,带 NPU 的能到 TOPS 级别。留 2 倍余量比较稳妥。
第四步,看接口。传感器接口(I2S/SPI/I2C/DCMI)、输出接口(GPIO/PWM/UART/CAN)、调试接口(SWD/JTAG)是否满足。
第五步,评估功耗和供电。电池供电的话,算平均功耗和续航;市电供电的话,关注电源纹波和散热。
第六步,看生态和工具链。芯片厂商有没有提供 TinyML 相关的例程、库、文档?社区活跃度如何?遇到问题能不能找到人问?
6.2 快速验证:用现成开发板跑通第一个模型
理论算完,最好尽快上手验证。我的建议是先用现成的开发板跑一个最简单的模型,比如 Hello World 级别的正弦波预测或者关键词唤醒。这样能快速验证工具链是否顺畅、推理时间是否符合预期、内存是否够用。
STM32H743I-DISCO 或者 NUCLEO-H743ZI 都是不错的起点,板载 ST-Link,烧录调试方便,SRAM 够大,外设齐全。跑通 TFLM 的 micro_speech 例程,你能得到第一手的推理时间数据,这比看手册估算靠谱得多。
跑通之后,再逐步替换成你自己的模型和传感器,观察内存占用和推理时间的变化。这个过程可能会发现一些之前没考虑到的问题,比如某个算子的内存开销特别大,或者某个传感器的 DMA 配置和 TFLM 冲突。早发现早解决,比画完板子再改要省事得多。
6.3 从开发板到自研硬件的过渡要点
开发板验证通过后,如果要自研硬件,有几个点要特别注意。
第一,电源设计要留余量。开发板上的电源通常比较充裕,自研时如果为了省成本用了电流能力刚好的 LDO,可能会在推理峰值时出现电压跌落,导致芯片复位。建议电源的额定电流至少是实测峰值的 1.5 倍。
第二,晶振和复位电路要可靠。这两块是硬件稳定性的基础,不要在这上面省钱。晶振选质量好的,负载电容按手册推荐值配;复位电路加合适的 RC 和二极管,确保上电复位可靠。
第三,调试接口一定要引出。哪怕产品定型了,也要留 SWD 的测试点,方便后续排查问题。我见过为了省两个引脚把 SWD 去掉的板子,出了问题只能拆芯片,非常痛苦。
第四,外部存储的布线要注意信号完整性。如果用 OctoSPI 或者 SDRAM,走线要等长,阻抗要匹配,否则高速下会出错。这块最好让有经验的硬件工程师 review 一下。
第五,预留传感器接口的兼容性。TinyML 项目经常需要换传感器做对比实验,如果 PCB 上只留了一种传感器的接口,换传感器就要重新画板。建议用排针或者 FPC 连接器,把常用的接口(I2S、SPI、I2C)都引出来。
6.4 常见选型误区与我的实际踩坑记录
最后分享几个我踩过的坑,希望能帮你少走弯路。
误区一:只看主频不看架构。我曾经选了一块 200MHz 的 M4 芯片,以为比 100MHz 的 M7 快,结果跑 CNN 时发现 M7 反而更快,因为 M7 有双发射流水线和更大的 Cache。主频只是表象,架构和 Cache 才是关键。
误区二:忽略 Flash 等待周期。有些芯片的 Flash 在高速下需要插入等待周期,如果你把代码放在 Flash 里跑,实际执行速度会比标称主频低不少。解决办法是把关键代码搬到 RAM 里跑,或者选带 Cache 的芯片。
误区三:低估工具链的坑。TFLM 的版本更新很快,不同版本之间的 API 可能有变化。我有一次用了一个新版本的 TFLM,发现某个算子的实现变了,导致推理结果和之前不一致。后来固定了版本,问题才解决。建议在项目开始时就把工具链版本锁定,不要随意升级。
误区四:忘记算传感器的功耗。做电池供电的设备时,我只算了 MCU 的功耗,忘了麦克风一直开着也要耗电。结果实测续航只有估算的一半。后来改成麦克风间歇工作,续航才达标。
误区五:调试接口被复用。前面提过,SWD 引脚被配置成 GPIO 后烧不进去。这个坑我踩过两次,后来养成了习惯:在代码里永远不碰 SWD 相关的引脚,或者在初始化时先检查调试器是否连接。
这些经验看起来琐碎,但每一个都是真金白银换来的。TinyML 硬件选型没有标准答案,关键是理解你的任务需求,然后在这些需求之间做合理的权衡。希望这篇内容能帮你在选板子的时候少一些纠结,多一些笃定。