2025年中旬,为了验证STM32N6的NPU性能以及体验官方的Model Zoo生态,自制了一块STM32N6570核心板,结果因为工作忙加上没配IO板,在抽屉里吃灰了一年多。其实这块板子挺让人纠结,芯片贵、电路复杂、软件配置也麻烦,对于只是业余随便折腾的电子爱好者来说,在这些琐碎细节上耗精力实在不划算,所以一直不太想碰。但考虑到当初打板就花了一千五百多,直接扔了又太可惜,思来想去还是给它补了一块IO板,打算验证完外部存储器功能就彻底搁置,给它一个完整的生命周期。
相关文件已开源到github: https://github.com/cl-ei/stm32n657i0-dev-board-hardware
主控STM32N657I0H3Q,板上晶振48Mhz,有一个低电平驱动的红色LED灯,连接PG10引脚。核心电压默认给到了0.89v,配置R30和R31可以调整到0.81v。Flash型号为MX66UW1G45GXDI00,1G bit(128MB),需要先焊接SB1将VDDA1V8供电输入到Flash芯片的VDD引脚。IO配置如下:
/* MX66UW1G45GXDI00 Pin Map */
#define FLASH_NCS PN1
#define FLASH_DQS PN0
#define FLASH_CLK PN6
#define FLASH_IO0 PN2
#define FLASH_IO1 PN3
#define FLASH_IO2 PN4
#define FLASH_IO3 PN5
#define FLASH_IO4 PN8
#define FLASH_IO5 PN9
#define FLASH_IO6 PN10
#define FLASH_IO7 PN11
系统复位后会执行内部的bootROM,启动模式依赖BOOT0、BOOT1引脚和一个TAMP backup register以及一个OTP(一次性编程)的word决定。BOOT1引脚默认为PA6。启动模式如下:
| BOOT0 | BOOT1 | Boot source |
|---|---|---|
| - | 1 | Development boot |
| 0 | 0 | Flash boot |
| 1 | 0 | Serial boot |
Serial boot即从串口或USB接口启动,不在讨论范围。Dev boot是开发调试时,调试器直接将代码搬到对应的内存地址进行执行;而Flash boot即从外部存储器启动,可以通过OTP配置启动方式,比如选择从SPI NOR Flash启动还是SDMMC等。
这里的OTP很坑,只能一次性编程,如果配置错了标志位,就可能导致启动时找不到对应外部设备而变砖,整块板子都会报废。好在芯片中有很多OTP是用户用途的,比如用来写入用户定义的序列号、秘钥等,可以先找一个无关系统功能的OTP word进行配置,以此熟悉配置过程。
第一段引导加载程序(FSBL)是 STM32N6 微控制器启动流程中的关键组件。它负责初始化系统、配置硬件,并将应用程序代码从外部存储器加载至内部或外部存储器中执行。
当boot引脚拨到 0 0 时,这里有几种启动方式,分为两种类型,一是在内部SRAM上执行代码,二是在外部存储器上执行。
启动流程
复位之后,bootROM会检查外部存储器中存储的的FSBL前1K byte的内容(签名,其实只有前512 byte有效,后512 byte为填充值),如果校验OK,则bootROM会将FSBL从外部存储器搬到内部SRAM中,然后跳转到SRAM中FSBL的起始位置(跳过1K byte的签名)开始执行,此时执行的就是内部SRAM的FSBL。
如果图简单,FSBL可以包括启动的配置(bootloader)和用户代码,即用户应用被包含在FSBL之内,采用上述的启动流程就可以运行。这里的好处就是,一旦进入到SRAM中的FSBL,则外部存储器可以完全移除或者断电,而且代码运行在内部sram中,速度也比较快。
但缺点是,FSBL被限制在512KB,除去1K的签名部分,只有511KB。如果用户代码大小超过了这个限制,就得另寻它法。除此之外,FSBL还抢占了宝贵的内部SRAM空间,虽然这个芯片宣称有4.2MB SRAM,但其中的2.2MB是直接挂载到NPU的,即CPU无法直接访问,可用的只有2MB,而FSBL的地址恰好在1~1.5 MB的位置,它将连续的2MB内存,切分成了两段。
此种模式是对前一种方式的优化,bootROM 从外部存储器获取FSBL,并加载到内部SRAM中运行,然后FSBL对外部存储器进行配置,并获取第二个存储在外部存储器的二进制文件(application code),并将它拷贝到内部SRAM。这第二个二进制文件加载完成之后,FSBL就跳转到SRAM的新位置执行(即application code所在SRAM的位置)。
这里的好处是,可以将applicaion搬到SRAM的任意合适位置,比如搬到SRAM末尾,这样就可以获得连续的1.5MB内存,灵活性很高。
这里有详细介绍: How to create an STM32N6 FSBL load and run
这里的不同点在于,在FSBL中直接将外部存储器配置为存储映射模式(Memory Mapped Mode),跳转到外部存储器application的代码地址进行执行。
这将彻底释放内部SRAM。此时,我们需要生成两个文件,一个是FSBL,可以把它视作bootloader,它必须包含有效的文件头或签名,烧录到外部存储器映射后的首地址;另一个是application,是用户代码,烧录到外部存储器的其他位置,只要不与FSBL重叠就行(推论一)。
参考 How to execute code from the external serial NOR using the STM32N6
分为以下几步执行:
Mode: Octo SPI
Port: Port2 Octo
Chip Select Override: NCS1 -- Port2 # 这里其实是要把CS端口设置为PN1,参考上述的芯片连线
Generic 配置项:
- Fifo Threshold: 4
- Memory Mode: Disable
- Memory Type: Micron
- Memory Size: 1 GBits
- Chip Select High Time Cycle: 1
- Free Running Clock: Disable
- Clock Mode: Low
- Wrap Size: Not Supported
- Clock Prescaler: 0
- Sample Shifting: None
- Delay Hold Quarter Cycle: Enable
- Chip Select Boundary: Disabled
- Maximum Transfer: 0
- Refresh Rate: 0
- Memory Select: NCS1
- Switching Duration Clock Number: 1
并在Middleware and Software Packs中配置ExtmemManager,在Runtime usage中勾选FSBL和子选项Active External Memory Manager。详细配置:
Boot:
- Select boot code generation: Enable (勾选)
- Selection of the boot system: Execute In Place
- Header size: 0x400
XIP:
- select the memory: Memory 1
- Application offset: 0x100000
- Application offset NS: 0x180000
在子选项卡Memory 1中:
Select driver
Select the memory driver EXTMEM_NOR_SFDP
Configuration
Memory Instance XSPI2
Number of memory data lines EXTMEM_LINK_CONFIG_8LINES
配置XSPI的时钟,参考文档中写的是50Mhz。
然后生成代码,编译成两个文件,分别在项目下寻找FSBL和Application文件夹,并在输出路径下寻找.bin文件。这里将它们拷贝到一个文件夹(C:\sign_n6),执行命令对这两个文件都进行签名:
C:\sign_n6> dir
>>>
2026/04/25 22:52 4,864 N657i0_ext_xip_AppliSecure.bin
2026/04/25 22:49 60,384 N657i0_ext_xip_FSBL.bin
..
# 执行签名:
C:\sign_n6>"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\STM32_SigningTool_CLI.exe" -bin C:\sign_n6\N657i0_ext_xip_FSBL.bin -nk -of 0x80000000 -t fsbl -o FSBL-trusted.bin -hv 2.3 -dump FSBL-trusted.bin -align
C:\sign_n6>"C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\STM32_SigningTool_CLI.exe" -bin C:\sign_n6\N657i0_ext_xip_AppliSecure.bin -nk -of 0x80000000 -t fsbl -o Appli-trusted.bin -hv 2.3 -dump Appli-trusted.bin -align
然后进行烧录,在cubeProgremer中选定下载算法,这里可以参考官方的N657x0-DK,然后在左侧栏选定下载按钮,勾选“校验编程”和“下载文件”,将:
将两个boot引脚拨到 0 0 的位置,让它从外部存储器加载,即可观察到启动过程,实测已成功。

