尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32H750XB 驱动 MR25H40CDF MRAM 实战:SPI 接口配置与工业数据存储

STM32H750XB 驱动 MR25H40CDF MRAM 实战:SPI 接口配置与工业数据存储 1. 为什么 MRAM 在嵌入式存储里越来越受关注搞嵌入式存储的兄弟应该都有体会选型的时候翻来覆去就那么几类EEPROM 擦写寿命长但容量小、速度慢NOR Flash 读取快但写入前必须擦除还得整块整块地擦NAND Flash 容量大便宜可坏块管理和 ECC 校验能把人折腾疯FRAM 读写快寿命也长但容量和价格一直是个坎。这几年 MRAM磁性随机存储器慢慢进入大家的视野尤其是像 MR25H40CDF 这种 SPI 接口的 4Mbit MRAM 芯片在工业现场和嵌入式数据记录场景里出现得越来越多。MR25H40CDF 是 Everspin 家的 SPI 非易失性 MRAM4Mbit 容量也就是 512KB支持 40MHz SPI 时钟工作电压 2.7V 到 3.6V工业级温度范围 -40°C 到 85°C。它最大的特点就是写入不需要擦除、写入速度接近 SRAM、擦写寿命几乎无限官方标称 10^14 次以上、数据保持时间超过 20 年。这几个特性放在一起基本上把传统存储方案的痛点全给覆盖了。STM32H750XB 则是 ST 家的高性能 Cortex-M7 系列 MCU480MHz 主频带 128KB Flash 和 1MB RAM外设资源丰富SPI 接口有好几路其中 SPI1 和 SPI4 支持高达 100MHz 的时钟。拿它来驱动 MR25H40CDF性能上完全不会有瓶颈而且 H750 的缓存和 DMA 机制能让 SPI 读写效率拉满。这套组合适合什么人做工业数据采集的、做电力监控终端的、做车载记录仪的、做医疗设备日志存储的还有那些需要在断电瞬间把关键数据写进去的场景。如果你正在用 EEPROM 或者 Flash 做频繁写入的数据记录被擦写寿命和写入延迟折磨过那这套方案值得认真看看。2. 整体方案设计与选型思路拆解2.1 为什么选 MRAM 而不是 EEPROM 或 Flash先算一笔账。假设你有一个工业采集设备每秒要记录一次传感器数据每次记录 32 字节一天就是 86400 次写入一年就是 3153 万次。EEPROM 的擦写寿命通常在 100 万次左右就算你做磨损均衡撑死也就几十万次每扇区一年下来早就超了。NOR Flash 更惨擦写寿命一般只有 10 万次而且写入前必须擦除整个扇区写入延迟动辄几毫秒到几十毫秒遇到断电的时候数据还没写完就丢了。MR25H40CDF 的写入机制完全不同。MRAM 的存储单元是磁性隧道结MTJ通过改变自由层的磁化方向来存储数据写入过程不需要擦除直接覆盖写就行。每次写入的延迟在几十纳秒级别整个 SPI 事务的时间主要花在传输上而不是存储单元操作上。擦写寿命 10^14 次按每秒写一次算能写 300 多万年。这个数字看着夸张但确实解决了频繁写入场景的核心痛点。还有一个容易被忽略的点MRAM 的写入功耗比 EEPROM 和 Flash 低得多。EEPROM 写入时需要电荷泵升压Flash 擦除时需要高压这些都会带来额外的功耗和噪声。MRAM 写入只需要很小的电流翻转磁化方向在电池供电或者能量收集的场景里优势明显。2.2 SPI 接口选型与硬件连接考量MR25H40CDF 支持标准 SPI 模式 0 和模式 3最高时钟 40MHz。STM32H750XB 的 SPI1 挂在 APB2 总线上最高时钟可以到 100MHzSPI4 挂在 APB2 上也能到 100MHz。实际用的时候40MHz 的 SPI 时钟对 H750 来说很轻松但要注意 PCB 布线和信号完整性问题。硬件连接上MR25H40CDF 的引脚定义很标准CS片选、SCK时钟、SI数据输入、SO数据输出、WP写保护、HOLD保持。WP 和 HOLD 这两个引脚在标准 SPI 模式下可以不用但建议把 WP 拉高、HOLD 拉高避免误触发。CS 引脚建议用硬件片选也就是接到 SPI 外设的 NSS 引脚上这样时序最干净。如果 IO 不够用软件片选也行但要注意在 SPI 事务前后手动控制 CS 的拉低和拉高中间不能被打断。电源方面MR25H40CDF 的 VDD 范围是 2.7V 到 3.6V典型值 3.3V。去耦电容建议在芯片电源引脚旁边放一个 0.1uF 的陶瓷电容再并一个 1uF 的钽电容或者陶瓷电容位置越近越好。SPI 信号线上如果走线比较长可以串 22Ω 到 33Ω 的电阻做阻抗匹配减少过冲和振铃。2.3 STM32H750XB 的 SPI 外设配置策略STM32H750XB 的 SPI 外设功能很强支持 TI 模式、Motorola 模式、硬件 CRC、FIFO、DMA 请求等。驱动 MR25H40CDF 只需要用到最基本的 Motorola SPI 模式配置成主机、全双工或者半双工都行。关键参数有这么几个时钟极性CPOL和时钟相位CPHAMR25H40CDF 支持模式 0CPOL0CPHA0和模式 3CPOL1CPHA1。建议用模式 0因为大多数 SPI 从设备都支持模式 0兼容性最好。数据大小8 位。波特率预分频SPI1 挂在 APB2 上假设 APB2 时钟 100MHz预分频设为 4 就是 25MHz设为 2 就是 50MHz。MR25H40CDF 最高 40MHz所以预分频至少设为 425MHz或者 250MHz 超了不行。实际用 25MHz 就很稳需要更快的话可以试试 33MHz 左右但要看 PCB 质量。NSS 管理用硬件 NSS 的话配置成输出模式由 SPI 外设自动控制。用软件 NSS 的话把 NSS 配置成 GPIO 输出手动拉低拉高。FIFO 阈值H750 的 SPI 有 16 字节 FIFO读写的时候可以利用 FIFO 减少中断次数提高效率。用 STM32CubeMX 配置的话选 SPI1模式选 Full-Duplex Master硬件 NSS 选 Disable用软件片选然后手动配置 GPIO 作为 CS 输出。这样最灵活也方便调试。3. MR25H40CDF 的核心指令与操作细节3.1 指令集解析与常用命令MR25H40CDF 的指令集和标准 SPI Flash 很像但简化了不少。常用的指令有这么几条指令名称指令码功能说明时钟字节数WREN0x06写使能1WRDI0x04写禁止1RDSR0x05读状态寄存器11WRSR0x01写状态寄存器11READ0x03读数据13NWRITE0x02写数据13NRDID0x9F读设备 ID13和 Flash 最大的区别是MRAM 没有扇区擦除指令也没有页编程的概念。写入的时候直接发 WRITE 指令跟上 24 位地址然后连续写数据就行。地址会自动递增写到芯片末尾会自动回卷到开头。这个特性用起来很舒服不需要像 Flash 那样先擦后写也不需要管理扇区边界。状态寄存器里主要关注 WEL写使能锁存和 WIP写进行中两个位。WEL 在发完 WREN 之后置 1写完数据之后自动清零。WIP 在写入过程中为 1写完之后变 0。实际用的时候WREN 之后不需要等 WIP因为 MRAM 写入速度极快SPI 传输完数据基本上就写完了。但保险起见可以在写入后读一下状态寄存器确认 WIP 为 0。3.2 读写时序与关键参数计算读操作的时序很简单CS 拉低发 0x03发 24 位地址高字节在前然后开始读数据每个 SCK 上升沿输出一位。地址可以连续递增读到最后自动回卷。整个读操作期间 CS 必须保持低电平。写操作的时序CS 拉低发 0x06WRENCS 拉高。然后再 CS 拉低发 0x02WRITE发 24 位地址然后发数据。数据在 SCK 上升沿被采样。写完之后 CS 拉高数据真正写入存储单元。注意 WREN 和 WRITE 之间 CS 必须拉高一次这是 MRAM 的要求和 Flash 一样。时序参数方面MR25H40CDF 的关键时间参数如下SCK 时钟频率最高 40MHz对应周期 25ns。CS 建立时间tCSS最小 5ns。CS 保持时间tCSH最小 5ns。数据输出有效时间tV最大 8ns。写周期时间tWC最大 15ms不对MRAM 没有写周期等待写入是即时的。实际上 MR25H40CDF 的写入时间就是 SPI 传输时间没有额外的内部写周期。这里要特别说明一下很多 Flash 的数据手册里会标一个 tWC写周期时间通常是几毫秒意思是发完写指令后要等这么久数据才真正写进去。MRAM 没有这个概念发完数据就写完了不需要等待。这是 MRAM 相比 Flash 的一个巨大优势在断电场景下尤其重要。3.3 状态寄存器与写保护机制MR25H40CDF 的状态寄存器有 8 位但只有低几位有意义bit0WIPWrite In Progress写入进行中标志。bit1WELWrite Enable Latch写使能锁存。bit2 到 bit7BP0 到 BP3不对MR25H40CDF 的块保护位是 BP0 和 BP1还有 SRWD 位。具体来说状态寄存器 bit2 是 BP0bit3 是 BP1bit7 是 SRWDStatus Register Write Disable。BP0 和 BP1 用来设置块保护范围可以保护 1/4、1/2 或者整个存储阵列不被写入。SRWD 和 WP 引脚配合使用可以硬件锁定状态寄存器。实际用的时候如果不需要块保护把 BP0 和 BP1 都设成 0SRWD 设成 0这样整个存储阵列都可写。如果需要保护一部分数据不被误写可以设置 BP0 和 BP1。比如 BP10BP01 的时候保护高 1/4 地址空间。这个功能在固件升级或者参数存储场景里挺有用。写状态寄存器之前也要先发 WREN然后发 WRSR 指令和状态数据。写完状态寄存器之后WEL 会自动清零。4. STM32H750XB 驱动 MR25H40CDF 的完整实现4.1 硬件初始化与 GPIO 配置先搞定硬件初始化。用 STM32CubeMX 生成代码的话SPI1 的配置大概是这样hspi1.Instance SPI1; hspi1.Init.Mode SPI_MODE_MASTER; hspi1.Init.Direction SPI_DIRECTION_2LINES; hspi1.Init.DataSize SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity SPI_POLARITY_LOW; hspi1.Init.CLKPhase SPI_PHASE_1EDGE; hspi1.Init.NSS SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler SPI_BAUDRATEPRESCALER_4; hspi1.Init.FirstBit SPI_FIRSTBIT_MSB; hspi1.Init.TIMode SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial 7; hspi1.Init.CRCLength SPI_CRC_LENGTH_DATASIZE; hspi1.Init.NSSPMode SPI_NSS_PULSE_DISABLE;CS 引脚用 GPIO 控制配置成推挽输出初始状态拉高。假设 CS 接在 PA4 上GPIO_InitStruct.Pin GPIO_PIN_4; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);SPI 的 SCK、MISO、MOSI 引脚配置成复用推挽速度设成 Very High。H750 的 GPIO 速度等级对 SPI 高速通信影响很大设低了波形会变差。4.2 底层读写函数封装先封装几个基础函数CS 控制、SPI 单字节收发、状态寄存器读写。#define MRAM_CS_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET) #define MRAM_CS_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET) static uint8_t mram_spi_transfer(uint8_t tx_data) { uint8_t rx_data; HAL_SPI_TransmitReceive(hspi1, tx_data, rx_data, 1, HAL_MAX_DELAY); return rx_data; } static void mram_write_enable(void) { MRAM_CS_LOW(); mram_spi_transfer(0x06); MRAM_CS_HIGH(); } static uint8_t mram_read_status(void) { uint8_t status; MRAM_CS_LOW(); mram_spi_transfer(0x05); status mram_spi_transfer(0xFF); MRAM_CS_HIGH(); return status; }这几个函数是后面所有操作的基础。注意mram_spi_transfer用的是HAL_SPI_TransmitReceive全双工模式发一个字节的同时收一个字节。如果只发不收可以用HAL_SPI_Transmit但全双工更通用。4.3 数据写入与读取的完整流程写数据的函数void mram_write(uint32_t addr, uint8_t *data, uint32_t len) { mram_write_enable(); MRAM_CS_LOW(); mram_spi_transfer(0x02); mram_spi_transfer((addr 16) 0xFF); mram_spi_transfer((addr 8) 0xFF); mram_spi_transfer(addr 0xFF); for (uint32_t i 0; i len; i) { mram_spi_transfer(data[i]); } MRAM_CS_HIGH(); }读数据的函数void mram_read(uint32_t addr, uint8_t *data, uint32_t len) { MRAM_CS_LOW(); mram_spi_transfer(0x03); mram_spi_transfer((addr 16) 0xFF); mram_spi_transfer((addr 8) 0xFF); mram_spi_transfer(addr 0xFF); for (uint32_t i 0; i len; i) { data[i] mram_spi_transfer(0xFF); } MRAM_CS_HIGH(); }这两个函数已经能完成基本的读写操作了。但实际用的时候有几个优化点第一地址是 24 位的MR25H40CDF 的容量是 512KB地址范围 0x000000 到 0x07FFFF。地址超过 0x07FFFF 会自动回卷所以写的时候要注意不要越界。第二连续读写的时候可以用 DMA 来搬数据减少 CPU 占用。H750 的 SPI1 支持 DMA 请求配置好 DMA 通道之后HAL_SPI_TransmitReceive_DMA可以直接把数据搬完CPU 可以去干别的事。第三如果写入的数据量比较大可以分多次写每次写一页或者一个块。MRAM 没有页的概念但分块写便于管理也方便出错重试。4.4 DMA 加速与性能优化用 DMA 的话SPI 的配置需要改一下把 DMA 请求打开。在 CubeMX 里配置 SPI1 的 TX 和 RX DMA 通道然后代码里这样用void mram_read_dma(uint32_t addr, uint8_t *data, uint32_t len) { uint8_t cmd[4]; cmd[0] 0x03; cmd[1] (addr 16) 0xFF; cmd[2] (addr 8) 0xFF; cmd[3] addr 0xFF; MRAM_CS_LOW(); HAL_SPI_Transmit(hspi1, cmd, 4, HAL_MAX_DELAY); HAL_SPI_Receive_DMA(hspi1, data, len); // 等待 DMA 完成 while (hspi1.State ! HAL_SPI_STATE_READY); MRAM_CS_HIGH(); }注意 DMA 接收的时候CS 必须在 DMA 完成之后才能拉高否则数据会不完整。可以用 DMA 传输完成回调函数来拉高 CS这样更可靠。实测下来用 DMA 读 512KB 数据SPI 时钟 25MHz大概需要 170ms 左右。如果用 40MHz大概 105ms。这个速度在嵌入式场景里已经很快了比 EEPROM 的读写速度快了几个数量级。5. 实际项目中的常见问题与排查技巧5.1 SPI 通信失败的典型原因SPI 调不通是最常见的问题尤其是第一次画板子的时候。按我的经验排查顺序应该是这样的先看电源。MR25H40CDF 的 VDD 必须在 2.7V 到 3.6V 之间用万用表量一下芯片电源引脚确认电压正常。如果电压偏低检查去耦电容是不是没焊好或者电源走线太细导致压降。再看 CS 信号。用示波器抓 CS 引脚确认在 SPI 事务期间 CS 确实被拉低了事务结束后又拉高了。如果 CS 一直低或者一直高检查 GPIO 配置和代码逻辑。然后看 SCK 和 MOSI。用示波器或者逻辑分析仪抓波形确认 SCK 有正常的时钟输出MOSI 上有数据变化。如果 SCK 没有波形检查 SPI 外设的时钟使能了没有GPIO 的复用功能配置对了没有。最后看 MISO。如果前面都正常但读出来的数据全是 0xFF 或者全是 0x00检查 MISO 引脚是不是接反了或者从设备根本没有响应。可以发一个 RDID 指令0x9F读回来的应该是 Everspin 的厂商 ID 和设备 ID。如果读回来不对那肯定是通信有问题。5.2 数据写入后读出来不对怎么办写入之后读出来数据不对通常有几种可能第一种WREN 没有发成功。MRAM 写入之前必须先发 WREN如果 WREN 没发或者发错了写入操作会被忽略。可以在写入后读状态寄存器的 WEL 位确认 WREN 是否生效。第二种CS 时序不对。WREN 和 WRITE 之间 CS 必须拉高一次如果 CS 一直保持低电平WREN 和 WRITE 会被当成一个事务写入会失败。这个坑我踩过当时调了半天才发现是 CS 控制的问题。第三种地址越界。MR25H40CDF 的地址范围是 0x000000 到 0x07FFFF如果写的地址超过这个范围数据会回卷写到开头覆盖掉原来的数据。写之前一定要检查地址范围。第四种写保护没解除。如果状态寄存器的 BP0 或 BP1 被设置了对应的地址区域会被保护写入操作会被忽略。读一下状态寄存器确认 BP0 和 BP1 都是 0。5.3 高速 SPI 下的信号完整性问题SPI 时钟跑到 25MHz 以上的时候信号完整性问题就开始显现了。常见的问题包括过冲和振铃。SCK 和 MOSI 的上升沿和下降沿如果有明显的过冲会导致从设备误判。解决办法是在信号线上串 22Ω 到 33Ω 的电阻位置尽量靠近驱动端。串扰。SPI 信号线如果和其他高速信号线平行走线会互相干扰。解决办法是 SPI 信号线之间保持足够的间距或者用地线隔离。反射。如果 SPI 走线比较长阻抗不匹配会导致反射。解决办法是控制走线阻抗一般单端 50Ω 左右差分 100Ω。SPI 是单端信号走线尽量短不要超过 10cm。实测下来25MHz 的 SPI 时钟在普通的 2 层板上跑 5cm 左右的走线问题不大但如果走线超过 10cm 或者板子上有其他高速信号最好还是用 4 层板SPI 信号线走在内层上下都有地平面参考。5.4 常见问题速查表现象可能原因排查方法解决办法读出来全是 0xFFMISO 没接好或从设备没响应检查 MISO 连线发 RDID 指令重新焊接或更换芯片读出来全是 0x00MISO 被拉低或 CS 没拉低检查 CS 信号和 MISO 电平修正 GPIO 配置写入后数据不变WREN 没发或写保护开启读状态寄存器 WEL 和 BP 位发 WREN清除 BP 位写入后数据错乱CS 时序不对或地址越界抓 CS 波形检查地址范围修正 CS 控制检查地址高速时数据出错信号完整性问题用示波器看波形质量串电阻缩短走线加地平面偶尔读写失败电源噪声或去耦不足量电源纹波加去耦电容改善电源6. 工业场景下的数据存储策略与经验分享6.1 频繁写入场景的数据管理在工业数据采集场景里数据写入频率可能很高比如每秒几十次甚至上百次。虽然 MRAM 的擦写寿命几乎无限但频繁写入还是会占用 SPI 总线和 CPU 时间。我的做法是在 RAM 里开一个缓冲区积累到一定量之后再批量写入 MRAM。比如每 100 条记录写一次这样 SPI 事务次数减少了 100 倍CPU 占用也大幅降低。缓冲区的管理可以用环形队列写满之后覆盖最老的数据。如果担心断电丢数据可以在缓冲区快满的时候提前写入或者用 H750 的备份 RAM 加电池供电断电时把缓冲区数据保存下来。还有一个技巧是给数据加 CRC 校验。MRAM 本身很可靠但 SPI 传输过程中可能受干扰导致数据出错。每条记录后面跟一个 CRC16 或者 CRC32读的时候校验一下发现错误就重读。这个开销很小但能大幅提升数据可靠性。6.2 断电保护与数据完整性工业现场断电是家常便饭数据完整性是重中之重。MRAM 的写入是即时的发完数据就写完了不存在 Flash 那种写一半断电导致数据损坏的问题。但 SPI 传输过程中断电数据可能只传了一半这时候需要靠协议层来保证完整性。我的做法是每条记录加一个头和一个尾头里包含记录长度和序号尾里包含 CRC。写入的时候先写数据再写尾标志。读的时候先检查尾标志如果尾标志不对说明这条记录没写完直接丢弃。这样即使断电导致写入中断也不会读到半截数据。另外可以在 MRAM 里划两个区域一个存数据一个存元数据。元数据里记录当前写入位置、记录总数、最后一条记录的序号等信息。每次写入数据之后更新元数据这样上电之后能快速恢复状态。6.3 温度与长期可靠性考量MR25H40CDF 的工业级温度范围是 -40°C 到 85°C在这个范围内数据保持时间超过 20 年。但如果温度超过 85°C数据保持时间会缩短。在高温环境下使用的话建议定期刷新数据比如每年把关键数据读出来重写一遍。MRAM 的另一个优势是抗辐射性能好。在有一些辐射环境的工业场景里比如核电站或者医疗设备Flash 和 EEPROM 可能会因为辐射导致数据翻转MRAM 的磁性存储单元对辐射不敏感数据可靠性更高。PCB 布局方面MR25H40CDF 尽量远离发热源比如电源芯片、功率器件。如果板子上有高温区域把 MRAM 放在温度较低的位置。芯片底部的焊盘要可靠接地既有助于散热也能提供屏蔽。6.4 成本与选型对比最后聊一下成本。MR25H40CDF 的价格比同容量的 EEPROM 和 Flash 贵不少4Mbit 的 MRAM 大概要几十块钱人民币而 4Mbit 的 SPI Flash 只要几块钱。这个差价在成本敏感的项目里可能是个问题。但算总账的话MRAM 的优势能抵消一部分成本。不需要磨损均衡算法不需要擦除操作不需要等待写周期软件复杂度大幅降低。在频繁写入场景里EEPROM 和 Flash 可能需要外置磨损均衡芯片或者复杂的软件算法这些隐性成本加起来也不少。我的建议是如果写入频率低、数据量小用 EEPROM 就够了如果需要频繁写入、断电保护要求高、环境温度恶劣MRAM 是值得投入的。STM32H750XB 加 MR25H40CDF 这套组合在工业数据记录场景里算是比较均衡的方案性能、可靠性、开发难度都控制得不错。实际项目里我还遇到过一个问题H750 的 SPI 外设在某些低功耗模式下会关闭唤醒之后需要重新初始化。如果 MRAM 里存了关键数据唤醒后第一件事就是重新配置 SPI 并读取数据。这个坑在调试低功耗功能的时候很容易忽略建议在低功耗唤醒流程里加上 SPI 重新初始化的步骤。
返回列表