你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【NUCLEO-H5E5ZJ评测】M.2存储扩展实测

[复制链接]
xusiwei1236 发布时间:2026-11-3 00:55

【NUCLEO-H5E5ZJ评测】M.2存储扩展实测

系列第 2 篇。上一篇《CoreMark移植实录》在板上跑通了 CPU 性能基线,这一篇给板子"插上一块 64MB 外置闪存"——用 ST 官方的 M.2 存储套件,把 XSPI 八线总线的真实性能、稳定工作边界、甚至"从外部 NOR 执行代码"的代价,全部用数据说话。

一、准备工作

1.1 存储套件简介

本文使用的扩展硬件是 ST 的 B-M2MEM-PACK1 套件——五块 M.2 串行存储子板,覆盖不同厂商、容量、电压与总线方案:

板卡 器件 类型 容量 电压 最高时钟 总线
MB1927-33BA Macronix MX25LM51245G Octal NOR 512 Mbit(64 MB) 3.3 V 200 MHz 1/8 线 STR+DTR
MB1927-18BA Macronix MX25UW25645G Octal NOR 256 Mbit 1.8 V 200 MHz 1/8 线 STR+DTR
MB1928-33LA ISSI IS25LP032D Quad NOR 32 Mbit 3.3 V 133 MHz 1/2/4 线 STR
MB1928-33LB Winbond W25Q16JV Quad NOR 16 Mbit 3.3 V 133 MHz 1/2/4 线 STR
MB1928-18LA ST M95P32 EEPROM 32 Mbit 1.8 V 80 MHz 1 线 STR

每块板都带 128Kbit I2C 识别 EEPROM、一颗由主控 GPIO 控制开关的 LDO(负责存储器的上电/断电复位)、红绿双 LED 和可供自行换料的空焊盘。

本文只测 MB1927-33BA,选它的理由很直接:

  • NUCLEO-H5E5ZJ 的 M.2 插槽 VDDIO 固定 3.3V,两块 18xx(1.8V)板不能直接用——模组上的 LDO 只转换存储器供电,信号线没有电平转换,详见 1.2 节的原理图查证;
  • 它是套件里唯一支持**八线 + DTR(双沿采样)**的模组,是五块中理论读写性能最高的(8 位总线 @200MHz,理论带宽远超 Quad NOR 的 66 MB/s);
  • 容量最大(64MB),足够玩文件系统镜像和代码外置。

一个容易被搞混的点:512 Mbit = 64 MB。存储行业标容量用 Mbit,写吞吐用 MB/s,单位差 8 倍,读数据时留意。

1.2 M.2 接口定义

NUCLEO-H5E5ZJ 板背面有一颗 M.2 Key A 连接器(CN19),专用于外扩串行存储,接到片上 XSPI1 接口。查 UM3601 的引脚表可以得到完整映射(八线一组信号全齐,含 DQS 和 NCLK):

功能 M.2 引脚 MCU 引脚
CLK / NCLK 41 / 43 PF10 / (NCLK 板上已引出,DTR 模式用 DQS 采样,例程未配置)
DQS 25 PB2
NCS 20 PB10
D0~D7 35/37/43…67 PD11、PD12、PF7、PD13、PE7、PD5、PD6、PC0
LDO_EN 18 PG5
LED1/LED2 42 / 38 —

两个必须知道的"坑":

