使用使用 Edge Impulse 在 STM32N6570-DK 上实现的实时水果检测
如果你曾尝试在边缘端构建过任何类型的视觉系统,比如农业监测、库存追踪等需要本地识别物体而无需向云端发送请求的场景,你可能已经遇到过同样的难题:传统微控制器(MCU)本身没有足够的内存来运行物体检测。无论是内存不足无法缓冲摄像头帧,还是存储空间不足无法保存模型权重,都是问题所在。通常的解决办法是采用Linux SBC(单板计算机),但这会迅速消耗你的电源预算,并大幅增加产品成本。
STM32N6570-DK 的设计旨在消除这种权衡。ST 采用了非传统的方案来实现该板的架构。这款芯片没有内置闪存,而是搭配了一块外部 Octo-SPI 闪存、4.2MB 的内部 SRAM,以及一个与 Cortex-M55 核心并行运行的专用 Neural-ART 加速器。由此构成的微控制器拥有足够的高速存储空间,可同时容纳相机帧缓冲区、模型权重和 NPU 激活数据。再加上 Edge Impulse 来处理 MLOps 流程,原本需要数周时间才能完成的 C++ 工具链开发,如今只需一个周末即可轻松完成。本文将详细说明这一设计的具体实现方式,包括其中一些并不显而易见的部分。
零内部闪存优势
对于计算机视觉任务,内存的解耦以及存储和运行时的有效且独立的内存选项,使得该芯片具备可行性。帧缓冲区、模型权重、NPU激活值和系统逻辑均可同时存在于SRAM中,而不会相互拥挤。启动过程专门在AXI SRAM2区域运行,链接脚本将其划分为255KB的代码段和256KB的数据段,这对后续章节中提到的二进制文件大小限制具有直接影响。
无闪存设计还意味着芯片需要一个结构化的启动流程,在推理开始之前将所有内容加载到SRAM中。在启动时,Boot ROM、第一阶段引导加载器(FSBL)以及加载并运行的过程负责从外部闪存将二进制文件提取到内部存储器中,从而使模型最终运行在高速SRAM上,而非依赖较慢的闪存执行。在硬件方面,电路板其余部分完成了与视觉相关的特定工作流:ST Neural-ART 加速器负责推理卸载,使Cortex-M55不会被矩阵计算所淹没;而H264编码器、NeoChrom 2.5D GPU,以及内置的摄像头和麦克风接口则处理输入输出任务,无需额外外接芯片。对于STM32N6570-DK这一开发套件而言,实现可运行演示版本与可量产设计之间的差距异常之小。
由于没有内部闪存,STM32N6 无法像普通微控制器那样直接上电并从地址零开始执行你的应用程序。每次启动都始于片上启动ROM,这是唯一存在于实际ROM中、在其他任何操作之前运行的一段代码。它会初始化系统,检测复位源,然后访问外部Octo-SPI闪存,将第一阶段引导加载程序(FSBL)加载到AXI SRAM2中,并通过ECDSA 256/384签名验证进行认证,之后才跳转执行。最后这一点是不可妥协的:FSBL必须经过签名,否则启动ROM将无法以安全锁定状态执行它。随后,FSBL接管控制权,配置系统时钟,初始化XSPI2外部存储器接口,并通过“加载与运行”(LRUN)序列,将主应用二进制文件从外部闪存复制到内部SRAM中。整个流程如下所示:
Boot ROM -> AXI SRAM2 加载 -> 27F6 FSBL(时钟 + XSPI2 初始化) U+27F6 传感器缓冲区填充 -> 27F6 Neural-ART 推理(添加长箭头的 Unicode 字符:
Edge Impulse 的 STM32N6 部署使用了上述的加载并运行模板,适用于许多视觉项目。如果您的项目需要超过 511KB 的应用上限,则应考虑本指南中介绍的“就地执行”模板——链接。
软件桥接:Edge Impulse + ST Neural-ART 可移动模式
在STM32N6上使用Edge Impulse部署模型时,无需手动配置ST Neural-ART工具链、处理NPU的内存布局,或自行应对C++编译流程——这些正是大多数项目在推理运行前卡住的原因。Edge Impulse会自动完成所有这些工作,直接针对Neural-ART加速器进行优化,并生成可无缝集成到STM32N6启动流程中的二进制文件,无需人工干预。该平台支持FOMO和YOLOv5,但我们选择了YOLO-Pro,特别是Pico和Nano版本。通常情况下,YOLO-Pro的完整空间边界框会对传统MCU造成性能瓶颈,但在STM32N6上,得益于4.2MB连续SRAM和Neural-ART加速器的支持,该板能够轻松应对更复杂的架构需求。更值得关注的是,Edge Impulse如何通过ST Neural-ART的可重定位模式实现模型部署。它不会将神经网络权重直接嵌入应用固件中,而是通过构建过程将其拆分为独立的二进制文件network_data.hex,该文件位于独立的闪存地址,与主应用程序相互隔离。实际上,这意味着你可以在不重新编译或刷写固件的情况下更新模型权重。只需在单一地址处重刷一个文件,即可将一个模型替换为另一个模型,而系统的其余部分保持不变。对于那些希望从演示走向实际部署的用户来说,在开始训练之前理解这种分离机制是十分必要的。
本项目的数据集包含两种水果类别,即橙子和牛油果。数据采集策略比类别数量更为重要。在受控光照条件下拍摄的图像,一旦出现阴影覆盖画面或叶片部分遮挡目标,模型就会失效。为避免这种情况,我们采集了多种光照条件下的图像,包括直射背光、不同距离以及存在自然遮挡的情况。Edge Impulse 的数据采集流程确保了这一实际性需求得以满足。
edge-impulse-daemon 命令可将 STM32N6570-DK 直接连接到您的项目中,使您无需离开平台即可从内置摄像头捕获并标记图像。在此阶段,图像已调整为标准化的输入分辨率,从而在推理时减少了 CPU 的预处理开销,而不再每帧都进行处理。本项目选择了 160 x 160 的分辨率。
在数据集完成标注并上传后,Edge Impulse Studio 的训练只需选择对象检测学习模块,并将模型架构设为 YOLO-Pro Pico 或 Nano(本项目选择了 Pico 版本)。在开始完整训练任务之前,建议先检查目标性能分析器。选择 STM32N6570-DK 作为目标设备,分析器会返回与实际硬件相匹配的内存使用量、闪存消耗和推理延迟估算值。在这一阶段发现内存预算问题无需付出任何代价;而等到刷入固件后再发现问题,则需要耗费调试时间。
Pico 和 Nano 的选择非常明确:Pico 更快,占用空间更小;Nano 则在内存略有增加的同时,提供了更高的精度。作为一般准则,建议先从 Pico 开始,只有当检测的置信度不足以满足项目需求时,才考虑升级到 Nano。
部署:三个二进制文件、三个地址、一个订单及常见误区
Edge Impulse 的 STM32N6 导出文件包含三个文件:第一阶段引导加载程序(ai_fsbl_cut_2_0.hex)、应用程序固件(firmware-st-stm32n6.bin)以及可重定位的模型权重(network_data.hex)。刷写这些文件需要使用 STM32CubeProgrammer,但 Edge Impulse 也提供了平台脚本(Linux/macOS 系统下为 flash.sh,Windows 系统下为 flash.bat),可自动封装编程器并替您执行相关命令。在运行前,请将 BOOT1 开关拨至正确位置以进入 DEV 模式,并通过 NRST 重置电路板。否则,电路板将无法接受闪存写入操作。闪存顺序和地址是固定的:FSBL 位于 0x70000000,应用程序位于 0x70100000,权重位于 0x71000000。引导加载程序只需写入一次;在模型更新时,仅需重新刷写权重和固件,因为这是可重定位架构。
地址分配不可变,network_data.hex 必须精确地位于 0x71000000。如果未使用 arm-none-eabi-objcopy 来强制该地址,应用程序在推理时会硬故障,且错误输出中没有任何信息指向实际原因。当三个二进制文件都写入后,将 BOOT1 按左键翻转,复位,板子便会从外部闪存启动进入完整的推理流程。
对于高分辨率图像,在首次完整运行前,有必要了解一个隐形的CPU开销:摄像头输入的图像分辨率高于模型的输入尺寸,这些帧在数据传入NPU之前,会先在Cortex-M55上进行尺寸调整。在持续推理速率下,预处理成本会不断累积。如果测得的FPS低于性能分析器的推理延迟所提示的数值,那么这就是需要首先排查的地方。
还有一个最终问题会迫使你为干净的代码而费力地排查幽灵bug:同时运行摄像头、Cortex-M55和Neural-ART加速器,其耗电量超过了标准USB数据端口可靠提供的电流。症状包括电源中断、随机复位以及摄像头行为异常,这些现象看起来完全像是软件问题。解决方法很简单:连接CN8以提供额外电源,并将跳线JP2拨至3-4:5V_USB_STLK位置。请在首次完整推理运行前完成此操作,而不是在调试了一个从未出错的二进制文件一小时后才进行。
结语:这个开发板释放了什么
STM32N6 学习曲线较长,但一旦用户掌握了其工作原理,这款开发板便提供了一项在其他地方难以找到的真正优势:在微控制器上实现稳定、实时的视觉推理,无需 Linux 内核,无需庞大的功耗预算,也无需每次重新训练时都将模型权重绑定到固件中。
此处建立的模式——边缘计算用于MLOps流水线、ST Neural-ART可迁移模式以实现部署灵活性、YOLO-Pro Pico/Nano作为模型架构,均可直接应用于水果检测之外的更多场景。工业检测中的常亮摄像头、农业监测节点、无需依赖云端即可实现本地视觉的可穿戴设备:所有这些应用都共享着本项目所依托的核心约束条件。
本文编译自hackster.io





