嵌入式系统基础:MCU架构、外设接口、内存与存储限制、实时操作系统基础

TinyML 的最终目标是将训练好的模型部署到资源受限的嵌入式设备上,而绝大多数此类设备的核心就是微控制器(MCU)。与运行 Linux 的应用处理器不同,MCU 在功耗、成本和实时性上具有显著优势,但其架构设计、外设接口、内存与存储限制以及软件执行模型,都深刻影响着 ONNX 模型如何被转换、优化和最终运行。理解这些底层机制,是避免“模型在 PC 上跑得好、上板就崩溃”的关键第一步。本章将系统拆解 MCU 的四大核心基础,为后续的模型转换与算子优化打下坚实的硬件认知基础。

MCU 核心架构 外设与接口 内存与存储 CPU 核心 (ARM Cortex-M) 流水线 / 中断控制器 NVIC 总线矩阵 (AHB/APB) 连接内核与外设的桥梁 时钟与复位 PLL / 外部晶振 / 看门狗 调试接口 (SWD/JTAG) 程序下载与实时调试 UART / SPI / I2C 串行通信接口 GPIO / 外部中断 传感器触发与信号采集 ADC / DAC 模拟信号与数字信号转换 DMA 控制器 外设数据直接搬运至内存 定时器 (PWM/输入捕获) 精确延时与波形生成 Flash (只读存储) 存放代码与只读数据 (权重) SRAM (运行内存) 存放变量、堆栈、中间计算结果 EEPROM / 外部存储 参数校准与离线数据记录 Cache (可选) 部分高性能 MCU 提供指令缓存 图:MCU 三大核心资源——架构、外设、存储的协同关系

核心原理:MCU 的资源边界与执行模型

MCU 的本质是一个单芯片微型计算机,它将处理器核心、存储器、可配置输入输出外设集成在同一颗硅片上。与 PC 或手机 SoC 不同,MCU 通常运行裸机程序或轻量级 RTOS,没有虚拟内存、没有用户态与内核态的严格区分,所有代码均运行在特权模式。这意味着 TinyML 模型转换后的 C 代码,将直接操作物理地址,任何内存越界或指针错误都会导致 HardFault 异常,系统直接死机。

从指令集架构看,当前 TinyML 领域最主流的是 ARM Cortex-M 系列(M0+/M3/M4/M7/M33)以及 RISC-V 内核。Cortex-M4 与 M7 内置了 DSP(数字信号处理)指令和可选的 FPU(浮点运算单元),这对于卷积运算中的乘加操作至关重要。例如,Cortex-M4 的单周期 MAC(乘加)指令可以显著加速矩阵乘法,而 FPU 则能硬件加速浮点运算,但代价是更高的功耗与更大的芯片面积。理解目标 MCU 是否支持 DSP 扩展、FPU 是单精度还是双精度,直接决定了 ONNX 模型转换时算子能否被高效映射。

MCU 的时钟频率通常在 16 MHz 至 480 MHz 之间(如 STM32H7 系列),远低于 PC 的 GHz 级别。但 TinyML 应用(如关键词唤醒、异常检测)往往对延迟有硬性要求,因此必须在算法层面做极致的优化。此外,MCU 的功耗通常以 mW 甚至 uW 为单位,这要求模型推理必须在极短的时间内完成,以便让芯片尽快进入低功耗睡眠模式。

判断方法:如何评估 MCU 是否适合目标模型

在开始 ONNX 模型转换之前,必须对目标硬件进行量化评估。以下是四个关键维度的判断清单:

评估维度 关键指标 对 TinyML 的影响 最低要求参考
Flash 容量 存储代码 + 模型权重 + 常量表 决定能否装下完整的模型参数 ≥ 模型大小 × 1.5(含代码)
SRAM 容量 运行时的变量、中间特征图、堆栈 决定推理时能否容纳激活值 ≥ 最大中间张量 × 2 + 堆栈
算力 (MAC/s) 主频 × 并行度(如 DSP 指令) 决定推理延迟上限 ≥ 模型 MACs ÷ 目标延迟
外设接口 ADC 采样率、DMA 通道数、通信速率 决定传感器数据能否实时喂给模型 ≥ 传感器输出速率 × 1.2

一个实用的判断流程是:首先从 ONNX 模型中提取参数量与 MACs(乘加次数),然后根据目标 MCU 的主频与是否有 FPU/DSP 估算推理时间。例如,一个 1MB 的模型在 100 MHz 的 Cortex-M4 上,若全部为 8bit 整数运算,大约需要 100M 次乘加,考虑流水线效率,预估耗时在 1-2 秒,这显然不适合实时控制类应用。