配置坑点总结——上手前先核对两点:

  • M.2 Key A 是 ST 私有引脚(规范见 TN1618)。虽然形状上和标准 M.2 设备兼容,但 UM3611 明确警告:不要把第三方 M.2 设备(WiFi 卡之类)插进这个槽,电气定义不同,可能损坏双方硬件;
  • 电压必须匹配:33xx 板 3.3V、18xx 板 1.8V,主控侧 IO 电平必须与模组一致。一个常见的疑问是"18xx 板上不是有 LDO 吗?"——翻 MB1927 官方原理图可以看清楚:板载 LDO 把 M.2 送来的 3V3 转成 1.8V,只给存储器芯片供电;OCTOSPI 的 CLK/DQS/IO0-7/NCS 信号线从连接器经串联电阻直连存储器(全板唯一的电平转换器 MAX13046 只管复位和 I2C 侧信号)。于是 18xx 板要求主机 VDD 也是 1.8V:正向 3.3V 驱动超过 1.8V 器件的绝对最大额定(约 2.2V),反向 1.8V 输出又低于 3.3V IO 的 VIH(约 2.31V),双向都不成立。而 NUCLEO-H5E5ZJ 的电源树只有 3.3V 档(UM3601 无 1.8V VDD 选项),所以本板只认 33xx。

1.3 器件特性概览

MX25LM51245G 是 Macronix 的 OctalFlash,关键参数:

  • 容量 64MB,页 256B,擦除粒度 4KB/32KB/64KB;
  • 两种工作模式:1 线 SPI(上电默认,兼容传统命令集)和 8 线 OPI(STR 最高 133MHz / DTR 最高 200MHz);
  • 模式切换靠 Configuration Register 2(CR2)里的 DOPI 位——易失,断电即回到 SPI 模式;
  • OPI 读命令 0xEE11(DTR 指令对),20 个 dummy 周期,DQS 采样;
  • 换算成理论带宽:8 线 DTR @133MHz ≈ 8bit × 2 沿 × 133M = 266 MB/s 的引脚级上限。

后文的实测会回答:这个 266 MB/s 离实际有多远。

二、硬件连接

2.1 模组安装

断电状态下把 MB1927-33BA 插入板背面 CN19(金手指有方向,Key A 缺口对准),拧上 M.2 固定螺丝即可。无任何跳线——33BA 与主板电压天然匹配。

2.2 XSPI 引脚分配

工程用 STM32CubeMX 配置:Pinout 里把 OCTOSPI1 设为 Octo 模式,按 1.2 节映射把 11 个信号分配到对应引脚(CubeMX 会自动给出 AF10_OCTOSPI1 复用),NCS 用 NCS1。

CubeMX 引脚配置总览——彩色高亮为 XSPI1 八线组 + DQS/NCS

外设参数页(Connectivity → OCTOSPI1)的配置:

CubeMX OCTOSPI1 参数配置——Octo 模式与 Macronix 器件参数

对应生成的关键初始化参数:

hxspi1.Init.MemoryType          = HAL_XSPI_MEMTYPE_MACRONIX;
hxspi1.Init.MemorySize          = HAL_XSPI_SIZE_512MB;  /* 32 位地址模式 */
hxspi1.Init.ChipSelectHighTimeCycle = 10;
hxspi1.Init.ClockPrescaler      = 0;                    /* 内核时钟不分频 */
hxspi1.Init.DelayBlockBypass    = HAL_XSPI_DELAY_BLOCK_ON; /* 使能 DLYB 延时块 */

注意 HAL_XSPI_SIZE_512MB 的含义是"32 位寻址",不是容量——OPI 模式下地址固定 32 位,必须这么配。

2.3 时钟配置

CPU 侧沿用系列第一篇的满频配置:板载 HSE 48MHz 晶振经 PLL1(÷M12 ×N125 ÷P2,VCO 500MHz)倍频到 250MHz,内核电压档 VOS0、Flash 等待级 5,AHB 与三条 APB 总线全部同频满速——这套链路决定了 DWT 计时基准和 CPU 轮询类测试的上限。

CPU 时钟链路——HSE 48MHz 经 PLL1(÷M12 ×N125 ÷P2)倍频至 250MHz SYSCLK

