1. 为什么一块板上要塞两颗STM32:这事的真实动机
先讲个场景。上个月我在调一块带无刷电机驱动的传感器采集板,主控用的是一颗STM32F103,跑着三路PID闭环。电机的PWM一开,电流采样中断偶尔会抖,本来2kHz的采样率硬被挤掉几百赫兹。更要命的是,附近还有一个RS485总线要实时响应上位机指令,这边一忙,那边就超时。后来我干脆加了第二颗STM32,一颗专门管电机和电流环,另一颗专管通信和采集,问题立刻消失。
一块PCB上放两颗STM32,听上去有点"大炮打蚊子",但很多实际项目里这是性价比极高的解法。它背后真正的需求通常是这几类:
- 实时性硬隔离:电机控制、开关电源这类对中断响应时间有硬要求的任务,和需要跑协议栈、人机交互的任务放在同一颗MCU上,调度冲突只是时间问题。
- 模拟采集与数字通信的地噪声隔离:高精度ADC采样时,数字总线翻转带来的电源毛刺会直接耦合进模拟信号。两颗芯片分别供电,中间加磁珠或者LDO隔开,实测可以把采样噪声从几个mV压到几百µV。
- 外设资源不够:有些封装只有3个UART,同时要挂GPS、RS485、蓝牙和调试口,怎么排都差一口。两颗芯片等于把可用外设翻倍,而且每颗芯片都能工作在比较低的时钟频率,降低EMI。
- 安全冗余:虽然不是双MCU锁步那种等级,但两颗芯片互相做心跳监测,至少一颗死掉时另一颗能接管关键IO,对非安全认证但要求高可靠的产品来说,简单实用。
如果你遇到的是这类场景,那这篇文章就是为你准备的。我会从通信方案选型、电源和时钟架构、启动顺序设计、调试下载坑点、PCB布局EMC这几个维度,把双STM32方案里真正值得注意的地方全部过一遍,包括我在实际测试中翻车后总结的经验。
先说结论:双STM32设计成败的关键,八成不取决于软件,而取决于三个硬件层面的决定——通信接口怎么选、复位时钟怎么分配、调试和烧录口怎么共存。下面一个个展开。
2. 双MCU之间怎么通信:UART、SPI、I2C的实测对比与选型逻辑
两颗芯片放一块板上,通信方式比两个独立模块之间通信的选择余地大得多。因为距离近、环境可控,你可以用并行总线、SPI、UART、I2C甚至直接映射内存地址。但每种方案的性格差别很大,不是随便选一个都行。
2.1 UART:最稳妥但别忽略波特率误差叠加
UART是绝大多数人的第一反应——简单、现成、调试方便。但它有两个容易被忽略的问题。
一个是波特率误差。两颗芯片的HSE晶振或内部RC都有自己的精度,F103这类芯片用内部RC时误差可以到1%~2%,当双方波特率误差方向相反时,UART的采样窗口会被压缩。常规做法是两边都用同一个外部晶振(一根晶振输出接两个芯片的OSC_IN),或者通信双方都改用内部高速时钟但进行软件校准。我实测过一颗用内部RC、一颗用8M外部晶振的板子,波特率115200时偶发乱码,改成双芯片共用同一个外部时钟源之后就干净了。如果没法共用时钟,建议把波特率降到38400以下,并用奇偶校验位增加容错。
另一个是中断延迟。UART收发是字节级的,9600波特率下每字节差不多1ms,如果主循环里同时处理电机控制和通信解析,很容易丢字节。双MCU方案里我习惯给两边的UART都配DMA,并用空闲中断来判断一帧数据结束。STM32的HAL库对空闲中断支持得不错,开启HAL_UARTEx_ReceiveToIdle_DMA之后,CPU基本不需要逐字节介入。
2.2 SPI:高速大数据量场景的主力
如果两边的数据量上来了,比如一个芯片采集音频、另一个做FFT运算,UART就不够看了。STM32的SPI在36MHz或更高时钟下轻松跑满几十Mbps,而且全双工,一次传输同时收发数据,非常适合握手协议。
但SPI做双机通信有个很实际的坑:片选和主从关系。如果你设置一颗为主、一颗为从,从机侧的程序必须准备好随时响应,否则主机的数据就丢。我的做法是双MCU之间不使用标准SPI的主从CS机制,而是把CS引脚当普通GPIO用,发送前拉低、结束后拉高,从机侧用外部中断检测CS下降沿再开始接收。这样从机无需一直轮询。
还有一个建议:SPI线上的信号完整性在板内短距离(小于10cm)通常没问题,但如果走线经过了连接器或者长排线,建议把时钟降到10MHz以下,必要时串33Ω或47Ω电阻抑制过冲。这部分后面EMC章节会一起说。
2.3 I2C:能不用尽量别用,尤其跨芯片
I2C虽然只需两根线,但跨芯片通信时问题很多。首先是地址冲突——两颗STM32的I2C外设地址都是可配的,但如果你还挂了其他I2C设备,地址空间很快就紧张了。其次是I2C是开漏结构,需要上拉电阻,板内短距离还好,一旦线长一点,上升沿变慢,速度只能降到100kHz甚至更低。
更麻烦的是I2C的阻塞问题。从机拉低时钟线进行流控的时候,如果从机程序卡死,总线会一直锁住。很多工程师在双MCU通信上栽跟头,就是I2C总线被拉死之后,查了半天不知道是哪边的问题。所以我的结论很直接:板内双MCU通信,I2C只适合低速状态信息传输,比如传递温度和电压阈值这类低频数据,不适合做主数据通路。
2.4 并行总线与共享内存:什么时候值得上
两颗STM32之间如果数据量达到几百KB/s以上,SPI也不太够了,这时可以用FSMC或FMC并行总线,把从机映射到主机的外部存储区域。F103系列带FSMC的型号,F4和H7系列带FMC,理论上可以把另一颗STM32当SRAM来读写,速度非常快。
但并行总线会占掉大量GPIO,PCB布线也变复杂。除非你的场景确实是高吞吐,比如双芯片协同做软件无线电或者图像处理,否则我不建议普通项目上并行总线。做了并行总线之后,还需要在固件里定义一套共享内存结构体,包含数据序号、长度、校验和,防止读到半写的帧。
2.5 CAN:工业场景下的隐藏选项
如果你已经在用CAN总线,再多接一个STM32的成本几乎为零。CAN的仲裁机制天然适合多节点,而且抗干扰能力强。我做过的一块板卡就是一颗F103做伺服驱动,另一颗做IO扩展和状态监控,两者通过CAN通信,波特率1Mbps,一条双绞线搞定。CAN的缺点是协议栈稍微复杂,但只要用HAL库的CAN外设加FIFO,比你想的简单。
下面是我总结的选型参考表:
| 通信方式 | 典型速率 | 引脚占用 | 抗干扰能力 | 协议复杂度 | 适合场景 |
|---|---|---|---|---|---|
| UART | ≤1.5Mbps | 2或4(含流控) | 一般 | 低 | 低速控制、调试日志、状态同步 |
| SPI | ≤36Mbps | 3~4 | 较好 | 中 | 大数据量采集传输、双核分工 |
| I2C | ≤400kHz | 2 | 较差 | 低 | 低速低频状态信息 |
| CAN | ≤1Mbps | 2 | 强 | 中 | 工业现场、多节点组网 |
| FMC并行 | 数十MB/s | 20+ | 一般(需注意总线噪声) | 高 | 高吞吐场景 |
我在项目里的默认组合是:一颗为主控(Master),一颗为执行/采集从机(Slave),通信主链路走SPI,状态走UART,心跳和错误上报走CAN(如果系统里本来就有CAN)。SPI三根线加一根CS,加一根中断线(从机有新数据时拉高通知主机),这个组合实测最稳。
3. 电源、时钟、复位、调试口的四大共地设计
两块芯片放一块板上,硬件上的麻烦不是"多一个芯片",而是"多一个芯片之后,那些本来只需要管一次的东西都要管两遍"。电源、时钟、复位、调试口,每一项都值得单独过一遍。
3.1 电源架构:独立LDO还是共用一路电源?
这是我的血泪教训。第一次做双STM32板子时,为了省事,两颗芯片的VDD直接并到同一个3.3V电源轨上。结果电机一启动,电源轨瞬间跌了200mV,通信SPI偶发CRC错误,查了整整两天,最后用示波器看到电源纹波和SPI错误的对应关系才破案。
正确的做法分两档。如果两颗芯片工作性质差别不大,都用同一路3.3V问题不大,但前提是每个芯片的VDD引脚都放100nF陶瓷电容,并且靠近MCU侧再加一个4.7µF~10µF的钽电容或MLCC做中频储能。如果其中一颗芯片带电机、加热丝、继电器这类负载,另一颗主要做精密采集,那必须分两路供电——一路给执行芯片,一路给采集芯片,两路之间用磁珠或小阻值电阻做单点连接,模拟地和数字地在MCU附近单点汇合。
实测数据:共用电源轨时,ADC采样值跳动范围大约±8LSB(12位模式下);分离供电之后,降到±1~2LSB。对采集类应用,这个差距是决定性的。
3.2 时钟设计:共享晶振还是各自独立?
双STM32的时钟方案有几种选择,各有优劣:
- 各自独立晶振:电路最简单,每颗芯片一个8MHz晶振,互不干扰。缺点是一旦需要对时间同步敏感的通信(比如PWM同步、高速SPI),两边时钟频率的微小差异会累积成相位漂移。
- 单晶振双负载:一个8MHz晶振输出接到两颗芯片的OSC_IN,OSC_OUT空接。这个方法只要晶振驱动能力够就行,F103系列通常可以。缺点是噪声会同时灌给两颗芯片,晶振附近要预留足够的铺地。
- 主机输出MCO给从机:主芯片的MCO引脚输出8MHz或更高频率接到从机OSC_IN,从机不用自己的晶振。这样两边时钟完全同源,SPI和USB的同步最稳。缺点是如果主芯片死了,从机也失去时钟,整体可靠性下降。
我的建议:如果你的双MCU之间经常要进行时间戳对齐或者同步采样,直接上第三种方案;如果只是各自干各自的活,偶尔传个状态,选第一种最省心。注意从机用外部时钟输入时,OSC_OUT引脚要悬空,并且RCC配置要选"外部时钟源"而不是"外部晶振",别选错。
3.3 复位电路:RC值怎么选才不互相干扰
复位电路看似简单,双MCU时却有个隐蔽问题。如果两颗芯片用同一个RC复位电路,上电时电源爬升过程会让复位引脚电位缓慢上升,可能导致某颗芯片在电源还不稳定时就开始运行,另一颗还在复位状态。
我的做法是:两颗芯片各用独立的复位电路,RC时间常数取10ms~100ms。比如100kΩ电阻配100nF电容,时间常数约10ms,配合STM32的上电复位机制足够。使用外部复位芯片的话,选择带手动复位输入和开漏输出的型号,可以做到"一个按键同时复位两颗芯片"。复位芯片的输出接两颗芯片NRST引脚之前,最好各串一个100Ω电阻,防止一颗芯片内部下拉时把另一颗的复位引脚也拉低。
另外,STM32的NRST引脚内部有弱上拉,如果你在NRST上外接电容做延时,电容值不要太大,否则复位释放沿变缓,芯片可能进入异常状态。我见过有人放大10µF电容在NRST上,结果芯片一直复位不过去,上电后就是起不来。
3.4 调试口:JTAG/SWD引脚冲突怎么破
这是很多人第一次做双STM32最崩溃的地方。每颗STM32的SWDIO和SWCLK引脚在F103上是PA13和PA14,F4也是类似位置。两颗芯片都用SWD时,如果你把两颗芯片的SWDIO直接并到一起,ST-Link会不知道跟谁说话,甚至因为引脚驱动力度不同导致通信失败。
解决方案有三个,按推荐度排序:
- 分时复用J-Link/ST-Link接口:板上放一个2x5的SWD排针,中间串0Ω电阻或跳线。调试芯片A时焊上A路的电阻,调试芯片B时焊上B路的。缺点是调试切换麻烦,但最可靠,适合调试阶段。
- 用SWD接口的断开功能:有些调试器支持target interface切换,但物理上你还是需要把两根线分别连到两个芯片的SWD引脚,中间加跳线帽或拨码开关。这个方案适合开发板,量产板不建议,因为拨码开关容易误触。
- 两块芯片用不同调试口:F103系列可以把SWD映射到其他引脚,但需要早期在代码里配置AFIO重映射,而且重映射后调试器第一次连接会麻烦。另一个思路是芯片A用SWD,芯片B用串口ISP或自定义Bootloader升级,用串口打印调试信息代替在线调试。这个在量产阶段反而最实用,因为芯片B的固件已经稳定,不需要频繁断点单步。
如果你是做量产产品,我建议最终固件里把两颗芯片的调试接口都禁用,省下的引脚拿去干正事。注意F103禁用JTAG时需要调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE),否则PA13~PA15和PB3、PB4继续被调试器占用。
4. 启动顺序与双核握手:防止两棵死锁的一整套逻辑
两颗芯片上电后,谁先跑没关系,但如果互相依赖对方的初始化数据,就很容易出现"你等我、我等你"的死锁。这个问题的本质是:从芯片的角度看,它不知道对方此刻处于什么状态——是还在复位、已经在运行、还是卡死了。所以必须建立一套显式的启动握手协议。
4.1 启动顺序设计:主从角色要在硬件上确定
先确定角色。我的习惯是主机(Master)由电源直接上电,从机(Slave)的电源由主机的GPIO控制(一个P沟道MOSFET或负载开关)。这样主机软件可以在完全准备好后再给从机供电,从机看到的电源是干净利落的上升沿,不会因为电源爬升缓慢而反复复位。
如果两颗芯片同时上电,也没有关系,但要确保复位时序有足够的错开。上文说的各自独立RC复位电路就保证了这一点。更好的做法是用一颗电源监控芯片,比如TPS3823这类,它的复位输出有固定的延时,可以保证输出到两颗芯片NRST的时间差至少有200ms。
硬件准备好之后,从机Boot0引脚要拉低,让从机从Flash启动。有些人会把Boot0悬空,这在单芯片时可能没问题,但双芯片时悬空引脚容易受旁边走线干扰,导致从机偶尔进入Bootloader模式,程序跑不起来。量产的板子,Boot0和Boot1都通过10kΩ电阻下拉到地,不要偷懒。
4.2 握手协议:别用"延时等对方"这种野路子
有人在从机初始化时直接HAL_Delay(2000),以为等主机准备好就行。这在单板上可能碰巧能用,但只要主机初始化稍微慢一点,或者中间某个步骤卡住,从机就在那儿干等,然后两边都以为对方有问题,整个系统启动时间莫名其妙多出几秒。
靠谱的做法是定义应用层握手协议。我用的是这个结构:
- 从机上电后立即拉高READY引脚(一个GPIO,主机用外部中断检测),告诉主机"我从机已经启动,进入等待命令状态"。
- 主机检测到READY后,发送SYNC帧(比如0xAA 0x55 0x01 0x02 0x03 0x04 0x04,最后一个字节是校验和)。
- 从机收到SYNC帧后,回复ACK帧(0x55 0xAA 0x81 0x81),同时进入运行状态。
- 主机收到ACK后,才允许发送业务数据。如果主机在500ms内没收到ACK,主动重启从机电源或拉低从机NRST引脚。
这套协议的精髓是"谁超时谁负责"。主机负责监控超时并决定是否重启从机,从机不需要关心主机状态,它只要在收到SYNC前不断重发READY信号或者保持等待即可。这个设计避免了两边同时等对方的经典死锁。
时序参数上,SYNC重发间隔取100ms,超时阈值取500ms,比较合适。太短容易在上电瞬间误判,太长会让系统启动显得迟钝。
4.3 双看门狗:独立看门狗+窗口看门狗怎么分配
双MCU系统里,看门狗策略也需要区分。我的分配方式是:
- 主机:启用独立看门狗(IWDG),超时时间约1秒,在主循环里喂狗。如果主机卡死在某个中断里,IWDG会把它拉回来,同时从机通过心跳超时检测到主机异常,接管关键IO。
- 从机:启用窗口看门狗(WWDG),窗口期设置得比较窄,确保从机主循环严格按周期执行。如果从机中断风暴导致主循环被挤掉,WWDG会比IWDG更快地发现问题。
另外,两颗芯片之间最好有硬件心跳线:主机每100ms翻转某个GPIO电平,从机用另一个GPIO检测这个翻转。如果从机在300ms内没看到电平变化,就认为主机死机,从机执行安全动作(比如关闭电机驱动、拉高报警信号)。这个心跳线用代码翻转GPIO即可,不需要额外硬件,但比纯粹的软件心跳(靠通信触发)更可靠,因为它不经过协议栈。
4.4 共享Flash和EEPROM的细节
如果两颗芯片要共用外部SPI Flash或者板载EEPROM,有一个陷阱叫双写覆盖。比如主机在地址0x00写系统参数,从机在地址0x100写校准数据。如果两边共用SPI总线和片选,但某一个芯片在写操作进行到一半时被另一个芯片打断(比如SPI片选被意外拉低),数据就会写坏。
我的建议是:共享存储必须加一把信号量锁。最简单的方式是用一个GPIO做硬件锁:要写EEPROM之前,先请求锁(拉高/拉低某根线),对方检测到后暂停自己的写操作,写完释放。软件上再配合页写入缓冲和CRC校验,基本就不会出现双写覆盖了。
如果数据量不大,其实更省心的方案是:两颗芯片各自保留一段专属的存储区域,不需要共享。主机用前1/2的Flash空间,从机用后1/2,中间留出隔离区域。这样两边各写各的,完全不需要协作,省掉通信协议和锁定的麻烦。
5. 这块PCB的布局、布线与EMC:双芯片不是"画两遍"那么简单
双STM32的PCB设计,最容易犯的错误是把单芯片的成熟布局复制两份然后拼在一起。这样出来的板子,大概率在EMC测试时被搞得很惨。因为我实际调试中遇到的噪声、串扰、地弹问题,绝大多数都出在"两套系统共用一套地"这个环节。
5.1 分区布局:数字区、模拟区、功率区要划清楚
晶振的位置很关键,两个晶振不能贴近放。8MHz晶振输出的是模拟小信号,而SPI、UART这类数字信号翻转时会在参考地上激起噪声。如果晶振离数字走线太近,时钟抖动会变大。我的经验是两个晶振至少相隔2cm以上,并且远离开关节点(电机驱动桥、DC-DC电感)。
如果板上同时有模拟采集和电机驱动,布局上以"功率区→中间隔离带→模拟区"为基本顺序。主控芯片放在中间,ADC输入和传感器接口放在一侧,电机驱动放在另一侧。两个STM32分别承担不同任务时,执行芯片贴近功率区,采集芯片贴近模拟前端,中间用铺地隔离,不要用一根细线连接两边。
5.2 电源和地:星型接地不是玄学
双芯片的电源和地规划,单点汇聚是关键。最容易出现的问题是:两颗芯片地通过各自的外设回路形成环流。最典型的表现是,当芯片A的某个GPIO翻转驱动LED时,芯片B的ADC采样值会跟着跳,这就是共地阻抗耦合。
解决方法是采用星型接地:每颗芯片的地引脚先在芯片下方通过过孔汇聚到内层完整地平面,然后从地平面的中心点(通常是电源输入端)单点引出,不要再有多条地线在图间来回穿梭。不要用"串联接地"方式——芯片A的地返回电流流经芯片B的地引脚区域,这是最糟糕的。
对于ADC采样部分,模拟地AGND和数字地DGND用0Ω电阻或磁珠单点连接,这个点通常放在ADC芯片或MCU的AGND引脚附近。芯片内部模拟和数字部分已经做了隔离,外部只需要保证回流路径干净即可。
5.3 SPI走线:高速信号别追求"越短越好"的唯一标准
有人以为SPI走线越短越好,这没错,但不够。短是基础,更重要的是回路面积要小。SPI的SCK、MOSI、MISO、CS四根线,尽量在同一层走,并且旁边有连续的地平面跟随。如果必须换层,换层位置旁边要放地过孔,保证返回电流可以平滑地跳层,否则信号回路面积变大,辐射噪声显著增加。
时钟线尽量远离复位线和中断线。SCK 18MHz翻转的谐波很强,如果跟从机的NRST引脚走线相距太近,可能造成复位误触发。我有一块板子SPI时钟线从NRST边路过,结果主机偶尔意外复位,后来把线距拉开到3W规则(线间距是线宽的3倍)才解决。
5.4 连接器和排针的引脚分配
如果板子需要引出调试口或通信口,连接器引脚分配时注意,不要把两个芯片的SWD引脚放在同一个连接器的相邻脚位上,否则调试时跳线帽戴错位置,可能同时驱动两颗芯片的SWD引脚,烧坏IO。一个更稳妥的做法是:调试连接器上分配独立引脚给两套SWD,J-Link和ST-Link都不支持同时连两颗芯片,所以板上留一个拨码开关或者0Ω电阻选择开关。量产板上直接把调试口改成2.54mm间距的测试点,生产时用测试夹子批量烧录,平时不需要预留连接器。
6. 下载与调试的完整方案:从单独烧写到量产批量烧录
双芯片方案里,下载调试是最能"逼疯"人的环节。因为两颗芯片固件不同,一根ST-Link只能连着调试器连一颗,另一颗完全看不到,经常出现"我改了芯片B的代码,但忘了给芯片B烧录,程序跑的还是旧的"这种低级错误。
6.1 开发阶段的接线方案
开发阶段,最省事的方式是板上保留两个SWD接口,分别对应芯片A和芯片B。同时插两个ST-Link到电脑上一起烧写,或者用STM32CubeProgrammer命令行一次烧两个hex,都很方便。STM32CubeProgrammer支持-c port=SWD mode=UR和-w firmware.hex的参数,写一个批处理脚本就可以一次调用两次命令,分别烧两颗芯片。
我自己的习惯是写个Makefile目标,比如make flash-all,里面依次执行:
STM32_Programmer_CLI -c port=SWD mode=UR reset=HWrst -w build_master/master.hex STM32_Programmer_CLI -c port=SWD mode=UR reset=HWrst -w build_slave/slave.hex如果你用STM32CubeIDE,也可以右键项目名选"Build Targets"→"Add",新建一个target,把两个项目的post-build命令都放在里面。这样每次改完代码,一个快捷键就把两颗芯片都烧了,不会漏。
6.2 量产阶段的批量烧录和校验
量产时,两颗芯片如果都留SWD,需要两个测试点,测试架上一个双头探针同时接触两个SWDIO/SWCLK,这是可行的,因为量产时两颗芯片之间没有通信,可以分别烧录。不过实际生产中更常见的做法是:
- 芯片A(主控):用SWD直接烧录,因为主控固件更新频率高。
- 芯片B(从机):固件放到主机固件的末尾,做成"镜像区"。主机启动时检查从机固件版本,如果版本不一致,就通过UART或SPI把新固件推给从机,从机收到后写入自己的Flash,再跳转运行。这就是IAP(In-Application Programming)方案。
IAP方案的优点是,产线上只需要一个SWD口烧录主机,从机由主机完成首次烧录或升级,省掉一个探针位,还方便以后现场远程升级。缺点是Bootloader代码要提前烧进从机,而且从机的Bootloader要做好Flash写入保护,防止应用程序把Bootloader覆盖掉。
关于烧录保护,STM32的RDP(Read Protection)等级建议设成Level 1,防止固件被读出来,同时允许后续升级。如果把RDP设成Level 2,芯片就永久锁死了,现场升级就彻底不可能,量产前想清楚。
6.3 调试会话里最容易踩的坑:两个SWD调试器冲突
有时你想用两个调试器同时调试两颗芯片,这在软件上可以,但有几个坑要避免:
- 电源冲突:两个ST-Link如果都从目标板取电,会同时给板上3.3V供电,电流方向不好说,有时会把某个调试器保护触发。让其中一个调试器不连目标板电源(把ST-Link的3.3V脚断开或选"不供电"模式),只连SWDIO/SWCLK/GND/Reset。
- 复位冲突:两个调试器同时接管复位引脚,如果一方在复位引脚上做电平控制,另一方也会受影响。有些调试器通过NRST做硬件复位,两个调试器的复位信号会互相打架。建议调试时只让主调试器连接NRST,从机用软件复位或者只使用SWD通信,不用硬件复位。
- 断电顺序:同时调试两颗芯片时,拔掉一个调试器后发现另一个芯片程序也乱了,这是供电瞬间跌落导致的。每次拔插调试器前,先断开调试会话,再拔线,顺序反了容易导致芯片进入异常状态,有时候得重新上电才能恢复。
6.4 日志与状态监控:两块芯片怎么打日志
双芯片有一个天然优势,就是可以分开打日志。比如主机把日志发到串口1(接USB转串口),从机把日志发到串口2(接另一个USB转串口),然后开两个串口助手同时看。两个人各开一个窗口,效率极高,比单芯片上靠软件区分任务日志方便多了。
如果只有一个调试串口,可以用时间戳前缀区分来源,比如主机日志前缀[MASTER],从机日志前缀[SLAVE],都发到同一个串口上。但要小心两个串口的发送时间重叠,一个芯片发到一半另一个芯片也发了,造成串口数据交错乱码。这种情况下,建议两颗芯片都先送入自己的Ring Buffer,再由一个专门的转发任务统一从串口输出,避免直接并发写UART。
7. 写在最后:双STM32方案的边界与几个亲测有效的小建议
最后说点实在的。
双STM32不是性能问题的万能药。如果你是因为单颗芯片算力不够而想加一颗,那大概率方向错了——这种情况应该换更高性能的型号,比如STM32H7或直接用带双核的芯片(STM32H745就是双核Cortex-M7+M4)。双STM32适合的是"任务必须物理隔离"的场景,不管是实时性隔离、电源域隔离,还是为了降低单点故障率。
如果你已经决定用双STM32方案,我实际用下来觉得最有价值的几点:
- 通信协议一定要定义好版本号和校验和,哪怕只是主从两个节点。因为两颗芯片的固件有可能分开升级,升级节奏不一致时,旧协议和新协议直接不兼容。我吃过这个亏:主机升级后从机没升级,主从无法通信,现场查了半天才发现是协议版本不一致。
- 从机最好支持"烧录失败回退"机制,也就是Bootloader里保留固件B的副本,升级失败时还能从旧版启动。这个机制看着像服务器才需要的东西,但实际现场的尴尬场景太多了,值得预留。
- PCB打样回来不要急着焊两颗芯片,先只焊主机,把主机所有外设(电源、时钟、SWD、串口)全部调通,再焊从机。这次序能帮你把问题隔离在单芯片侧,不会出现"两颗芯片都有问题,不知道先查谁"的局面。
- 散热方面,如果两颗STM32都跑在72MHz以上,且板上还有功率器件,尽量让两颗芯片间距远一点,不要紧贴着放,避免热量集中。更关键的是,两颗芯片的电源引脚旁边都要留足过孔,电源回路电感直接影响高温下电压跌落的风险。
以上就是我在双STM32方案上的完整实践经验。从通信选型、电源和时钟架构、启动握手、PCB布局到烧录调试,每一环都踩过坑、填过坑。如果你按这个思路走一遍,应该能比我自己第一次做双芯片时省下至少两周的调试时间。