简介:这是一份面向嵌入式硬件工程师与STM32H7开发者的核心板原理图PDF,围绕STM32H750XBH6最小系统展开,可用于硬件设计参考、接口核对与项目集成评估。图纸完整呈现双片32MB SDRAM组成32位宽、共64MB内存,以及两片W25Q256构成的8位宽64MB Dual Quad SPI Flash存储方案,并给出6层板、29.5mm×32mm小尺寸模块的电源管理、限流保护、独立模拟基准、LDO、LED指示及FMC、QSPI、GPIO等连线信息;SDRAM的地址、数据与控制信号,QSPI的时钟、数据线与片选,以及复位、启动和EEPROM连接均有体现,便于核对引脚复用与电源树。包内共1个PDF文件,约87KB,单文件便于快速查阅与打印对照,也方便按电源、存储与接口区域逐页阅读。该资源已有3111人学习,适合需要理解H7核心板存储扩展、电源树与引脚分配的中高级开发者,也可为紧凑型工业控制、医疗设备与消费电子项目提供可落地的参考蓝本,帮助缩短选型与原理图评审周期。
1. 29.5mm×32mm 的核心板:把 64MB SDRAM 和 64MB QSPI Flash 塞进邮票大小
一块核心板能做到 29.5mm×32mm,基本就是一枚邮票的尺寸。这份《STM32H750XBH6 核心板原理图(PDF)》的看点正在这里:主控是 STM32H750XBH6,外扩两片 32MByte SDRAM 并成 32 位宽,凑出 64MB 的连续内存空间;再外挂两片 W25Q256,做成 8 位数据宽度的 QSPI Flash,总容量 64MB。小尺寸、大内存、双 SDRAM、双 QSPI Flash,这四个词加在一起就是它想解决的问题——H750 片内那 1MB Flash 和 1MB RAM,跑个 GUI 帧缓冲、音频环形队列或者图像缓存就没了,而这份 PDF 给出了一条可以直接照抄的外扩路径。它适合两类人:一类是正在做 H7 小尺寸方案选型、想拿现成拓扑改自己板子的硬件工程师;另一类是手上已经有 H750 板子、却始终搞不清 FMC 和 QSPI 到底该怎么接的固件工程师。下面按电源树、SDRAM、QSPI、避坑、上电验证这个顺序往下拆。
2. 电源树拆解:TPS63000 升降压打底,XC6206 与基准芯片各管一段
拿到原理图的第一件事不是看主控,是看电源。H750 号称 480MHz 主频,核心电流随负载跳变得厉害,电源树没理顺,后面所有调试都会变成玄学:程序跑着跑着 HardFault、ADC 读数乱跳、USB 枚举失败,最后查半天发现是某一路纹波太大。这份 PDF 的电源部分分了三段:前级是 TPS63000 做的升降压,中间是 XC6206 这类低压差线性稳压器做二次净化,最后还有一路独立的模拟基准,专门喂 VREF+。
2.1 为什么输入 3.3V~5V 必须先过一颗升降压而不是 LDO
核心板标称支持 3.3V~5V 输入,这个宽压范围如果直接用 LDO 实现,会遇到两个无法回避的问题。第一是压差,输入 3.3V 时,普通的 3.3V 输出 LDO 压差不够,输出会跟着输入往下掉,主控可能进入欠压复位;第二是功耗,5V 降到 3.3V,压差 1.7V,核心板加上 SDRAM 和 Flash 的静态电流按 400mA 估算,LDO 上就要白白烧掉 0.68W,在 29.5mm×32mm 这块面积上根本没有地方散,板子摸上去会明显发烫。
TPS63000 是四开关升降压拓扑,输入高于、低于、接近输出时都能稳压,原理图里它外围挂的是 2.2uH 功率电感和输入输出各 10uF 的陶瓷电容,这是它典型的外围配置。电感的饱和电流要按峰值电流选,别只看平均值;两端的 10uF 要用低 ESR 的 X5R/X7R,别拿普通铝电解凑数,否则开关瞬间的电压跌落会直接打到主控的供电脚上。
PS/SYNC这个脚在原理图上通过电阻网络接向输入侧,它的电平决定了芯片是工作在省电模式还是强制 PWM 模式。做低功耗产品希望轻载时效率高,就让它悬空或拉低;做射频、ADC 采样这类对纹波敏感的场景,就把它拉高强制 PWM,牺牲一点效率换干净的输出。这个选择在投板前就要定下来,改电阻比改布线容易得多。
2.2 FB 分压不是抄个阻值就行,改电压要重新算
TPS63000 的反馈脚内部基准是 0.5V,输出电压由 FB 脚上的两个分压电阻决定,公式是Vout = 0.5 × (1 + R上 / R下)。原理图上这两个位置是 6.8K 和 4.7K 这一档,很多人照着抄的时候只改其中一个电阻,结果输出变成 1.2V 或者 4V 这种奇怪的值,然后回头怀疑电感、怀疑电容,其实问题就出在分压比上。
动手改之前,先用一段脚本把常用阻值扫一遍,比拿计算器按半天靠谱:
# 按 TPS63000 的 0.5V 内部基准反推 FB 分压,改电压必须先跑一遍 VBREF = 0.5 def vout(r_top, r_bot): """r_top 接 VOUT 与 FB 之间,r_bot 接 FB 与 GND 之间,单位欧姆""" return VBREF * (1 + r_top / r_bot) def pick(target, e96): """在 E96 阻值表里找最接近目标电压的上下分压组合""" best = None for rt in e96: for rb in e96: v = vout(rt, rb) if best is None or abs(v - target) < abs(best[0] - target): best = (v, rt, rb) return best # E96 常用档位,乘 1k 得到欧姆 E96 = [1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82, 100] e96_ohm = [x * 1000 for x in E96] print(pick(3.3, e96_ohm)) # 目标 3.3V print(pick(1.8, e96_ohm)) # 若外设需要 1.8V 轨跑出来的结果会告诉你哪一组阻值最接近目标,误差通常在 1% 以内。这里有个细节:下分压电阻不要选得太小,否则静态电流白白流掉;也不要选得太大(比如几百 K),FB 脚的漏电流会把精度带偏。经验值一般落在 10K~100K 这个区间。
旁边那颗 100pF 的小电容是前馈电容,并在上分压电阻上。它的作用是在负载瞬变时给反馈环路提供一条快速通路,提升相位裕度。前馈电容不是越大越好,取值过大反而会在开关频率附近引入尖峰,典型值就在 100pF 到几百 pF 之间,照着原图抄一般不会出问题,但如果换了大电感或者改了开关频率,这个值要重新评估。
2.3 XC6206 与独立基准:模拟域和数字域要分开喂
数字电源稳了才轮到模拟。原理图里除了主 3.3V 轨,还有一路单独出来的 3.3V,通过 XC6206 这类小电流 LDO 二次稳压,外围配 1uF 输入、1uF 输出再加 100nF 高频去耦。这一路通常喂给 ADC 参考、运放、传感器接口这类模拟电路。XC6206 的压差和噪声指标一般,但它便宜、外围简单,放在核心板上作为“二次净化”够用。
关键在于它前面已经有一级开关电源。开关电源的输出纹波在几十 mV 量级,直接给 ADC 用会看到读数末位狂跳;串一级 LDO 之后,高频纹波被压下去一大截,再配上去耦电容,静态采样能稳到几个 LSB 以内。这是常见做法,成本只多一颗 LDO 加几颗电容,效果比在软件里做几十次平均要实在。
真正决定 ADC 精度的是那路独立的模拟基准。原理图上 VREF+ 并没有简单并到 3.3V 数字轨上,而是走了一颗专门的基准器件,旁边有分压电阻和 100nF 去耦,VREF-单独接地。这一步的意义在于把 ADC 的满量程从“跟着数字电源漂”变成“跟着一颗低噪声基准走”。如果偷懒把 VREF+ 直接接到 3.3V 轨上,主控跑满载时电源往下掉 30mV,ADC 的满量程就跟着变形,采样值整体偏移,而且这种偏移在不同负载下还不一样,标定都标不回来。
同样的道理适用于晶振。25MHz 主晶振旁边那两颗 22pF 负载电容,和 32.768kHz 低速晶振旁边的 6pF,都是按晶体厂家给的负载电容算出来的,不是随便填的。遇到 USB 枚举不稳定、RTC 走时偏快偏慢,先看这两组电容,别一上来就怀疑芯片。
3. 双 SDRAM 并成 32 位宽:FMC 引脚怎么对,时序怎么反推
H750 的 FMC 支持 SDRAM,这是它比普通 Cortex-M7 芯片强的地方。原理图里挂了两片 W9825G6,单片是 4M×16bit×4 banks,也就是 32MByte,两片并联组成 32 位数据宽,总容量 64MByte,地址空间从 0xC0000000 开始,走 FMC 的 SDRAM Bank1。
3.1 为什么是 32 位宽而不是 16 位,地址线为什么要错一位
32 位宽的意义不只是带宽翻倍。H750 的 FMC 在 32 位模式下,一次访问就能把一个 32 位变量完整取回来;16 位模式下一次只能取一半,编译器生成的 32 位读写会被拆成两条总线操作,代码里那些memcpy、DMA 搬运、帧缓冲写入的实际吞吐会明显下降。对于要跑 GUI 或者图像处理的项目,这个差别能到 30% 以上。
代价是地址线要错一位。32 位宽意味着一个地址对应 4 个字节,SDRAM 侧的 A0 实际接的是 MCU 侧的 A1,A1 接 A2,依此类推。这一点在原理图上不容易看出来,因为图纸上标的是网络名,不是物理连线顺序。如果打样回来发现读写地址整体偏移一倍,或者*(uint32_t*)0xC0000000和*(uint32_t*)0xC0000004读到同一块数据,八成就是这里接错了。检查方法是看 FMC_A0 到 FMC_A12 这组网络名在 SDRAM 侧的落点,A0 应该落在 SDRAM 的 A1 上。
除了数据线,控制线也要一一对上。原理图这一段的映射关系整理成表更清楚:
| FMC 信号 | MCU 引脚 | 接到 SDRAM 侧 | 作用 |
|---|---|---|---|
| FMC_SDCLK | PG8 | 两片 CLK | 同步时钟,走线要等长 |
| FMC_SDNE0 | PC2 | 两片 CKE/CS | Bank1 片选与时钟使能 |
| FMC_SDNCAS | PG15 | 两片 CAS | 列地址选通 |
| FMC_SDNRAS | PF11 | 两片 RAS | 行地址选通 |
| FMC_SDNWE | PC0 | 两片 WE | 写使能 |
| FMC_BA0/BA1 | PG4/PG5 | 两片 BA0/BA1 | Bank 地址,并联 |
| FMC_NBL0~NBL3 | PE0/PE1/PI4/PI5 | 分接两片 UDQM/LDQM | 字节掩码,32 位必须用满 4 根 |
| FMC_D0~D31 | 见 PDF | 低 16 位接第一片,高 16 位接第二片 | 数据总线 |
注意FMC_NBL2/NBL3这两根。在 16 位模式下只用到 NBL0/NBL1,很多人从旧工程迁移过来时忘了补上高字节掩码,结果只有低 16 位能写,高 16 位永远是 0 或者 0xFFFF,跑 32 位运算时数据全乱。这个坑非常典型,因为编译不会报错,只有实际读写才暴露。
3.2 时序参数不是拍脑袋填的,要按手册换算成 SDCLK 周期
SDRAM 初始化失败最常见的原因就是时序填错。HAL 库里的FMC_SDRAM_TimingTypeDef有七个字段,单位都是 SDCLK 周期数,不是纳秒。所以第一步要确定 SDCLK 频率:H750 的 FMC 时钟来自 HCLK3,常见配置是 100MHz 或者 120MHz 一档。
确定了频率,一个周期是 10ns,再把 W9825G6 手册上的 tRCD、tRP、tRC、tWR、tXSR 这些纳秒值往上取整除一下,就得到周期数。比如 tRCD 最小 15ns,10ns 一个周期,取 2 个周期;tRC 最小 60ns,取 6~7 个周期。装箱的时候宁可多给一拍也别少给,多一拍的代价是访问慢一点点,少一拍的代价是随机性读写错误,而且温度一变就变。
/* 两片 W9825G6 并联成 32 位宽,SDCLK = 100MHz(10ns/拍) */ FMC_SDRAM_TimingTypeDef sdram_timing = {0}; sdram_timing.LoadToActiveDelay = 2; /* tRCD 15ns -> 2 拍 */ sdram_timing.ExitSelfRefreshDelay = 8; /* tXSR 70ns -> 7 拍,留 1 拍余量 */ sdram_timing.SelfRefreshTime = 5; /* tRAS 42ns -> 5 拍 */ sdram_timing.RowCycleDelay = 7; /* tRC 60ns -> 6 拍,留 1 拍余量 */ sdram_timing.WriteRecoveryTime = 2; /* tWR 15ns -> 2 拍 */ sdram_timing.RPDelay = 2; /* tRP 15ns -> 2 拍 */ sdram_timing.RCDDelay = 2; /* tRCD 15ns -> 2 拍 */ /* 控制器本体:32 位宽、4 个 bank、行列地址位数按 4M×16×4 反推 */ FMC_SDRAM_InitTypeDef sdram_init = {0}; sdram_init.Bank = FMC_SDRAM_BANK1; sdram_init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; /* 512 列 */ sdram_init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; /* 8192 行 */ sdram_init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_32; /* 关键:32 位 */ sdram_init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; sdram_init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; /* 100MHz 下用 CL3 */ sdram_init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; sdram_init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; sdram_init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; sdram_init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;参数说明几句。ColumnBitsNumber和RowBitsNumber决定控制器发出的地址拆分方式,跟颗粒的物理组织必须一致,填错了表现为“只有前几 MB 能读写”。MemoryDataWidth设成 32 位是这块板子的核心差异点,设成 16 位会导致高 16 位数据线完全不参与。CASLatency在 100MHz 下一般用 CL3,如果时钟拉到 120MHz 以上可能需要放宽。
时序配完还要下发初始化命令序列,顺序不能乱:先开时钟使能,再发预充电全部 Bank,然后连发 8 次自动刷新,最后加载模式寄存器。这个序列漏一步,SDRAM 就处于未定义状态,读写返回值不可预测。
/* 初始化命令必须按顺序发,漏一步 SDRAM 就处于未定义状态 */ FMC_SDRAM_CommandTypeDef cmd = {0}; cmd.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; /* 1. 时钟使能 */ cmd.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1; HAL_SDRAM_SendCommand(&hsdram, &cmd, 0xFFFF); HAL_Delay(1); /* 等 100us 以上再继续 */ cmd.CommandMode = FMC_SDRAM_CMD_PALL; /* 2. 全部预充电 */ HAL_SDRAM_SendCommand(&hsdram, &cmd, 0xFFFF); cmd.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;/* 3. 自动刷新 8 次 */ cmd.AutoRefreshNumber = 8; HAL_SDRAM_SendCommand(&hsdram, &cmd, 0xFFFF); cmd.CommandMode = FMC_SDRAM_CMD_LOAD_MODE; /* 4. 加载模式寄存器 */ cmd.ModeRegisterDefinition = (uint32_t)0x0230; /* CL3 + 顺序突发 + 突发长度 8 */ HAL_SDRAM_SendCommand(&hsdram, &cmd, 0xFFFF); /* 刷新计数器按 SDCLK 频率算:100MHz × 64ms / 8192 行 ≈ 781 */ HAL_SDRAM_ProgramRefreshRate(&hsdram, 781);模式寄存器那个0x0230不是随手写的魔数,它由 CAS 延迟、突发类型、突发长度几段拼出来,跟上面CASLatency的设置必须对得上,两边不一致会出现“单次读写正常、连续突发就错位”的怪现象。最后那个刷新速率 781 是按 64ms 内刷完 8192 行算出来的,时钟变了这个值也要跟着改,忘了改会表现为跑几分钟后内存随机翻转。
4. 双片 W25Q256 的 8 位 QSPI:地址模式切不过去就白搭
Flash 这部分比 SDRAM 更容易翻车,因为它的坑大多藏在协议层而不是电气层。原理图上是两片 W25Q256,单片 32MByte,合起来 64MByte,标称 8 位数据宽,通过 QUADSPI 接到主控。H750 的 QUADSPI 支持双闪存模式,两片各占一组片选和一组四线 IO,合起来正好 8 位。
4.1 双片并联怎么理解,为什么不是简单并联
很多人第一反应是“两片 Flash 并联不就是容量翻倍吗”,其实不是。并联数据线只能扩位宽,不能扩容量;要扩容量必须让两片各自有独立的片选,主控按地址去选片。所以原理图上能看到两片 Flash 共用 SCK,但片选是分开的,分别接到 QUADSPI 的两个片选脚上。
这样做的收益是带宽:单片的四线 QSPI 在 100MHz 下理论带宽 50MB/s,双片并成八线之后翻倍。对于要从外部 Flash 直接执行代码(XIP)的场景,这个带宽直接决定程序跑起来卡不卡。代价是配置复杂,两片的模式必须一致,任何一片没进四线模式或者没开地址扩展,整个八线访问都会失败。
两片都工作在四线模式之后,容量合成 64MByte,映射到 0x90000000 起的连续地址空间。但这里有个硬约束:W25Q256 是 256Mbit 的颗粒,内部地址是 32 位的,出厂默认工作在 3 字节地址模式,只能寻址前 16MByte。超过 16MByte 的部分,必须发指令切到 4 字节地址模式,否则读回来全是无效数据。
4.2 4 字节地址模式:最容易漏的一步
这是整块板子最典型的翻车点。烧进去的程序放在 0x90000000 附近时一切正常,一旦程序超过 16MByte,或者把资源文件放到 0x91000000 之后,读到的东西就全是 0xFF。很多人以为是 Flash 坏了,或者焊接有问题,实际上就是地址模式没切。
正确做法是在初始化阶段,对两片 Flash 分别发一次进入 4 字节地址模式的指令,然后再配置内存映射。注意是“分别”,两片都要发,只发一片的话另一片仍然停留在 3 字节模式。
/* W25Q256 超过 16MByte 必须切 4 字节地址模式,两片都要切 */ static void flash_enter_4byte_mode(QSPI_HandleTypeDef *hqspi) { QSPI_CommandTypeDef cmd = {0}; cmd.Instruction = 0xB7; /* Enter 4-Byte Address Mode */ cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE; cmd.AddressMode = QSPI_ADDRESS_NONE; cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; cmd.DataMode = QSPI_DATA_NONE; cmd.DummyCycles = 0; cmd.NbData = 0; /* 片选 1 */ cmd.Address = 0; HAL_QSPI_Command(hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); HAL_QSPI_AutoPolling(hqspi, &(QSPI_AutoPollingTypeDef){ .Match = 0, .Mask = 0, .MatchMode = QSPI_MATCH_MODE_AND, .StatusBytesSize = 1, .Interval = 0x10 }, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); /* 片选 2,同一套指令换片选再发一遍 */ cmd.Instruction = 0xB7; /* 部分 HAL 版本用 QSPI_Config 切片选,这里按实际库补一句片选切换 */ HAL_QSPI_Command(hqspi, &cmd, HAL_QSPI_TIMEOUT_DEFAULT_VALUE); }这段代码里的关键点是Instruction = 0xB7。这是 W25Q256 的进入 4 字节地址模式指令,不同厂家的颗粒指令码可能不一样,换颗粒必须查手册。另外注意,进入 4 字节模式之后,后续所有读写指令的地址字段都要按 4 字节下发,包括QSPI_CommandTypeDef里的AddressSize要设成QSPI_ADDRESS_32_BITS,忘了改就会地址截断,读到完全不相干的位置。
除了地址模式,四线模式使能位(QE 位)也是常见漏项。W25Q256 出厂时 QE 位是 0,必须往状态寄存器 2 里写 1 才能进四线模式。这一步通常在首次上电时做一次,写完之后掉电保存。如果板子上电后 QSPI 只能以单线跑,速度慢得离谱,先查这个位。
4.3 内存映射之后怎么验证真的通了
配置完 QSPI 进内存映射模式,最直接的验证不是烧程序,是直接读。用调试器在内存窗口看 0x90000000 开始的一段,正常应该能看到 Flash 里的内容,通常是启动向量表,前四个字节是栈顶地址,紧接着是复位向量,指向 0x9000xxxx 这个范围。如果看到全 0xFF,说明读到的是擦除态或者根本没通;如果看到全 0x00,可能是地址没对上或者片选一直没拉起来。
再进一步可以做交叉验证:把同一个固件同时烧到 0x90000000 和 0x92000000,也就是第一片和第二片各自的开头,然后分别读回来比对。这一步能确认两片的片选和地址映射都是独立的,而不是简单镜像。这个验证我在第一次做双 Flash 板子时没做,结果上板发现第二片根本没响应,回头查是片选网络名在原理图上写错了,飞线补救的。
5. 避坑清单:照着这份 PDF 打板前必须复核的五件事
原理图能抄,但抄错一个网络名就够喝一壶。下面五条是我在同类板子上真实踩过的,按“现象 → 原因 → 解决”排开。
5.1 SDRAM 读写全是 0xFFFF 或随机值
现象:程序能跑起来,但一访问 0xC0000000 就 HardFault,或者在调试器里看到整片内存都是 0xFFFF,偶尔是随机数。
原因:九成是 FMC 时序没配对。常见的是SDClockPeriod设成 2 分频但时序按 1 分频算的,或者RowCycleDelay给少了。还有一种隐蔽情况是刷新速率没按实际 SDCLK 算,跑几分钟才开始出错,非常迷惑。
解决:先用最慢的时序试通,把七个时序字段全部往上加 1~2 拍,刷新速率按SDCLK × 64ms / 行数重算,确认能稳定读写之后再逐项往下压。压的过程中写个简单的读写循环,跑满 64MB 全片比对,别只测前几 KB。
5.2 程序超过 16MB 之后跑飞
现象:小工程烧进去正常,工程一大就起不来,或者运行到某个资源加载点直接 HardFault。
原因:W25Q256 还在 3 字节地址模式,超过 16MByte 的地址被截断,读到的指令是错的。
解决:初始化阶段对两片 Flash 都发 0xB7 进入 4 字节模式,同时把 QSPI 命令的地址长度改成 32 位。验证方法是往 0x91000000 写一段特征数据再读回,对得上才算过。
5.3 板子上电发烫,主控反复复位
现象:接 5V 供电,板子几秒钟就明显发热,主控间歇性复位。
原因:TPS63000 的 FB 分压抄错,输出不是 3.3V 而是更高,后级 LDO 和主控全部过压。或者是PS/SYNC脚电平接反,芯片工作在异常模式。
解决:上电前先用万用表量 FB 脚对地电压,正常应该在 0.5V 左右;上电后先空载量输出电压,确认在 3.3V±3% 再去接主控。分压电阻按 2.2 节那段脚本重算,别凭感觉。
5.4 ADC 采样值整体偏移,且随负载变化
现象:静态采样看着还行,一跑大负载 ADC 读数整体往下掉几十个 LSB,标定也标不准。
原因:VREF+ 直接接到了数字 3.3V 轨上,没有走独立基准。主控满载时电源纹波和压降直接反映到满量程上。
解决:按原理图把 VREF+ 改成由独立基准供电,基准旁边配 100nF 加 1uF 两级去耦,VREF- 单独走一根地到模拟地。改完再测,同样的负载跳变下读数应该基本不动。
5.5 USB 枚举时好时坏,RTC 走时偏快
现象:同一块板子,有时候插上就识别,有时候要插拔好几次;RTC 一天快十几秒。
原因:晶振负载电容不对。25MHz 主晶振旁边那两颗电容是按晶体厂家的负载电容算的,换了型号没跟着改;32.768kHz 那颗同理,6pF 的负载电容对走时精度影响很大。
解决:按晶体规格书上的负载电容公式CL = C1 × C2 / (C1 + C2) + Cs反算,其中 Cs 是杂散电容,一般取 3~5pF。算完之后用示波器看起振波形和频率偏差,别只靠“能起来就行”。
6. 上电验证顺序:从输入到 VCAP,按这个顺序量一遍再谈调试
拿到一块新打的板子,最忌讳的就是直接插调试器烧程序。我现在的习惯是:不通电先量阻抗,通电后按电源树的顺序一级一级往上量,每一级都对上期望值才往下走。这样做看着慢,实际上省掉的是后面几小时的瞎猜。
具体顺序整理成表,照着走一遍大概十分钟:
| 顺序 | 测点 | 期望值 | 不对时先查什么 |
|---|---|---|---|
| 1 | 输入 VIN 对 GND | 3.3~5.0V | 接插件焊盘、限流芯片是否导通 |
| 2 | VDD_SYS 对 GND | 3.3V ±3% | TPS63000 的 FB 分压、电感是否虚焊 |
| 3 | VDD_3V3_M 对 GND | 3.3V ±3% | XC6206 的 EN 脚电平、输入是否到位 |
| 4 | VREF+ 对 VREF- | 按基准器件标称 | 分压电阻、基准去耦电容 |
| 5 | VCAP1/VCAP2 对 GND | 约 1.2V | 电容容值是否漏贴、极性是否反 |
| 6 | NRST 对 GND | 上电后拉高至 3.3V | 复位电容、BOOT0 电平 |
第 5 项那个 VCAP 特别值得说一句。H7 系列的内核需要外接电容给内部稳压供电,这两颗电容漏贴或者容值不对,表现是“程序能烧进去但一跑就挂”,而且挂的位置每次都不一样,非常像软件 bug。我见过有人为了这个查了三天代码,最后发现是 VCAP 电容贴成了 100nF 而不是 2.2uF。
量完电源再上调试器。第一件事不是烧业务程序,是烧一个最小工程:点灯、串口打印、然后对 SDRAM 做全片读写测试、对 QSPI 做地址越界读测试。这三件事都过了,才说明硬件拓扑没问题,后面跑复杂程序才有意义。顺序反了的话,一个内存错误能被误判成 RTOS 调度问题,排查成本翻好几倍。
还有一个小技巧:SDRAM 全片测试别只写固定图案。先写 0x55555555、再写 0xAAAAAAAA,两次都读回比对,能揪出相邻数据线短路;再写一遍地址递增值,能揪出地址线错位。这三种图案跑完,比单纯写 0 和 1 靠谱得多。
从那以后我每次拿到一份新的核心板原理图,都会先把电源树和 FMC、QSPI 这几组信号在纸上重新画一遍,标上每个网络的去向,再对着实物量一遍才动手写代码。图纸上省下的十分钟,通常会在调试台上变成十个小时。希望帮到你。
本文还有配套的精品资源,点击获取