ARTICLE DETAIL

资讯详情

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

STM32H745外扩SDRAM:FMC时序与PCB布线调试全攻略

STM32H745外扩SDRAM:FMC时序与PCB布线调试全攻略 做嵌入式硬件最怕的不是SoC选型而是明明按照参考设计搭好电路代码也写了SDRAM就是跑不稳。最近用STM32H745IIT6外挂一片IS42S83200J做参考设计从原理图到PCB再到驱动反反复复调了一周总算把这套方案彻底吃透。这篇就把这次实践中FMC接口、时序换算、PCB布线、软件初始化以及各种“按手册操作却翻车”的细节完整记录下来。先交代一下这套方案到底在做什么。STM32H745IIT6是ST新一代双核旗舰MCU内部集成了Cortex-M7和Cortex-M4两个内核主频最高480MHz封装为LQFP176Flash有2MB片内RAM总共1MB。看到这里你可能会问1MB RAM对单片机来说已经很夸张了为什么还要外扩SDRAM实际上H745这种性能级别的MCU常见应用场景是HMI人机界面、网络摄像头图像采集、音频合成、边缘AI推理和工业协议网关。跑图形界面要帧缓冲跑摄像头要行缓冲和帧存储跑FFT和各种算法要巨型临时数组这些场景下1MB片内RAM根本不够用。IS42S83200J是一片32MB容量的SDRAM数据总线宽度32位8M×32bit组织方式容量上比片内RAM大32倍性价比又高综合下来是H745外扩内存的常用选择。我这套参考设计就是围绕“H74532位SDRAM”这个组合做的完整硬件验证。1. 整体设计思路为什么选择外部SDRAM这套方案1.1 H745的片内资源与外扩存储的边界先梳理清楚H745内部的存储结构。STM32H745IIT6的M7内核访问主SRAM内部SRAM分成好几个块DTCM、ITCM、AXI SRAM和SRAM1/2/3等共1MB。其中DTCM和ITCM连接在M7的核心总线上访问延迟低但只能被M7内核访问M4和DMA都碰不到。AXI SRAM和普通SRAM挂在总线矩阵上可以跨核访问但容量依然有限。实际做项目时这1MB会被内核堆栈、RTOS、通讯协议栈、DMA描述符、中间件缓冲分掉大半真正留给大块数据的只有几MB甚至更少。在这种背景下外部SDRAM扮演的角色就很明确大容量、低成本的运行数据缓冲池。GUI用SDRAM做framebuffer摄像头驱动用SDRAM做多帧轮转缓存网络应用用SDRAM做TCP收发缓冲算法模块用SDRAM存储中间变量。STM32H745的FMC控制器原生支持SDRAM接口硬件上无需额外逻辑芯片软件上FMC会自动负责刷新操作让SDRAM用起来和普通SRAM一样简单。这就是为什么我坚持外部SDRAM而不是去找大容量SRAM或PSRAM的原因——FMCSDRAM是性价比和可维护性最平衡的方案。1.2 选型对照IS42S83200J在同类SDRAM中的优势选定SDRAM方向后型号上我做了一圈对比。值得考虑的候选有IS42S83200J32MB32位宽、IS42S16320J32MB16位宽、W9825G6KH32MB16位宽等。IS42S83200J最突出的两部分优势一是总线宽度32位和H745的FMC数据总线D0-D31直接一对一连接一次访问能搬运4字节带宽是16位器件的两倍二是在3.3V IO电平的SDRAM里主频能跑到143MHz对应时钟周期7ns给FMC时序余量留出了足够的调节空间。除此之外ISSI在工业级市场扎根很深IS42S83200J有工业温度范围选型长期供货稳定在电机驱动、电力监控、机器视觉这类温度环境苛刻的项目里比较放心。真正让我敲定它的还有一个原因ST官方的H745评估板和不少第三方核心板上SDRAM都选的这颗料网上的参考电路和驱动代码都很成熟。硬件这东西最难的不是设计而是出了问题找不到参照物。选一颗有大量成功案例的SDRAM踩坑成本会低很多。做参考设计最关键的目标是“可复现”选型上求稳比求新重要得多。1.3 参考设计的系统组成与数据流向整套系统除了MCU和SDRAM还包括电源电路、时钟电路、调试接口和几个关键外设接口。电源部分用一颗输入5V的DC-DC转3.3V给SDRAM和MCU的IO供电再通过一颗LDO产出1.2V内核电压。时钟系统采用25MHz无源晶振作为HSE源芯片内部PLL倍频到480MHz给M7240MHz给M4而FMC外设时钟来自AHB总线HCLK典型配置为240MHz再通过FMC内部四分频得到60MHz的SDRAM时钟。数据流向可以这样理解M7通过内部总线发起读或写地址总线矩阵将请求转发给FMC控制器FMC对SDRAM发出对应的命令和地址数据在D0-D31数据线上以32位宽度并行传输。需要强调的一点是FMC的SDRAM刷新是硬件自动完成的不需要CPU干预但刷新定时器的配置必须精确否则SDRAM内部存储电容的电荷会泄漏导致数据慢慢丢失。这一块后面会重点讲。2. FMC接口设计与时序换算把SDRAM手册翻烂才是正道2.1 H745与IS42S83200J的引脚连接方案引脚连接是整个参考设计的物理基础。IS42S83200J是8M×32位组织地址线只需要A0-A12共13根行列复用32根数据线D0-D31bank选择用BA0和BA1两根控制线有行选通RAS、列选通CAS、写使能WE、片选CS、时钟使能CKE、差分时钟CLK还有4根字节掩码DQM0-DQM3分别对应32位数据总线的4个字节。H745的FMC接口这些信号都有对应引脚。实际引脚映射我整理成了对照表方便布线时直接查SDRAM信号STM32H745引脚类型说明A0-A12由FMC地址引脚映射输出行列复用地址BA0/BA1FMC_BA0/FMC_BA1输出Bank选择D0-D31FMC_D0-FMC_D31双向32位数据总线DQM0FMC_NBL0输出字节0掩码DQM1FMC_NBL1输出字节1掩码DQM2FMC_NBL2输出字节2掩码DQM3FMC_NBL3输出字节3掩码RAS/CAS/WEFMC_NRAS/NCAS/NWE输出行/列/写选通CSFMC_SDNE0输出SDRAM片选bank0CKEFMC_SDCKE0输出时钟使能CLKFMC_SDCLK输出SDRAM工作时钟采用32位直连的好处是数据带宽最大化H745的FMC对外设访问最高可达到32位宽度如果选16位SDRAM还要考虑字节对齐和带宽减半的问题。直连之后STM32内部将SDRAM映射到0xC0000000地址段bank1或0xD0000000地址段bank2访问SDRAM就像访问内部SRAM一样直接操作地址即可。有一点容易忽视H745的FMC_NE、FMC_NCE等信号在不同型号上的引脚复用不同CubeMX里需要根据实际封装勾选正确的复用功能引脚冲突在编译阶段不一定报错但跑起来SDRAM完全没反应的情况很多就是这里错了。2.2 SDRAM时序参数与FMC寄存器换算方法SDRAM不同于SRAM它的每一次操作都伴随行激活、列读写、预充电、刷新等步骤每个步骤都有最小时间要求FMC必须按这些要求配置时序寄存器。这是SDRAM设计中最关键的一环配置过紧SDRAM工作不稳定配置过松则浪费性能。先看IS42S83200J数据手册中几个最重要的时序参数。在CAS3、电源电压3.3V条件下一般取值为tRCD最小20nstRP最小20nstRAS最小42nstRC最小63nstRFC自动刷新周期约72ns刷新周期64ms对应8192行。这些数字是器件级的硬约束FMC的SDTR寄存器就是用来设置这些时间参数的。STM32H745的FMC_SDTR寄存器里TRCD、TRP、TWR、TRC、TRAS、TXSR、TMRD这些字段的单位是FMC时钟周期而字段值需要减1后写入。比如FMC时钟配置为60MHz时钟周期约16.67ns那么TRCD20ns对应1.2个周期向上取整为2个周期写入值就是2-11。同理TRP20ns也写入1TRAS42ns对应2.52个周期取整3写入2TRC63ns对应3.78个周期取整4写入3。我这边实际取的是FMC时钟60MHz所以各项看来都在很小的值这说明60MHz下时序压力很小SDRAM能稳定运行。真正容易出问题的是刷新周期。FMC_SDCR寄存器中的RT时钟周期数用来控制两次自动刷新之间的间隔。计算公式是刷新间隔刷新周期/行数即64ms除以8192约等于7.81微秒。然后这个时间再除以FMC时钟周期16.67ns约等于469个周期再减去20个周期的裕量最终写入值约449。如果没有留裕量刷新间隔刚好卡在临界值当供电电压波动或温度升高时SDRAM内部刷新可能来不及就会出现偶发的数据损坏。这个20周期的裕量是ST参考手册明确建议的。2.3 CAS延迟和突发长度的选择逻辑CAS延迟指的是读命令发出到第一个有效数据出现在总线上的延迟周期数IS42S83200J支持CAS2或CAS3。从性能上说CAS2更优但CAS2要求SDRAM时钟频率不超过某个上限具体由数据手册的时序决定。我实际测试下来在FMC时钟60MHz这个频率档位CAS3的时序余量最充裕偶发错误最少所以参考设计里模式寄存器配置为CAS3。突发长度BL决定了每次读写连续传输多少个数据字。IS42S83200J支持BL1、2、4、8和全页突发。CPU对SDRAM的访问以Cache line为单位一个Cache line通常是32字节如果BL1每次读32位就要发起一次列访问效率很差BL8则一次突发传输32字节和Cache line完美对齐。实际使用中我把BL配置为8搭配M7内核Cache的Write-Back策略读写性能明显比BL1高出一大截。但BL8要小心地址跨越边界的问题如果一次突发跨越了行边界SDRAM会强制插入额外的预充电和激活性能反而下降。所以应用层分配大缓冲区时尽量按行对齐SDRAM一行的长度是列数乘以数据宽度IS42S83200J一行是1024列×4字节4KB。3. 硬件设计细节电源、时钟和PCB布局里的信号完整性3.1 SDRAM供电和去耦电容的布置经验给SDRAM供电看起来简单实际影响非常大。IS42S83200J的VDD和VDDQ都是3.3V但SDRAM在工作时有明显的电流突变特别是在行激活和突发传输的瞬间电流可能达到几十毫安的跳变。如果电源路径阻抗太高VDD电压会出现毛刺轻则数据读错重则SDRAM状态机错乱。我的做法是电源PCB上单独走一条3.3V主路径给SDRAM不要和数字逻辑混用靠近SDRAM的每个电源引脚都放一颗100nF的MLCC去耦电容同时在SDRAM附近放一颗10uF的钽电容做低频储能。另外SDRAM的VDDQ也是3.3V如果板上还有别的3.3V敏感器件建议在SDRAM的VDDQ引脚额外加一个小磁珠隔离避免数字开关噪声倒灌。时钟信号FMC_SDCLK是SDRAM正常工作的心跳CLK的波形质量直接影响时序裕量我建议SDCLK走线做阻抗控制表层50欧姆单端走线尽量短远离板上其他高频开关节点。还有一条很多人忽略的CKE信号不能被拉低。SDRAM上电后如果CKE为低器件会进入掉电模式所有命令都无效。复位期间GPIO默认态可能出现CKE被拉低的情况硬件上建议加一颗10k上拉电阻到3.3V保证上电时CKE默认有效。3.2 PCB布线的等长与分组策略32位并行总线加SDCLK往来的信号接近40根PCB布局时如果随意拉线时序偏差会大得离谱。SDRAM接口的时序余量是纳秒级别FMC输出地址和数据的时钟是同一个SDCLK所以地址线、数据线、控制线与SDCLK之间的偏差必须控制在一定范围内。我实际布线时把信号分成三组地址和控制组A0-A12、BA0/BA1、RAS、CAS、WE、CS、CKE、数据组D0-D31、字节使能组DQM0-DQM3。组内等长控制在25mil以内组间等长控制在100mil以内。PCB走线速率在常规FR4板材上大约是每英寸150ps25mil对应约4ps的偏差这个量级对60MHz的SDRAM完全无压力。重点是数据组32根数据线如果分别走表层和底层电学长度差异会变大我建议数据线尽可能走同一层减少过孔带来的stub效应。还有一条实际经验SDRAM下方尽量保持完整的参考地平面不要有大面积的开槽否则返回电流绕远路相当于增加了线长时序偏差和辐射都会变大。参考设计里我把SDRAM放在PCB边缘BGA封装的MCU在另一侧两者之间的走线区域干净没有其他高速信号穿越。3.3 上电时序和复位顺序SDRAM对电源的上升时间和CKE的时序有明确要求。IS42S83200J数据手册要求上电后先保持CKE为低至少100微秒然后CKE拉高再等待至少200微秒之后才能发送预充电命令。如果MCU复位期间GPIO状态不明确CKE提前拉高SDRAM上电时序可能不满足。解决方案有两个思路一是硬件上CKE引脚外加RC延时让上电后CKE延迟一段时间才到达高电平二是软件上在FMC初始化前加入等待CubeMX生成的初始化代码里一般会包含一条HAL_Delay但我更建议把等待时间明确写大一些比如延时10ms再执行SDRAM初始化序列保证上电稳定。软件延时的代价只有几十毫秒相对于SDRAM初始化失败后的一整天排查成本可以忽略。另外MCU自身和SDRAM之间如果存在电平转换要注意转换IC的上电顺序。参考设计里SDRAM和MCU同为3.3V电平省掉了电平转换这层麻烦。如果将来换用1.8V的SDRAM就需要仔细检查两边电源轨的上电顺序避免IO引脚在总线浮空期间向电源轨倒灌电流。4. 软件部分CubeMX配置到SDRAM读写验证4.1 CubeMX中FMC的配置要点CubeMX里配置FMC相对简单但有几个地方容易漏。SDRAM型号选择时需要配置数据位宽为32位而不是默认的16位否则读写数据总是不对。内部Bank选择SDRAM bank1对应地址0xC0000000片选信号FMC_SDNE0。CAS延迟选择3行地址位宽填13列地址位宽填10因为IS42S83200J的行地址是13位列地址是10位8M×32的组织中8M4bank×2048行×1024列实际行地址位宽应为13位列地址10位。这里要注意SDCR寄存器里行地址位宽的设置如果和实际器件不匹配SDRAM的访问会错位。时序参数在CubeMX里直接填时间值软件会帮你换算成寄存器值但这里有个隐患CubeMX只做简单换算不做取整和裕量补偿。所以我更建议先在CubeMX里填写初值再打开生成的代码检查SDTR寄存器实际写入的值必要时手动修改HAL库初始化结构体中的参数。时钟配置上FMC挂接在AHB总线上CubeMX的时钟树中HCLK配置为240MHz那么FMC的时钟来源最终取HCLK的2分频或4分频等这取决于SDRAM的时钟频率设置。IS42S83200J最高支持143MHz所以60MHz是一个保守且稳定的选择。4.2 SDRAM初始化序列的Demo代码HAL库把SDRAM的初始化流程封装成了几步命令但原理还是需要自己理清楚。初始化序列依次是CKE拉高并等待稳定发出预充电命令PALL执行至少两次自动刷新命令配置模式寄存器MRS然后设置刷新定时器。下面这段是我调试通过的代码流程核心部分FMC_SDRAM_CommandTypeDef command; SDRAM_HandleTypeDef hsdram1; hsdram1.Instance FMC_SDRAM_DEVICE; /* 1. 预充电所有bank */ command.CommandMode FMC_SDRAM_CMD_PALL; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; command.AutoRefreshNumber 1; command.ModeRegisterDefinition 0; HAL_SDRAM_SendCommand(hsdram1, command, 0x1000); /* 2. 连续8次自动刷新 */ command.CommandMode FMC_SDRAM_CMD_AUTOREFRESH_MODE; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; command.AutoRefreshNumber 8; command.ModeRegisterDefinition 0; HAL_SDRAM_SendCommand(hsdram1, command, 0x1000); /* 3. 配置模式寄存器 CAS3, BL8 */ command.CommandMode FMC_SDRAM_CMD_LOAD_MODE; command.CommandTarget FMC_SDRAM_CMD_TARGET_BANK1; command.AutoRefreshNumber 1; command.ModeRegisterDefinition 0x33; // CAS3, BL8, 顺序突发 HAL_SDRAM_SendCommand(hsdram1, command, 0x1000); /* 4. 配置刷新计数器 */ HAL_SDRAM_ProgramRefreshRate(hsdram1, 449);模式寄存器值0x33需要手工算一下bit0-bit2是突发长度BL8对应二进制111所以bit2-bit0为111bit3是突发类型顺序突发选0bit4-bit6是CAS延迟CAS3对应011放在bit6-bit4也就是bit41bit51bit60bit7是操作模式0表示标准模式。组合起来0b001100110x33。如果你用CAS2bit4-bit6变成010值就变了。这一块直接抄网上代码最容易出错建议每次换SDRAM型号都对着手册重新算。4.3 地址线、数据线和缓存一致性的验证方法初始化完成后先用测试代码确认物理连接正确。我习惯分三步做验证第一步只写一个固定的32位数到某个地址然后读出来对比如果一致说明基本通路正常第二步对SDRAM所有地址空间跑一遍递增数据的写入和读取这一步能发现地址线的连接错误第三步用伪随机数填满整个32MB空间再读回校验检测数据线有没有短路或虚焊。uint32_t *sdram_base (uint32_t *)0xC0000000; uint32_t i, val; uint32_t errors 0; /* 地址线测试每个地址写入自身地址值 */ for (i 0; i 8 * 1024 * 1024; i) { sdram_base[i] i; } for (i 0; i 8 * 1024 * 1024; i) { val sdram_base[i]; if (val ! i) { errors; } }注意这个测试遍历的是8M个32位字刚好等于32MB全部空间。如果地址线A0-A12中某一位接错写入和读出的地址会发生映射错位错误模式非常有规律根据错误地址和期望地址的差就能反推出是哪一根地址线的问题。数据线的问题则体现在某个bit位上固定读错值比如D7短接到地那么每次读写的bit7永远是0从错误数据的二进制特征一眼能看出来。还有一个M7内核特有的问题必须提Cache一致性。H745的M7内核带有D-Cache默认情况下代码访问0xC0000000地址段时如果MPU配置缺失D-Cache可能不进SDRAM区域也可能进但导致DMA写入的数据在Cache里看不到。调试阶段我一般先关闭D-Cache或者把SDRAM区域配置为非Cacheable先排除掉缓存一致性这个变量。等SDRAM物理层验证通过后再根据实际性能需求配置MPU为Write-Back模式并在DMA传输前后加SCB_CleanDCache和SCB_InvalidateDCache操作。5. 实际调试中踩过的坑与排查思路5.1 SDRAM初始化命令超时调试中遇到的第一个问题是HAL_SDRAM_SendCommand函数一直返回超时。排查方向从软件到硬件逐层排查。先检查CubeMX生成的GPIO初始化代码确认FMC的所有引脚都配置为复用功能且复用编号正确。我一开始用的是LQFP176封装的H745部分FMC引脚和ADC、DCMI等外设复用CubeMX中如果不小心勾掉了某个引脚的FMC复用初始化代码根本不会配置该引脚SDRAM自然无法工作。逐一对照数据手册的引脚复用表检查后发现有一根地址线被配置成了普通GPIO输出修复后初始化命令不再超时。如果GPIO没问题下一步就要查SDRAM的供电和CKE电平。用示波器测量SDRAM的VDD引脚确认3.3V正常测量CKE引脚确认初始化前为低、初始化开始后拉高。我的板子上CKE被一个GPIO通过跳线控制跳线没插的时候CKE悬空SDRAM也初始化不了。加下拉电阻把默认状态固定住问题解决。5.2 数据偶发错乱和字节掩码的“幽灵问题”SDRAM能写入也能读出但运行几分钟后开始偶发数据错误这是最让人头疼的问题。我遇到的情况是DMA搬运摄像头数据到SDRAM时每隔几十帧就有一小块图像花掉。最开始怀疑是SDRAM刷新配置不对反复计算刷新计数器无果。后来用示波器同时抓SDCLK和DQM信号发现DQM3这根信号线上有严重的过冲幅度超过了3.6V已经触发SDRAM输入保护。检查PCB走线后确认DQM3走线过长且经过一个过孔换层阻抗不连续导致反射。问题定位后处理方案是给DQM3串了一颗22欧姆的阻尼电阻放在靠近MCU输出端的位置同时把走线改短过冲幅度降到3.3V以内图像花块问题彻底消失。这个案例再次印证了总线时钟频率不高但信号质量依然关键SDRAM的输入保持时间和建立时间窗口很窄任何反射引起的振铃都可能落在窗口边缘。5.3 刷新配置与温度漂移还有一次批量测试时发现常温下读写正常放到恒温箱里升温到70度SDRAM出现大量位翻转错误。这个现象是刷新周期太临界导致的。SDRAM内部的电容电荷泄漏速度随温度升高而加快数据手册的64ms刷新周期通常是在常温下的指标温度升高后刷新间隔必须缩短。我重新计算刷新计数器把原先469个时钟周期缩短到400个时钟周期留出充足裕量70度高温拷机24小时不再出现数据翻转。这里给一个建议量产产品如果工作温度范围宽刷新率不要照着数据手册的极限值去配留出20%到30%的裕量不会牺牲多少带宽但稳定性会大幅提升。如果板上空间允许加一颗温度传感器根据环境温度动态调整刷新率也是更精细的做法不过对多数项目来说固定裕量就够了。5.4 MCU与SDRAM的访问仲裁冲突最后补一个容易被忽略的系统级问题。H745双核架构下M7和M4都可能访问同一片SDRAM如果两边同时发起访问总线矩阵会仲裁但仲裁的等待时间不定。在实时性要求高的场景比如M4在做电机控制采样M7在刷GUI两个内核同时抢SDRAM总线最坏情况下的延迟可能达到几十纳秒如果任务对这个延迟敏感就会出现周期性抖动。我的做法是SDRAM优先分给M7做大数据缓冲M4尽量使用片内的SRAM只有共享数据才放到SDRAM。共享区域用HSEM硬件信号量做互斥避免两个内核同时写同一块区域导致数据错乱。这套方案跑下来SDRAM的总线负载和实时性表现都在可控范围内。6. 性能基准与扩展可能性验证稳定后我对这套参考设计做了性能实测。FMC配置为60MHz时钟32位数据总线突发长度8理论峰值带宽约240MB/s。实际用DMA搬运内存块测试读写混合场景下有效带宽达到约190MB/s接近80%的效率这在SDRAM方案里属于正常水平。如果想把带宽再往上推可以把FMC时钟调到90MHz甚至更高但PCB走线的等长和阻抗控制要求会明显提升普通两层板很难保证稳定建议至少四层板再做高频尝试。一套配置可以通过CubeMX导出不同的引脚复用快速适配不同PCB布局。后面如果再设计相似项目我大概率会把SDRAM封装换成IS42S83200J的兼容型号或升级到容量更大的IS42S86400JFMC接口基本不用大改只需要调整模式寄存器的行列地址位宽和刷新计数器开发周期能压得很短。说实话SDRAM这个技术栈看起来是上一代的产物但STM32H7这类高性能MCU在不少工业项目里已经站稳了脚跟外部SDRAM作为成本最低的大容量内存补充方案生命周期还很长。这次参考设计做完最大的体会就是SDRAM调试没有玄学所有不稳定现象背后都能找到明确原因关键在于是否愿意拿着示波器逐根信号排查像翻字典一样对着时序图核对每一个参数。这周踩过的坑、摸索出的经验希望正在看这篇文章的你不需要重新走一遍。
返回列表