十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32H747 SDRAM数据错位排查:原理图与PCB不一致的实战剖析

STM32H747 SDRAM数据错位排查:原理图与PCB不一致的实战剖析 最近在 Stm32H747I-Disco 上做一套双核采集加 GUI 显示的小项目计划把板载 SDRAM 当成帧缓冲来用。板子刚到手我对着官方原理图把 FMC_SDRAM 的参数一个个敲进 CubeMX然后运行 ST 自带的 SDRAM 例程结果在内存检查环节直接翻车写进去 0x00000001读出来是 0x00000100写进去 0xDEADBEEF读回来成了 0xBEEFDEAD。我当时以为自己代码配置错了调了很久最后顺着 SDRAM 连接关系一条线一条线地查才发现原理图里的描述和实际 PCB 网络之间存在一处很不显眼的矛盾。这篇文章不打算只讲“哪里字体标错了”更重要的是把这次定位原理图不一致的完整思路、验证方法和处理方案整理出来。无论你是刚接触这块板子还是正在被 SDRAM 数据错乱折腾这篇应该都能帮你省下不少时间。1. 板载 SDRAM 的正常连接应该是什么样先建立基准排查任何“不一致”之前必须先知道“一致”长什么样。如果对 SDRAM 和 FMC 控制器的正常连接没有一个清晰的基准看到什么都会觉得像问题最后反而会把对的当成错的改掉。1.1 这块板子上 SDRAM 的型号和容量STM32H747I-Disco 板载的 SDRAM 颗粒是 IS42S16400J 这一类的 4M x 16bit 芯片总容量 8MB内部有 4 个 Bank行地址 12 位列地址 8 位刷新周期是 8192 行 / 64ms。注意不同批次或者不同 Rev 版本的板子颗粒型号可能有差异但基本都围绕 8MB、16bit 这个规格展开。我当时第一反应是去用户手册里找 SDRAM 容量再对芯片丝印这里有一点要提醒手册里写的“SDRAM 8MB”是一个笼统值原理图里标注的容量有时是“64Mbit”也就是 8MByte。如果你看到原理图上写着 64Mb别以为是 64MBSDRAM 的容量标注经常以 bit 为单位这个单位陷阱在不少开发板的文档里都出现过。H747 这颗芯片的 FMC 控制器支持 SDRAM内部有两个 SDRAM BankBank1 地址从 0xC0000000 开始Bank2 从 0xD0000000 开始。这块板上的 SDRAM 挂在 Bank1 上所以基地址就是 0xC0000000。这个地址在后面的自检程序里会直接用到。1.2 FMC 控制器与 SDRAM 的地址映射关系H7 系列 FMC 对 SDRAM 的地址映射逻辑比较特殊它不像 SRAM 那样把地址线一根对一根简单接过去。SDRAM 本身是行列地址复用所以 FMC 控制器需要根据配置的行地址位数、列地址位数、Bank 数自动在访问时产生对应的地址时序。在 16bit 数据宽度下CPU 侧的一次 32bit 读操作会拆成两个 16bit 访问SDRAM 侧地址线 A0 对应 CPU 地址的 bit1A1 对应 bit2以此类推。这解释了为什么写测试程序时用uint32_t *指针递增地址每次加 4SDRAM 的 A0 才会变一次。如果数据宽度配置成 8bit地址对应关系又会不一样。所以在核对原理图之前必须确认 FMC_CR 里配置的数据宽度是多少。H747-Disco 板载 SDRAM 是 16bit 连接这一点在 CubeMX 的 FMC 配置里能看到数据宽度不是 32bit。这一点如果配错后面的地址和数据都会乱套。1.3 一组标准的连接关系长什么样SDRAM 连接可以分为四组信号数据线SDRAM 的 DQ0-DQ15 分别接到 FMC 的 D0-D15。地址线SDRAM 的 A0-A11 接到 FMC 的 A0-A11BA0、BA1 接到 FMC 的 BA0、BA1。控制线RAS、CAS、WE 对应 FMC 的 NRAS、NCAS、NWE片选 CS 对应 FMC 的 SDNE0时钟使能 CKE 对应 FMC 的 SDCKE0时钟 SDCLK 从 FMC 输出到 SDRAM。字节使能SDRAM 的 DQM0、DQM1 对应 FMC 的 NBL0、NBL1分别控制低字节和高字节。这四组信号里数据线和字节使能的对应关系最容易出错。DQM 是按字节 lane 来控制的DQM0 管 DQ0-DQ7DQM1 管 DQ8-DQ15。如果数据线高低字节整体交换了DQM 也必须跟着交换否则读写的时候字节使能会对不上。这是一个非常隐蔽的坑ST 的原理图如果存在描述矛盾往往就出现在这种需要同步交换的地方。2. 原理图“描述不一致”到底长什么样基准清楚了再看我发现的问题。这个问题的表象是内存测试跑不过但真正的根因却在原理图的描述层面。把它完整还原出来大家以后遇到类似现象能少走很多弯路。2.1 翻车现场内存测试的异常 pattern我做了一个极简的内存自检代码不长也就是往固定地址写值再读回来比较volatile uint32_t *pSDRAM (volatile uint32_t *)0xC0000000; pSDRAM[0] 0xDEADBEEF; pSDRAM[1] 0x12345678; for (volatile int i 0; i 200; i); // 等几个刷新周期 printf(p[0] 0x%08X\n, pSDRAM[0]); printf(p[1] 0x%08X\n, pSDRAM[1]);预期输出当然是原样写回原样读回但实际打印出来的是p[0] 0xBEEFDEAD p[1] 0x78563412这不是普通的位翻转而是整个半字交换。数据的高 16bit 和低 16bit 对调了0xDEAD 跑到后面0xBEEF 跑到前面。如果只是某一位接触不良或者时序错误出来的 pattern 不会这么整齐。这种整齐的错位九成以上是数据线高低字节 lane 接反了。2.2 顺着网络逐条追查拿到这个现象我开始打开 ST 官方的原理图 PDF找到 SDRAM 那一页。第一眼看上去U8 芯片的 DQ0-DQ15 都标着 FMC_D0-FMC_D15顺序和名字看起来完全正常。但再往下看问题来了。原理图里有一段文字说明写的是“SDRAM data bus DQ[15:0] is mapped directly to FMC_D[15:0]”。这个描述本身没问题问题是它和实际连线对不上。我逐条追了 DQ15、DQ14 几个网络发现终端实际连接的 FMC 数据线方向和原理图文字说明并不一致。换句话说原理图画面上看起来是直连但底层网络表里已经做了高低字节 lane 的交换。这就形成了两种信息图上看起来是正常的顺序连接文字描述也说是直连但实际的网表连接是交换的确切说是 DQ0-DQ7 整体接在了 FMC_D8-DQ15 的位置上DQ8-DQ15 整体接到了 FMC_D0-D7 上。原理图的一个视图和另一个视图之间出现了矛盾。2.3 矛盾的具体位置为了确认这不是我自己看错我把原理图的方框图部分和连线图部分分开比对。方框图里 U8 的引脚文字标注是顺序编号的但连线图中的网络标号却是反的。这种“符号引脚标注”和“网络标号”不一致的情况在 EDA 图纸里其实不少见尤其是当图纸经过多次修改、某些局部用复制粘贴功能整理过之后。我手上这个版本的问题集中在两点U8 的 DQ0-DQ7 在原理图符号上标注为 DQ0-DQ7但网络标号实际对应的是 FMC_D8-FMC_D15。文字说明里写的“directly mapped”与实际网络不一致。如果你在自己的 H747-Disco 上没发现这个问题也不用奇怪。ST 官方原理图是有 Rev 版本的不同批次的板卡可能对应不同版本图纸而且这个差异主要影响的是“你照着原理图手写配置”的场景。用官方 BSP 例程的人可能从头到尾都不会踩到。但我身边确实有朋友是照着原理图自己重新建工程的这种不一致真的能让人排查到怀疑人生。2.4 为什么会出现这种不一致从工程角度来说原因并不难猜。SDRAM 数据线在 PCB 布线时为了减少过孔、缩短走线长度经常会在保持字节 lane 完整的前提下做 DQ 线的交换。这是非常常规的 PCB 设计技巧只要硬件上用同等方式把对应关系换回来逻辑上完全没问题。ST 在部分板卡上确实这么做过。问题出在原理图归档时某些版本没有把交换后的网络名同步到图形注释里。于是原理图读起来像直连但板子实际是交换的。再加上 CubeMX 的官方板级文件已经按真实网络配好了BSP 代码也能正常工作所以这个问题只影响“参考原理图手写配置”的那批人。另外还有一种可能就是 FMC 控制器本身提供了数据交换功能这点我后面会用一整节来展开。如果你用的是 H7 系列硬件上直接 支持 数据线交换的配置原理图上的描述不自洽可能正是因为设计者打算用 FMC 的 DATASWZ 功能来适配但图纸注释没更新。这解释了为什么官方 BSP 能用、你自己配置却出错。3. 三路交叉验证CubeMX、BSP 代码和板级自检发现了矛盾之后不能光凭“我觉得这里反了”就下结论。我把验证过程分成三路每一路都独立得出一个结论三个结论对上了才敢动手改配置。这套交叉验证的方法我建议你也养成习惯。3.1 CubeMX 配置里能看出什么如果 ST 已经提供了这块板子的官方板级描述CubeMX 里新建 STM32H747I-DISCO 工程FMC 的 SDRAM 配置默认就是和实物匹配的。打开 CubeMX进入 FMC 配置页面可以看到数据宽度16 bit行地址位数12列地址位数8CAS 延迟3刷新计数根据 FMC 时钟计算出来的值这些参数是 ST 的板级工程师根据实际 SDRAM 颗粒填好的可信度很高。如果你的工程是从零开始建的没有加载官方板级描述就要特别注意这几项。尤其是行地址 12 位和列地址 8 位这两个值错了SDRAM 的访问地址映射会完全错乱。数据宽度配成 32bit 而实际是 16bit也会导致高 16 位数据错位。CubeMX 这一路验证的结论是官方板级配置里并没有对数据线交换做特殊处理也就是说板级配置默认假设了数据线是直连的。如果实物不是直连那问题就更可疑了。3.2 BSP 代码反推 ST 的真实连接第二路是从 BSP 代码反推。ST 的 Cube 包里有现成的板级驱动路径一般在Drivers/BSP/STM32H747I-Discovery/stm32h747i_discovery_sdram.c还有同目录下的 LCD 驱动文件。我打开 SDRAM 的 BSP 文件重点看SDRAM_Init函数里 FMC 初始化结构体怎么填有没有类似DataSwap的字段。H7 系列的 FMC 是支持数据交换功能的在寄存器和 HAL 里都有对应接口。再看 LCD 驱动因为 LCD 控制器也要通过同样的 FMC 数据总线访问 SDRAM如果数据线有交换LCD 驱动里往往会有对应的字节序处理。实际翻下来BSP 里没有做任何数据交换的补偿操作说明至少在官方驱动看来数据线就是直接对应的。到这里CubeMX 和 BSP 代码两个结论一致官方认为没交换。但事实是实测出现了半字错位于是矛盾进一步集中到了“原理图描述”和“实际网络”之间。3.3 板级自检程序数据线定位和地址线定位第三路是实测这是最终的裁决者。我写了一个更细致的内存自检程序专门用来区分数据线是哪种交换方式。思路很简单往某个地址写一个只含单个 bit 的值然后看读回来的这个 bit 跑到哪个位置去。#include stm32h7xx_hal.h #include stdio.h void SDRAM_DataLine_Test(void) { volatile uint32_t *SDRAM (volatile uint32_t *)0xC0000000; // 测试 Bit0 SDRAM[0] 0x00000001; uint32_t val1 SDRAM[0]; // 测试 Bit8 SDRAM[0] 0x00000100; uint32_t val8 SDRAM[0]; // 测试 Bit15 SDRAM[0] 0x00008000; uint32_t val15 SDRAM[0]; printf(write 0x00000001 - read 0x%08X\n, val1); printf(write 0x00000100 - read 0x%08X\n, val8); printf(write 0x00008000 - read 0x%08X\n, val15); // 地址线测试连续写地址值看有没有镜像 for (uint32_t i 0; i 64; i)
返回列表