XSPI1 的内核时钟则不挂在主 PLL 上,走独立的 PLL2:HSE 48MHz ÷ M24 × N100 ÷ R4 = 50MHz 作为初始化频率(器件默认 1 线 SPI 模式下的安全频率),OCTOSPI1 的内核时钟源在时钟树的 Kernel Clocks 里选择 PLL2R。独立时钟链的好处是变频互不牵连:调整 XSPI 频率完全不动 CPU 与总线时钟,4.1 节的频率扫描就靠它在运行中逐档重配 PLL2 并重整定 DLYB。

CubeMX 时钟树——PLL1(M12/N125/P2→250MHz 主频)与 PLL2(M24/N100/R4→50MHz XSPI 内核时钟)

2.4 上电与复位控制

模组上的存储器由 LDO 供电,LDO 使能脚(PG5)接主控。上电时序有讲究:

/* MX_GPIO_Init 的 USER CODE 区(必须先于 XSPI 初始化执行) */
HAL_GPIO_WritePin(LDO_M2_Slot_GPIO_Port, LDO_M2_Slot_Pin, GPIO_PIN_RESET);
HAL_Delay(10);    /* LDO 关断保持——对存储器做一次冷复位 */
HAL_GPIO_WritePin(LDO_M2_Slot_GPIO_Port, LDO_M2_Slot_Pin, GPIO_PIN_SET);
HAL_Delay(200);   /* LDO 输出稳定 */

坑点实录:这套"先断电再上电"的冷复位必须放在 XSPI 初始化之前。因为 XSPI 初始化里有一步 DLYB(延时块)标定,需要存储器已经供电、DQS 链路正常。我第一次把 LDO 上电放在了 XSPI 初始化之后,结果初始化就出错。

冷复位还有一个重要用途:器件的 CR2 寄存器(八线模式配置)是易失的。任何时刻想让它回到已知的 SPI 模式,断一次电就行——后文的测试固件里 reset 命令就是这个原理。

三、驱动配置

3.1 XSPI 初始化配置

驱动直接复用 ST 固件包的 MemoryToolbox(Projects/NUCLEO-H5E5ZJ/Examples/XSPI/XSPI_MemoryToolbox_M2_MX25LM51245G),它把 MX25LM51245G 的命令层封装成了现成函数:读 JEDEC/SFDP、读写寄存器、擦除、页编程、间接读、memory-mapped 使能/退出,全部带超时和轮询。memory_toolbox.h 通过宏选择器件(M2_MX25LM51245G),换成套件里其他模组只需换宏和对应的头文件。

初始化阶段的 DLYB 标定(决定 DQS 采样相位)照抄例程:

HAL_XSPI_DLYB_CfgTypeDef cfg = {0};
HAL_XSPI_DLYB_GetClockPeriod(&hxspi1, &cfg);  /* 实测输入时钟对应的延时刻度 */
cfg.PhaseSel /= 4;                            /* 采样点取 1/4 周期 */
HAL_XSPI_DLYB_SetConfig(&hxspi1, &cfg);

3.2 器件识别验证

上电默认是 1 线 SPI 模式,第一件事读 JEDEC ID:

[M2] 1. JEDEC ID (SPI 1-line)  : PASS (C2 85 3A)

C2 85 3A 与 Macronix MX25LM51245G 数据手册一致——模组、插槽、走线、命令时序整条链路通了。

3.3 八线模式切换

从 SPI 模式切到 Octal DTR 的完整序列(全部在 1 线 SPI 模式下完成寄存器操作,最后一条命令生效即切换):

  1. 写 CR(0x15/0x01)把驱动强度提到最高挡(24Ω);
  2. 写 CR2 @0x300 更新 OPI 读的 dummy 周期;
  3. 把 XSPI 内核时钟提到 133MHz(PLL2:N=133、R=2),并重配 DLYB;
  4. 写 CR2 @0x000 置位 DOPI——从这条命令起,器件按 8 线 DTR 应答;
  5. 用 8 线 DTR 方式读状态寄存器回读验证。

串口输出:

[M2] 3. Octal DTR @133MHz      : PASS