案例拆解:STM32L4 系列上的关键词唤醒模型部署

假设我们需要在 STM32L4 系列 MCU(Cortex-M4F,80 MHz,512KB Flash,128KB SRAM)上部署一个语音关键词唤醒模型。该模型经过 TensorFlow 训练后导出为 ONNX 格式,参数量为 250KB,单次推理需要 12M MACs。

初始现象与目标: 模型在 PC 上推理延迟为 5ms,但希望 MCU 上延迟小于 100ms,且 RAM 占用不超过 80KB(留出 48KB 给系统栈和音频缓冲)。

分析判断过程: 首先,250KB 的模型权重可以放入 512KB Flash,但若使用浮点推理,12M MACs 在 80MHz 主频下(无 FPU 加速时)需要 150ms,超出预算。其次,浮点中间特征图若为 128×128 的二维数组,占用 64KB SRAM,加上音频数据,内存告急。

实际操作步骤:

  1. 量化: 使用 ONNX Runtime 的量化工具将模型从 FP32 转为 INT8,权重从 250KB 压缩至 63KB,MACs 运算量不变,但单次乘加时间缩短至 1 个周期。
  2. 算子替换: 将 ONNX 中的 Conv 算子映射为 CMSIS-NN 库中的 arm_convolve_s8 函数,该函数针对 Cortex-M 的 DSP 指令做了深度优化。
  3. 内存规划: 将音频数据缓冲放在 SRAM 起始地址,模型中间特征图采用“内存复用”策略,即前一层计算完立即释放,后一层复用同一块内存区域。
  4. 外设配置: 使用 DMA 将麦克风的 PDM 数据直接搬运至 SRAM,无需 CPU 干预,降低中断延迟。

结果对比: 优化后,模型推理延迟为 45ms,RAM 占用 72KB,满足设计要求。若不做量化与算子映射,延迟将高达 300ms,且内存溢出。

风险与代价: INT8 量化导致模型精度从 95% 下降至 93.5%,但通过量化感知训练可恢复至 94.2%。此外,CMSIS-NN 库增加了约 20KB 的 Flash 代码占用。

复盘经验: 在 MCU 上部署 TinyML,内存规划比算力优化更优先。先确认最大中间张量能否塞进 SRAM,再考虑算力是否足够。若内存不足,优先考虑模型剪枝或输入特征降维,而非盲目升级硬件。

实时操作系统基础:RTOS 在 TinyML 中的角色

虽然简单的 TinyML 应用可以运行在裸机上,但实际产品往往需要同时处理传感器采集、通信、用户交互与模型推理。此时引入 RTOS(实时操作系统)是必要的。RTOS 的核心价值在于任务调度与资源隔离。它允许将模型推理作为一个低优先级任务,将传感器数据采集作为高优先级中断服务程序(ISR),通过信号量或消息队列进行数据传递。

在 TinyML 场景下,RTOS 的选择需考虑以下因素:

  • 调度延迟: 中断到任务唤醒的时间应小于 10us,否则可能丢失传感器数据。
  • 内存占用: 每个任务需要独立的栈空间,RTOS 内核本身占用 2-8KB RAM,需预留。
  • IPC 机制: 消息队列与事件标志组是模型输入输出的主要通道。

常见的 RTOS 包括 FreeRTOS(最广泛)、RT-Thread(国产,组件丰富)、Zephyr(支持 Linux 开发习惯)。在模型推理任务中,通常将推理函数封装为独立任务,并设置其优先级低于中断处理,但高于显示刷新等非实时任务。

风险提示: 在 RTOS 中运行 ONNX 转换后的代码,必须注意可重入性问题。如果模型推理函数内部使用了全局变量或静态缓冲区,则无法被多个任务同时调用。建议将模型实例封装为独立对象,每个任务持有自己的上下文指针。

常见误区与总结复盘

在嵌入式系统基础这一章,开发者常犯以下错误,导致后续部署失败:

误区 后果 正确做法
忽视 Flash 与 RAM 的读写速度差异 频繁从 Flash 读取权重导致性能瓶颈 将热点数据(如卷积核)加载至 SRAM 缓存
未考虑堆栈溢出 系统随机死机,难以排查 使用 MPU(内存保护单元)或栈水印检测
外设初始化顺序错误 DMA 传输数据错位 严格遵循参考手册的时钟使能顺序
将 RTOS 当 Linux 用 任务阻塞导致实时性丧失 ISR 中只做标记,具体处理放任务中