硬汉嵌入式论坛

 找回密码
 立即注册
查看: 32|回复: 0
收起左侧

[STM32H7] STM32H743 的常见内存限制和问题,新手踩坑注意

[复制链接]

1

主题

0

回帖

3

积分

新手上路

积分
3
发表于 昨天 17:27 | 显示全部楼层 |阅读模式
我从入门开始一直在用STM32H743这个片子做测温相关的工控业务,新手起步没有什么头绪的情况下踩了不少它内存上的坑,这里我根据以前的经验,并基于 STM32H743 参考手册 (RM0433) 和应用笔记 (AN4891, AN2606),给新使用这个mcu的新手一点提示,别跟我以前一样跟无头苍蝇一样乱撞,当然,现在AI也很发达,有不会的直接问ai也没毛病。

STM32H743的内存坑产生的主要原因是其相对复杂的多域总线架构、ECC 校验机制以及缓存策略导致的。下面我来细细说下。



1. 总线架构与访问限制STM32H7 的总线矩阵不是全互联的,不同主设备(Master)对不同内存区域(Slave)的访问权限有严格限制。
这一点老手都门清,但是新手如果对总线互联矩阵不清晰,那你写驱动吧,写外设吧,写应用吧,一写一个不吱声,一个bug调一天。

1.1 DTCM/ITCM 的 DMA 盲区
你在研究了743的内存架构以后一拍脑门,哈ITCM和DTCM都是高速缓存,那我把高速外设的buffer放里面不得贼快?
可是如果你这些buffer都是通过DMA更新的,那你就完蛋了。
DMA1、DMA2、以太网 DMA、USB HS DMA 无法访问 ITCM (0x00000000) 和 DTCM (0x20000000)。
DCTM, ITCM 内存直接耦合在 CPU 上,只有 CPU 和 MDMA(通过 AHBS 接口)能访问。

1.2 SDMMC1 和 LTDC 的 D2 SRAM 盲区
位于 D1 域的 SDMMC1LTDC (屏幕控制器) 无法访问位于 D2 域的 SRAM1, SRAM2, SRAM3 (0x30000000 起始)。
还是总线互联矩阵导致的,SDMMC1 和 LTDC 没有通往 D2 域的访问路径。
必须将屏幕显存(Frame Buffer)或 SD 卡缓冲区放在 AXI SRAM (0x24000000) 或外部 SDRAM 中。如果必须使用 SRAM1/2/3 数据,需使用 MDMA 进行搬运。

1.3 D3 域 SRAM4 的访问限制
以太网、SDMMC1、LTDC、DMA2D 无法访问 SRAM4 (0x38000000)。这些高性能外设无法通过总线桥访问 D3 域。
SRAM4 主要供 D3 域的 BDMA 使用,或用于 D1/D2 域进入待机模式(Standby)时的数据保持。


2. D2 域 SRAM 的时钟陷阱
你把D2域的SRAM咔咔写到了sct文件里,寻思物尽其用,结果一上电设备就HardFault。代码刚启动,访问 0x30000000 (SRAM1) 地址变量时立即触发 HardFault。
与 F4/F7 不同,H7 复位后 SRAM1, SRAM2, SRAM3 的时钟默认是关闭的。
在使用这些内存区域之前(通常在 SystemInit 或 main 开头),必须通过设置 RCC_AHB2ENR 寄存器中的 SRAM1EN, SRAM2EN, SRAM3EN 位来使能时钟。


3. Flash 编程与 ECC 限制STM32H7 的 Flash 采用 256-bit (32字节) 字长,并带有 10-bit ECC 校验,这导致写入规则与其他旧型号不一样。
禁止脏写入 :严禁对非 0xFF 的地址进行重复写入(例如想把 0xFFFF 写成 0x5555)。ECC 是基于数据计算的。如果覆盖写入,新数据的 ECC 值与旧 ECC 值会发生冲突,导致 ECC 错误标志 (SNECCERR/DBECCERR) 置位。
唯一允许将数据覆盖写入为 全 0x00,这会将 ECC 码也变为全 0,控制器会视为有效。
Flash 编程必须以 256-bit (32字节) 为单位对齐进行。这意味着你不能只写入一个 uint32_t,必须凑齐 32 字节写入,或者使用驱动提供的处理函数。
等待周期:修改主频后系统不稳定或读出数据错误。Flash 速度跟不上 CPU。必须根据 CPU 时钟 (ACLK) 和电压等级 (VOS) 在 FLASH_ACR 中设置正确的 LATENCY。例如 VOS1 下 200MHz 需要 2 个等待周期。

4. Cache 一致性问题4.1 Cortex-M7 带有 L1-Cache (I-Cache 和 D-Cache),且 AXI SRAM 默认是 Cacheable 的。
然后就是月经问题之为什么我的DMA数据闹鬼了,哈哈,实际上CPU 读取 DMA 接收的数据是旧的,或者 DMA 发送的数据不是 CPU 刚写入的。
CPU 读写的是 Cache,而 DMA 读写的是物理 RAM。这又跟你的MPU 配置有很大关系,需要将 DMA 缓冲区所在的内存区域配置为 Non-Cacheable
或者在 DMA 传输前执行 SCB_CleanDCache (写回),在 DMA 接收后执行 SCB_InvalidateDCache (无效化)。这一问题在论坛内硬汉哥给了充分的实验和分析,我当时也是拜大哥的教程才搞懂。


4.2 进入待机模式前将数据存入 SRAM4,唤醒后数据消失的问题也是Cache问题。数据可能还滞留在 D1 域的 Cache 中,未写入物理 SRAM4。在 D1 域断电前,必须对 SRAM4 区域执行 Cache Clean 操作。

5. 系统 Bootloader 占用 RAM 如果应用程序跳转到系统 Bootloader (例如进行 DFU 升级),返回后发现部分变量被破坏。STM32H7 的内置 Bootloader 在运行时,会使用 0x20000000 开始的 16KB ~ 128KB (取决于具体型号,H743 为 16KB 左右) 的 RAM 作为其堆栈和变量区。注意:0x20000000 正是 DTCM 的起始地址。如果您的应用数据放在这里且未受保护,Bootloader 运行期间会被覆盖。


6. AXI 总线与投机读取FMC 或 QuadSPI 外设报错或者总线死锁一看一个挠头,一看一个白眼。Cortex-M7 具有投机读取(Speculative Read)特性。如果 AXI 总线上的外设(如 FMC 连接的设备)不支持这种预读,或者地址映射到了不存在的物理设备,可能会导致 AXI 总线挂起或错误。解决办法是使用 MPU 将外设区域配置为 DeviceStrongly-ordered 类型,禁止投机读取和 Cache。


最后我给个总结,建议按如下策略分配内存:

  • CPU 运算/栈/局部变量 -> DTCM (0x20000000) (速度最快,但避开 DMA)。
  • 通用 DMA 缓冲 (UART/SPI/ADC) -> SRAM1/2/3 (0x30000000) (需手动开时钟,配置 MPU 为不可 Cache)。
  • 大容量数据/网络/显存 ->AXI SRAM (0x24000000) (所有主设备可访问,需注意 Cache 一致性)。
  • 低功耗保持数据 -> SRAM4 (0x38000000)


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-2-7 05:57 , Processed in 0.064565 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表