坑点实录:第 3 步"先提频、再重配 DLYB、最后切模式"的顺序不能乱。DLYB 的采样相位与频率强相关,例程在 133MHz 下用实测值 PhaseSel=1, Units=10。另外这一套序列在每次冷复位后都要重跑——CR2 断电即失。

3.4 读写通路验证

切到八线 DTR 后做一轮完整通路验证:擦一个 4KB 扇区 → 读回确认全 0xFF → 写一页 256B 伪随机 pattern → 读回比对 → memory-mapped 模式使能 → 用 memcpy 直读外部地址空间比对 → 退出。十步全部 PASS:

=============================================
[NUCLEO-H5E5ZJ-M2] M.2 bench (MB1927-33BA / MX25LM51245G)
MCU: STM32H5E5ZJ @ 250000000 Hz
XSPI kernel clock: 50000000 Hz
[M2] slot LDO on (PG5), memory cold-reset done
[M2] 1. JEDEC ID (SPI 1-line)  : PASS (C2 85 3A)
[M2] 2. Write enable check     : PASS
[M2] 3. Octal DTR @133MHz      : PASS
[M2] 4. Bench scratch ready    : PASS
---------------------------------------------
type 'help' for commands
>

到这里,测试台就绪了。固件实现了一个串口命令行(info / reset / dtr / freq / rd / mm / mmr / wr / erase / xip),配一个 pyserial 脚本逐条发送、等 > 提示符同步,后续所有数据都是这样"现场驱动"出来的。

cmd 中用 pyserial 驱动测试台:一套命令跑完读/写/擦/XIP 全部性能项

四、性能实测

计时统一用 DWT 周期计数器(250MHz 主频),读测试累计 8MB、写/擦按区域实测,每个稳定档都带 pattern 回读比对。

4.1 频率稳定包络

先回答最关键的问题:这套硬件能跑多快? 用 freq 命令逐档提频(PLL2 动态分频 + DLYB 自整定 + pattern 校验),实测结果:

XSPI 频率 读吞吐(memmap) 随机页延迟 判定
50 MHz 1.56 MB/s 164 µs/页 稳定
66 MHz 2.01 MB/s 127 µs/页 稳定
100 MHz 2.89 MB/s 88 µs/页 稳定(推荐)
133 MHz 3.68 MB/s 69 µs/页 边缘:boot 稳定性自检 FAIL→复测又 PASS
166 MHz — — 总线事务挂死
200 MHz — — 挂死

133MHz 是数据手册标称值,但实测处于临界状态:同一份代码、同一频率,boot 时三次 64KB 读校验偶发失败。固件因此做了一个自适应机制——boot 自检 memmap 连续读三遍,不稳就自动降档:

[M2] 5. memmap stability @133000 kHz : FAIL
[bench] DLYB tuned: Units=10 PhaseSel=1
[bench] XSPI kernel: 100000 kHz (PLL2 N=100 R=2, VCO=200000 kHz)
[M2] 5. memmap stability @100000 kHz : PASS

结论:官方标称 133MHz,这块板上稳稳当当能跑的是 100MHz。M.2 连接器 + 板级走线引入的信号完整性代价,数据手册不会告诉你。166MHz 起连事务都完不成(HAL 等标志超时循环),200MHz 同样。

4.2 读吞吐对比

两种读路径、两种粒度,在 100MHz 稳定档下的对比:

读方式 吞吐 64KB 耗时 说明
间接轮询(HAL FIFO 轮询) 4.30 MB/s 19.5 ms 与 XSPI 频率无关
memory-mapped(memcpy 直读) 2.89 MB/s 28.9 ms 与频率成正比
memory-mapped 随机 256B 页 88 µs/页 — 延迟视角

