简介:面向嵌入式硬件工程师、STM32开发者与PCB设计学习者,这份STM32H750XBH6核心板原理图给出小尺寸高性能控制器的硬件参考。图纸展示双片SDRAM组成32位宽、64MB容量,两片QSPI Flash扩展64MB存储,并包含6层板、29.5mm×32mm模块的电源管理、限流保护、独立模拟基准、稳压与引脚连接思路。可对照升降压供电、去耦电容、复位启动配置、外部基准及存储器地址数据控制线,理解紧凑核心板的供电分区、接口复用和高速信号布局,对学习并行总线、多线QSPI连接和叠层规划有帮助。资源包仅含1个PDF文件,约87KB,已有3111人学习,适合工业控制、医疗设备等项目的原理图复盘、硬件选型与PCB设计参考。
1. 需求先落地:29.5mm × 32mm 上塞 64MB SDRAM 与 64MB Flash 的取舍
拿到一份 STM32H750XB 原理图,我第一眼只看三件事:存储怎么接、电源怎么分、板子多大。这块核心板把 64MB SDRAM、64MB Dual QSPI Flash 和一颗 BGA240 的主控压进 29.5mm × 32mm 的六层板,供电还要兼容 3.3V 到 5V。选型动机很直白:H750 片内只有 128KB Flash,跑 LVGL 全屏刷新、图像缓冲、字库和模型文件都不够用,所以必须用外部 QSPI 存代码、外部 SDRAM 存数据,把“大容量”这件事从芯片成本里挪到板级成本里。这套方案适合要做带屏 HMI、图像采集、运动控制且对体积敏感的人,也适合拿它当毕设硬件平台的读者——前提是你得先看懂这张图里哪些线是必须等长的、哪些参数是必须手算的。
2. 总体架构:三大总线分区、六层叠层与 120 个连接器引脚的分配
2.1 从 BGA240 的引脚分组倒推模块划分
H750XBH6 是 BGA240 封装,引脚密度高,原理图不能按“功能块好看”来画,得按总线和电源域切。这张图实际切成了四块:FMC 存储域、QUADSPI 存储域、用户 IO 域、电源与基准域。FMC 域占据了 PD0~PD15、PE7~PE15、PH8~PH15、PI0~PI10 这批数据脚,加 PF0~PF5、PF12~PF15、PG0~PG2 的地址脚,以及 PC0、PC2、PC3、PG4、PG5、PG8、PE0、PE1、PI4、PI5、PF11、PG15、PD4~PD7、PD11~PD13 这批控制脚。把它们抽成网络标号 FMC_D[0:31]、FMC_A[0:12]、FMC_BA[0:1]、FMC_NBL[0:3]、FMC_SDCLK 等,页面上就只剩“网标 + 器件”,读图效率高很多。
QUADSPI 域只有一组:PB2 作 CLK,PF6/PF7/PF8/PF9 作 IO3/IO2/IO0/IO1,PB6 作片选,PB10 在这张图里被复用成另一路片选或控制。用户 IO 域则是把 LCD 的 24 根 RGB、SDIO 的 6 根、USB 的 D+/D-、RMII 的 8 根、SAI 的 5 根、DCMI 的 8 根、USART1/2/3、I2C1/4、SPI2 全都摊到连接器上。这里有个容易被忽略的点:同一颗引脚在图上出现多次(比如 PA9/PA10 在 sheet1 和 sheet3 都出现),靠网络标号合并,读图时必须按网络名查,不能按引脚号查,否则会误判成短路。
2.2 六层叠层与 29.5mm × 32mm 的布局约束
六层板在这个尺寸下的典型叠层是:L1 器件与扇出、L2 完整地、L3 SDRAM 数据与地址走线、L4 电源平面、L5 完整地、L6 低速信号与连接器扇出。把 L2 和 L5 都做成完整地,是因为 32 位 SDRAM 在 100MHz 级别跑起来时,回流路径一旦断裂,眼图就会变成“玄学”,你会在实验室里花掉一整周去怀疑代码。L3 夹在两个地平面之间,正好走 SDRAM 的 D0~D31 和 A0~A12,做等长时参考平面是连续的,这是这块板子能在 29.5mm 宽度内布通的前提。
布局上,两片 SDRAM 通常贴着主控放在板子的一侧,两片 QSPI Flash 放在另一侧,原因是 SDRAM 的走线数量是 Flash 的六倍以上,必须优先保证它的扇出空间。晶振(25MHz 主振和 32.768kHz 低速振)放在主控的 OSC_IN/OSC_OUT 侧,负载电容 22pF 和 6pF 紧贴晶振脚放置,下面挖空不走线。连接器 CON1/CON2 放在板边,它们决定这块核心板插到地板上之后的高度,所以电源入口和限流器件要靠近连接器的电源脚,避免大电流路径横穿整块板。
2.3 板对板连接器的引脚预算表
120 个引脚要装下全部用户 IO 是不可能的,所以这张图做了一个明确的取舍:SDRAM 和 QSPI 全部焊死在板内,不出连接器;连接器只出“用户可能要接”的信号,并且做了复用。下表是按功能域整理的引脚预算,实际分配以原理图网络名为准。
| 功能域 | 引出信号 | 大致占用引脚 | 复用提示 |
|---|---|---|---|
| 电源与地 | VDD_3V3、VDD_IN、GND | 约 20 根 | 3.3V~5V 输入可直供 |
| 显示接口 | LCD_R[0:7]、G[0:7]、B[0:7]、HSYNC、VSYNC、CLK、DE | 约 28 根 | 与 FMC、DCMI 部分复用 |
| 存储扩展 | FMC_A16~A18、FMC_NE1、FMC_NWE、FMC_NOE、FMC_NWAIT | 约 8 根 | 可外挂并口屏或 SRAM |
| 通信 | USART1/2/3、I2C1/4、SPI2、SAI1 | 约 16 根 | 与 GPIO 复用 |
| 高速 | USB_D+/D-、RMII 8 根、SDIO 6 根 | 约 18 根 | 与 JTAG 部分冲突 |
| 调试 | SWDIO、SWCLK、NRST、BOOT0 | 4 根 | 必留 |
| 模拟 | VREF+、VREF-、ADC 输入若干 | 4~6 根 | 基准单独走线 |
这张表的价值在于答辩时能解释“为什么这块板子只有 120 pin 却够用”:不是引脚多,是把不常变的存储留在板内做了“固化配置”,把灵活的部分留给连接器。
3. 存储子系统:双 SDRAM 拼 32 位、双 QSPI 拼容量的实现细节
3.1 FMC 存储体映射与两片 16 位器件的拼接方式
两片 32MB 的 16 位 SDRAM 要拼成 32 位宽、总容量 64MB 的系统,接法不是简单并联。第一片的 DQ0~DQ15 接 FMC_D0~D15,第二片的 DQ0~DQ15 接 FMC_D16~D31;两片的地址线 A0~A12、bank 线 BA0/BA1、行列控制线 CAS/RAS/WE 全部并联;片选共用 FMC_SDNE0 和时钟使能 FMC_SDCKE0;最关键的是字节掩码——第一片的 LDQM/UDQM 接 FMC_NBL0/NBL1,第二片接 FMC_NBL2/NBL3。如果这两根线接反或者漏接,现象是“写 32 位数据能过、写 8 位字节数据就出错”,很多人会误判成时序问题。
FMC 的 SDRAM Bank1 映射到 0xC0000000,Bank2 映射到 0xD0000000,这张图用 Bank1 就够。地址空间算法是:13 位行地址 × 9 位列地址 × 4 个内部 bank × 4 字节(32 位宽)= 8192 × 512 × 4 × 4 = 64MB,和两片 32MB 的容量正好对上。这里要提醒一句:内部 bank 数是 4,不是 2,配成 2 会让高位地址镜像,跑到 32MB 之后就开始覆盖前面的内容。
3.2 SDRAM 控制器初始化参数与上电序列
参数不能抄别人的工程,得按器件手册算。下面是这块板子对应的初始化骨架,注释里写了每个值的来源。
/* 32 位双片 SDRAM 的 FMC 配置骨架 */ FMC_SDRAM_InitTypeDef init; FMC_SDRAM_TimingTypeDef timing; init.SDBank = FMC_SDRAM_BANK1; /* 0xC0000000 */ init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; /* 9 位列地址 */ init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; /* 13 位行地址 */ init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32; /* 两片拼 32 位 */ init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; /* 器件内 4 bank */ init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; /* 100MHz 下取 CL=3 */ init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; init.ClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; /* SDCLK = HCLK3/2 */ init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1; timing.LoadToActiveDelay = 2; /* tRCD,单位 SDCLK 周期 */ timing.ExitSelfRefreshDelay = 7; /* tXSR,退出自刷新到可访问 */ timing.SelfRefreshTime = 4; /* tRAS,最小行有效时间 */ timing.RowCycleDelay = 7; /* tRC,行周期 */ timing.WriteRecoveryTime = 2; /* tWR,写恢复 */ timing.RPDelay = 2; /* tRP,预充电时间 */ timing.RCDDelay = 2; /* tRCD,与 LoadToActiveDelay 对应 */光配结构体不够,上电后必须按固定序列走:先等 100~200 微秒让电源稳定,再发预充电全部 bank 命令,接着发 8 次自动刷新,然后写模式寄存器(突发长度、CAS 延迟、顺序模式),最后才使能时钟。少任何一步,读回来的数据就是随机值。把这段序列封装成sdram_init(),在上电后第一时间跑,别放在 RTOS 启动之后。
3.3 Dual QSPI 的真实结构:共享 IO、独立片选
这里要把一个说法纠正清楚:摘要里写“8 位数据宽度”,实际物理结构是两片独立的 4 位 QSPI 器件,共享 PB2 时钟和 PF6~PF9 四根 IO,各自带独立片选。它并不能像并行总线那样一次传 8 位,而是“两片四线、容量翻倍、带宽不变”。这个区别直接影响程序怎么写:如果你的代码按 8 位并行去读,永远读不对。
正确的用法是把它当成两个独立存储区:一片放主程序和常量,另一片放字库、图片或音频资源。运行时先配好两个 bank 的地址映射,读写时切换片选。因为 QSPI 走的是内存映射模式,CPU 可以直接从 0x90000000 取指,把最热的代码段放到执行更稳定的那一片上,另一片放冷数据,这样既省 RAM 又不牺牲启动速度。要注意的是,两片共享 IO,任何时刻只能有一片处于激活状态,切换片选前必须先让当前片退出内存映射模式,否则会出现“程序突然跑飞”的现象——这种问题的现场表现很像电源不稳,非常容易查错方向。
3.4 链接脚本与内存布局:把帧缓冲搬到 0xC0000000
外部 SDRAM 只有在链接脚本里显式声明,编译器才会把它当普通内存用。这块板子按下面的方式切三块内存:
/* 只列关键段,其余保持默认 */ MEMORY { DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K /* 最高速,放栈和热变量 */ RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K /* AXI SRAM,放 DMA 缓冲 */ SDRAM (xrw) : ORIGIN = 0xC0000000, LENGTH = 64M /* 外部 32 位 SDRAM */ } SECTIONS { .sdram_fb (NOLOAD) : { . = ALIGN(32); *(.sdram_fb) . = ALIGN(32); } > SDRAM }NOLOAD很重要,它表示这段不参与镜像加载,上电后不会被清零,适合放帧缓冲这种“写满再读”的区域,能省下几十毫秒的启动时间。DMA 缓冲放 RAM_D1 而不是 SDRAM,是因为 SDRAM 有刷新周期,突发访问时延不固定,做以太网或 USB 的 DMA 目标容易丢包。栈一定留在 DTCM,那里没有缓存一致性问题。
4. 电源与模拟基准:3.3V~5V 宽压输入、限流与独立 VREF 的设计
4.1 电源树:升降压芯片与 LDO 的分工
输入电压范围 3.3V 到 5V,意味着纯降压或纯升压都不行:3.3V 输入时要出 3.3V,压差接近零;5V 输入时要降到 3.3V。所以这张图用了升降压器件做主变换,把输入先稳到中间轨,再用 LDO 分出低噪声的模拟支路。主变换负责功率,LDO 负责干净,这个分工在带 ADC 的板子上几乎是标配。
设计上要注意的是反馈分压比。这类升降压器件的反馈参考通常只有几百毫伏,目标 3.3V 时的分压比约 5.6 倍,下偏置取 10K、上偏置取 56K 是常见组合;如果原理图里给的是 6.8K 和 4.7K 一组值,先别急着改,拿万用表实测输出再决定——分压电阻算错是这块板子最容易返工的一处,焊上去才发现出 1.2V 就晚了。电感取值按开关频率和纹波电流反算,输入输出各放 10uF 以上陶瓷电容,紧贴器件引脚,这是抗负载跳变的基础。
4.2 限流电阻与过流保护的取值
“内置限流芯片”这句话在图上对应的是输入侧的限流与滤波组合:一个磁珠加一组 RC,作用是抑制上电浪涌和限制短路电流。磁珠在 100MHz 处呈 600 欧姆左右的阻抗,能挡住连接器引入的高频噪声,但它的直流电阻必须小,否则压降会吃掉一部分输入裕量。选型时看两个参数:额定电流要大于整板峰值电流的 1.5 倍,直流电阻控制在几十毫欧以内。
过流保护不是“加上就完事”,要跟负载匹配。整板峰值出现在 SDRAM 全速读写加 LCD 刷新的时候,通常在几百毫安量级;限流点设在峰值的 1.5 到 2 倍之间,既能扛住瞬态又不至于在异常时烧线。这里有个血泪经验:如果限流点设太低,冷启动时电容充电电流会把电压拉塌,表现是“每次上电要按两次复位才能起来”,很多人会去怀疑复位电路,其实是限流在起作用。
4.3 独立基准与去耦网络
为什么要单独放一颗基准芯片?因为 ADC 的精度上限由参考电压决定,而数字电源上叠加着 SDRAM 刷新和 LCD 刷屏产生的纹波。用 VDD_3V3 直接当 VREF+,12 位 ADC 实际有效位数可能只剩 9 位。这张图里 VREF+ 走独立支路,从基准芯片出来经过 RC 滤波再进芯片的 VREF+ 脚,旁边配 100nF 加 10uF 的组合,一颗管高频、一颗管低频。
去耦网络的排布原则按“近、小、多”来:每对 VDD/VSS 旁边一颗 100nF,距离不超过 2mm;每个电源域入口一颗 10uF;VCAP 脚按规定容量单独接,不能和其他电容混用。原理图里密密麻麻的 100nF(C13、C15、C16、C18~C21、C23、C26、C27、C33~C37 等)不是凑数,它们每一个都对应一组电源引脚。抄这张图的时候,去耦电容一个都不能省,尤其是 BGA 背面那一圈,省掉之后板子能跑,但过 EM C 测试或者高温老化时就容易出问题,属于典型的“当时省事、后面返工”。
5. 避坑与排查:这块板子最容易翻车的五个地方
5.1 SDRAM 能读能写但数据随机翻转
现象是跑内存测试时大部分地址通过,少数地址读回值和写入值差一两个 bit,重启之后出错的地址还会变。原因通常出在字节掩码上:32 位拼接时,第二片的 NBL2/NBL3 没接、接反,或者被误当成普通 GPIO 复用掉了,导致高 16 位的写掩码失效,半字写入时低字节被意外覆盖。另一种可能是等长没做,D16~D31 这一组的走线比 D0~D15 长出一大截,在时钟边沿附近采样就随机出错。解决办法是先写一个只测单字节的用例,把 0x00、0xFF、0x55、0xAA 分别写到每个字节位置再读回,定位到具体哪几位出错;如果错的是整段高 16 位,直接去查 NBL2/NBL3 的网络连接。
5.2 把双 QSPI 当 8 位并行总线用
现象是从外部 Flash 读出的数据和写入的完全对不上,或者程序能启动但一访问资源区就死机。原因是把“两片 4 位器件”理解成了“一根 8 位总线”,代码里按 8 位宽度去拼数据。实际结构是共享时钟和 IO、独立片选,同一时刻只有一片在通信。解决方式是把两片当两个独立设备管理,切换前先让当前片退出内存映射模式,配置好再重新进入;同时确认两片的片选没有接在同一根线上,否则会出现两个器件同时驱动 IO 的冲突,长期跑还有损坏风险。
5.3 上电偶发不启动,复位一次就正常
现象是冷启动时大约十次里有一两次卡死,按下复位键就能正常跑。原因多半在电源斜坡:3.3V 到 5V 宽压输入经过升降压之后,主轨建立时间和复位释放时间不匹配,芯片在电压还没稳的时候就完成了复位,开始取指,读到的是无效数据;也可能是 PDR_ON 引脚的处理不当,让内部上电复位电路在临界电压附近反复触发。解决办法是给复位脚加 RC 延时,把释放时间往后推几十毫秒,同时确认 BOOT0 有明确的下拉,不要悬空。这类问题最像“玄学”,但只要在电源和复位脚上挂示波器看一次上电波形,基本一眼就能看出来。
5.4 基准电压被数字噪声污染,ADC 读数跳
现象是 ADC 采同一个稳定信号,读数在几十个 LSB 范围内跳动,换一块板子又好了。原因通常是 VREF+ 的走线从 SDRAM 或者电源电感下面穿过,或者基准芯片离数字区太近、退耦不足。解决方式是把 VREF+ 单独走一条线,两侧包地,串一颗小磁珠再进芯片,基准芯片的地单独回到模拟地,不要和数字地混在一个过孔上。如果已经投板,可以试着在 VREF+ 上并一颗 1uF 电容看跳动是否减小,能减小就说明是噪声耦合而不是基准本身的问题。
5.5 连接器插拔几次后接触不良
现象是板子插在底板上时好时坏,轻压一下又正常。原因是板对板连接器的引脚间距很小,反复插拔后弹片形变,加上核心板只有 29.5mm 宽,插拔时的侧向力全部作用在连接器上。解决办法是在结构上增加定位柱或者螺孔,让插拔力由结构承担而不是连接器焊盘;电气上可以在关键信号(复位、时钟)旁边并小电容做滤波,但不能并太大,否则会拖慢边沿。这类问题在答辩现场最容易出现,建议成品板插拔次数控制在几十次以内,演示前用固定支架。
6. 验收与答辩:从上电时序到全片读写的一份检查清单
原理图交付前,我一般按“静态检查 → 上电时序 → 存储自检 → 外设联通”四步走,每一步都有可交付的证据,答辩时直接拿波形和日志说话,比讲设计思路有说服力。
| 阶段 | 检查项 | 通过标准 |
|---|---|---|
| 静态 | 电源对地阻抗 | 3.3V 对地不短路,阻值在几十欧以上 |
| 静态 | 网络标号一致性 | BGA 引脚、去耦电容、连接器三处网络名统一 |
| 上电 | 主轨建立时间 | 上电到 3.3V 稳定小于 10ms,无过冲 |
| 上电 | 复位释放 | NRST 在电源稳定后至少 20ms 才拉高 |
| 存储 | SDRAM 全片读写 | 64MB 遍历写 0x5A5A5A5A 与 0xA5A5A5A5,错误数为 0 |
| 存储 | QSPI 双片识别 | 两片 ID 都能读回,容量各 32MB |
| 外设 | 串口与 USB | 枚举正常,回环测试无误码 |
| 外设 | 显示接口 | 全屏刷色无撕裂、无花屏 |
SDRAM 自检建议写成可复现的函数,遍历时按 1MB 步长做全片扫描,出错就打印首错地址:
/* 全片读写自检:返回错误个数,首错地址写入 err_addr */ uint32_t sdram_scan(uint32_t *err_addr) { uint32_t *base = (uint32_t *)0xC0000000UL; uint32_t n = (64UL * 1024 * 1024) / 4; /* 64MB / 4 字节 */ uint32_t i, err = 0; for (i = 0; i < n; i++) base[i] = 0x5A5A5A5A; /* 第一遍写图案 A */ for (i = 0; i < n; i++) { if (base[i] != 0x5A5A5A5A) { if (err == 0) *err_addr = (uint32_t)&base[i]; err++; } } for (i = 0; i < n; i++) base[i] = 0xA5A5A5A5; /* 第二遍写反码,抓粘连 */ for (i = 0; i < n; i++) { if (base[i] != 0xA5A5A5A5) { if (err == 0) *err_addr = (uint32_t)&base[i]; err++; } } return err; }两遍反码图案是有意为之:只写一种图案,某些位之间的短路看不出来,写反码能抓出相邻数据线粘连。跑完这一遍,如果错误数是 0,SDRAM 这一块基本可以签字了;如果错误集中在某个地址区间,回去翻原理图看那个区间的 bank 位有没有接错。
答辩时最常被问的两个问题是“为什么用两片 16 位而不是一片 32 位”和“Flash 为什么是两片”。第一个答带宽和成本:32 位单片的封装大、价格高,两片 16 位在 29.5mm 宽度内更好布,还能用同一型号降低采购复杂度。第二个答容量和分区:64MB 的空间可以拆成代码区和资源区,升级资源时不用动程序。把这些答案和上面的检查表一起准备好,基本不会被追问到卡壳。
从那以后我每次画完存储部分,都会强制自己先用万用表把每一根 NBL 和片选量一遍再投板,因为这个位置错一次,返工成本就是一整轮打样周期。希望这套流程能帮到你。
本文还有配套的精品资源,点击获取