XSPI2_BASE 为 0x70000000UL,这也就是从0x70000000烧录FSBL的原因。至于为什么Appli的偏移量是0x100000(0x70100000 - 0x70000000),该参考文档没有说明,这里足足有1MB的空间,而按照前面的分析,完全不需要偏移这么多。
查看了一下前面生成的FSBL的大小,大约是60KB,我们给它留128KB的空间,把application放在偏移128KB的位置即0x70020000,看看能否正常启动。当然这里要同步修改前面的ExtmemManager参数,将Application offset的值改成0x20000。事实证明,确实成功了,验证了我所想的,这个0x70100000是原作者随意设置的一个值,可能是随便找的一个整数而已。
在我按照教程逐步尝试的过程中,发现FSBL的代码可以正常执行,而Application却无法执行,在跳转之后,芯片像是死机一样不执行任何命令。我检查了所有参数,也排查了硬件问题,但都无果。
这里的区别在于,按照启动流程,FSBL是在SRAM中执行的,而Application是XIP在外部存储器执行,我怀疑是硬件问题导致XSPI总线的时钟无法支持到50Mhz的频率(实际上50M已经很低了),便采取降频策略再试,也无果。
在FSBL中的ErrorHandler中添加一些日志输出,发现压根没有进入到FSBL的ErrorHandler,而是在跳转之后发生的问题。这让我很头疼,查看Application的代码,才注意到以下关键几行:
// 在main.c中:
/* Secure SysTick should rather be suspended before calling non-secure */
/* in order to avoid wake-up from sleep mode entered by non-secure */
/* The Secure SysTick shall be resumed on non-secure callable functions */
HAL_SuspendTick();
/*************** Setup and jump to non-secure *******************************/
NonSecure_Init();
...
while (1) {
/* USER CODE BEGIN 3 */
...
}
在注释中,已经说明了HAL_SuspendTick等函数的用处,我心想可能是这两个函数,要么停了时钟,要么跳转到一个预期外的地址,导致程序死循环或者跑飞。注释掉这两个函数,故障解决,代码按照预期的方式正常运行了。
查阅了资料,关于Secure domain only(单域模式)的说明:
仅使用安全域,不启用 TrustZone 隔离。所有代码和资源都在安全侧运行,整个芯片作为一个整体项目开发。这类似于传统的单片机开发模式,开发流程简单直接,适合不需要复杂安全隔离的应用场景
所以,作为个人开发者或者业余爱好者,完全可以不使用TrustZone。
此次打了两块板子,其中一块板子(即用于验证的这块)可以正常跑通代码,没有什么异常之处。但另一块板子可以烧录程序,却无论如何也点不亮LED灯。仔细观察,发现用于产生VDD3V3的TPS62088YFP芯片貌似碎了一角(很轻微),用手摸了一下芯片,十分烫手。测量其电压,只有0.8V,而原本它会继续降压产生1V8给Flash芯片和部分io供电,测量这一路电压,也只有0.8V。
推测可能是TPS62088YFP已损坏,也可能是主芯片或者某个电容大短路,或者其它原因。
精力有限,此问题暂时搁置。
这里已经验证完了这块板的flash部分,也宣告了硬件设计上基本成功了。今天以后它将彻底沦为收藏品,我是不愿意再用它了,除非特殊情况。
槽点有很多,首先它的硬件复杂,需要5路电源并且有启动时序,与普通MCU的复杂程度完全不在一个级别,它更像是一个MPU阉割的产物。其次启动复杂,没有内部Flash,无论是创建项目、下载还是调试,都极为不便,尤其是在外部flash上断点调试,堪称地狱。最后,st主推的Model Zoo和CUBEAI的生态,也有很多问题,环境配置极其复杂,很多都需要版本强绑定,而且硬件支持有限,甚至很多模型下载下来还要做大量修改才能跑通,这对于一个业余爱好者来讲,每一条都足够劝退了。MCU还是不能让它脱离逻辑控制的主战场,真要高性能计算的场景,不如上MPU。总的来说,N6还是太鸡肋了。
这对以后选择折腾的对象提供了参考意义,应当把有限的精力放在关键地方,毕竟人生苦短。