两个反直觉的现象,根因都在"谁在等谁":

  • 间接轮询 4.30 MB/s 恒定不变(50MHz 与 133MHz 一模一样)——瓶颈根本不在总线,而在 CPU:HAL 逐 4 字节轮询 FIFO 标志,每 4 字节花掉约 240 个 CPU 周期。总线越快,CPU 白等越多;
  • memory-mapped 吞吐严格正比于频率(1.56 → 2.01 → 2.89 → 3.68 MB/s 对应 50/66/100/133MHz)——CPU 每次从外部地址空间 load 32 位,XSPI 都要重付一整笔事务开销(指令 + 32 位地址 + 模式字节 + 20 dummy ≈ 137 个时钟),数据传输本身只占 16 个时钟。固定开销吃掉了 90% 的带宽。

理论 266 MB/s 与实测个位数 MB/s 之间的差距,就这样一层层摊开了:在 Cortex-M33 上用 CPU 逐字读外置 NOR,事务开销才是天花板。想逼近带宽上限的路径只有两条:让 CPU 一次取更多字节(突发 load/DMA),或干脆用 MDMA 搬运——这是下一篇玩 DMA 时的事了。

4.3 页编程写入

页编程(256B/页,含写使能、命令、轮询 WIP 的完整周期):

[wr] region 64 KB: erase=352 ms, program=50 ms
[wr] program throughput : 1.29 MB/s

约 190 µs/页,折合 1.3~1.4 MB/s。数据手册标称页编程时间(典型 150µs 量级)占比不小,加上每页一次写使能 + WIP 轮询的往返,这就是 NOR 顺序写的真实速率——比读慢,但符合器件特性。

4.4 擦除与摊销

三种粒度的擦除实测(每种 4~16 次取平均,擦后 0xFF 校验全过):

粒度 平均耗时 等效速率
4KB 扇区 22 ms 183 KB/s
32KB 块 237 ms 137 KB/s
64KB 块 245 ms 266 KB/s

注意 32KB 与 64KB 的擦除时间几乎一样——大块擦除的耗时主要由器件内部操作决定,能一次擦大块就不要拆成多个小扇区。

把擦除摊进写入,得到"有效写吞吐":写满 1MB ≈ 擦除 3.4s + 编程 0.8s ≈ 0.16 MB/s。这个数字适合拿来对比 SD 卡篇——NOR 的定位是"随机小块读写 + 掉电可靠",不是顺序大容量吞吐。

五、外置执行

5.1 XIP 执行方案

XSPI 支持 memory-mapped,意味着外部 NOR 的内容对 CPU 来说就是普通内存——代码也能放进去原地执行(XIP)。为了量化这件事,固件做了个专门实验:

  • 链接脚本增加一个 .xip_code 段:VMA 在 OCTOSPI 地址空间(0x90000000),LMA 在内部 Flash——即编译时链接到外部地址、但镜像随固件存放在内部 Flash;
  • 被测函数是一个自包含的 CRC32(叶函数,无外部调用),整段仅 48 字节;
  • xip 命令流程:擦 NOR 扇区 → 把镜像从 Flash LMA 搬进 NOR → 使能 memory-mapped → 同一段机器码分别以两个地址作为函数指针执行 64KB 数据的 CRC,各跑四轮,ICACHE 开/关各测一组。
/* 链接脚本:代码段 VMA 在外部 NOR,装载镜像存内部 Flash */
.xip_code : { _xip_vma_start = .; KEEP(*(.xip_code)) _xip_vma_end = .; } >XSPI AT>FLASH

/* 双址执行:同一段机器码,两个入口 */
fn_flash = (XipFn_t)((uint32_t)_xip_lma_start | 1U);              /* 内部 Flash 副本 */
fn_xip   = (XipFn_t)((uint32_t)(OCTOSPI1_BASE + nor_base) | 1U);  /* 外部 NOR 原址 */

5.2 同码异址对照

实测结果(100MHz DTR):

执行位置 ICACHE 关 ICACHE 开
内部 Flash 195.28 ms 66.06 ms(3.0× 加速)
外部 NOR XIP 1226.35 ms 1226.23 ms
NOR 执行代价 6.28× 18.56×

CRC 四组全等(313C74FE),外部执行的功能正确性没有问题。但性能数据把话说得很清楚:

  • ICACHE 关:外部执行慢 6.28 倍——每条指令取指都是一笔 XSPI 事务(137 时钟起步),按位循环每处理 1 字节数据要取 10~20 条指令,取指开销全面碾压执行本身;
  • ICACHE 开:内部 Flash 被缓存后快了 3 倍(195→66ms),但外部 NOR 的耗时纹丝不动——实测 ICACHE 不缓存外部 NOR 的取指。这算本次测评最意外的发现:文档上 ICACHE 名义上可覆盖外部存储,实测在这个配置下并没有。

结论一句话:这块外置 NOR 适合放数据、资源、文件系统镜像;XIP 放冷代码可以(省内部 Flash),放热代码等于自降 6~19 倍主频。原计划"把 CoreMark 搬进 NOR 跑分"因此取消——在量级差距面前,跑分没有信息量,函数级对照已经把结论钉死了。

六、结果讨论

6.1 实测数据汇总

MB1927-33BA(MX25LM51245G @ NUCLEO-H5E5ZJ XSPI1,Octal DTR,100MHz 稳定档):

项目 实测 对照
读(memory-mapped,顺序) 2.89 MB/s 引脚理论 200 MB/s @100MHz DTR
读(间接轮询) 4.30 MB/s CPU 轮询瓶颈,与频率无关
随机 256B 页读延迟 88 µs 含每访问 ~137 时钟固定开销
页编程(256B) 1.3~1.4 MB/s 含写使能与 WIP 轮询
擦除 4KB / 32KB / 64KB 22 / 237 / 245 ms 大块擦除耗时近似
有效写吞吐(含擦除摊销) 0.16 MB/s 1MB 擦+写实测
XIP 执行 6.28×(18.56×)慢于内部 Flash 同码异址,ICACHE 开/关
稳定频率包络 ≤100 MHz 133 边缘,≥166 挂死

6.2 选型与使用建议

给打算在这块板上用 M.2 存储扩展的朋友几条落地建议:

  1. 频率设 100MHz,别贪 133——把 boot 自检(连续大块读校验)写进初始化,不稳自动降档,比 hardcode 一个频率可靠得多;
  2. 读数据优先 memory-mapped + 大块搬运,小粒度随机读要有延迟预算(百 µs 级);想突破单字 load 的开销天花板,用 MDMA 或让 CPU 发突发访问;
  3. 写全按页编程走,跨页写必须拆页;擦除按最大可用块来,32KB 和 4KB 耗时差 10 倍但吞吐反而更高;
  4. 代码放内部 Flash,数据放外部 NOR——除非你想体验 6 倍减速的 XIP;
  5. 每次冷复位(或掉电)后记住:器件回到 SPI 模式,八线切换序列要重跑。

七、参考资料

  • B-M2MEM-PACK1 用户手册(UM3611):模组清单、M.2 Key A 引脚、LDO/LED/焊桥
  • NUCLEO-H5E5ZJ 用户手册(UM3601):CN19 → XSPI1 引脚映射
  • TN1618:ST M.2 串行存储接口规范(私有引脚警告的出处)
  • Macronix MX25LM51245G 数据手册:命令集、时序、CR/CR2 寄存器
  • STM32Cube_FW_H5 固件包 XSPI_MemoryToolbox_M2_MX25LM51245G 例程(驱动基座)
  • 本篇工程与全部实测数据:https://gitcode.com/xusiwei1236/STM32H5E5-M2-Code(代码,含阶段化提交记录)与 STM32H5E5-M2-Test(测试记录与串口日志)
赞 1 收藏 1 评论0 发布时间:2026-11-3 00:55

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版