STM32F103+FreeRTOS排查实录:从“没反应”到揪出假芯片
2026/9/5 2:01:21 网站建设 项目流程

插上电,灯不亮,仿真器连不上,代码烧不进去,这是玩 STM32F103 + FreeRTOS 时最让人血压飙升的场景。更离谱的是,有时板子明明能下载程序,但上电后就是没反应,连个 LED 都不闪。很多朋友第一反应是“我代码写错了”,然后翻来覆去查 FreeRTOS 移植步骤,改配置、换启动文件,折腾几天一无所获。最后换一块新的 STM32F103C8T6,焊上去,一切正常。这时候才意识到,问题很可能出在芯片本身——你手里那片,极可能是“假芯片”。

这里的“假”,不是指那种完全不能用的废片,而是一类很特殊的存在:外观、丝印、引脚定义都和正品 STM32F103 一致,但内部 Flash 时序、ID 读取、低功耗行为、甚至内核版本却和正品有细微差异。这些差异平时也许感觉不到,一旦配合 FreeRTOS 这种依赖精确时钟和中断优先级控制的系统,就会暴露成各种“没反应”“进不了任务”“偶尔死机”的玄学问题。

这篇博文我会按一个完整的排查链路来写:从“怎么判断芯片没反应是什么原因”,到最小系统硬件检查,再到下载环节、FreeRTOS 跑不起来的“伪死机”,最后回到芯片真伪分辨和采购避坑。每一步都会解释为什么这样做,也会把我在实际项目里踩过的坑和总结的经验放进去。适合刚入门 STM32+FreeRTOS 的初学者,也适合那些被奇怪问题折磨到怀疑人生的老手。

1. 先别急着怀疑芯片:给“没反应”分个类

遇到问题第一件事不是换芯片,而是把“没反应”这个模糊的症状拆开。芯片没反应和芯片没反应之间,差别可能很大。我在排查这类故障时,习惯先回答三个问题:能不能下载?上电后复位引脚/时钟引脚有没有波形?代码是不是真的跑起来了?

1.1 用“能否下载程序”作为第一道分水岭

如果 J-Link、ST-Link 或者 DAP-Link 能正常识别到芯片,并且程序能烧进去,说明芯片内核基本是好的,电源和时钟树的核心部分大概率也没问题。这种情况下“没反应”通常是软件层面的问题,或者某个外设初始化失败,导致程序卡死在某个地方。这种问题,聚焦 FreeRTOS 配置、启动文件、外设时钟即可。

反过来,如果下载器连芯片都识别不到,报的是“No target connected”“Cannot connect to target”之类的错误,那就要从硬件连接、供电、复位电路、启动模式这几个方向查。很多所谓的“假芯片”翻车点,恰恰发生在这条链路上,因为打磨片、翻新片的引脚氧化、内部 ESD 损伤会导致 SWD 信号质量差,下载器时能连上时连不上。

1.2 用可控现象区分“硬件死”和“软件死”

还有一个实用的方法:在代码最开头,也就是进入 FreeRTOS 调度器之前,驱动一个 LED 或者翻转一个 GPIO。如果上电后 LED 不亮,甚至连复位瞬间的一点动静都没有,问题大概率在硬件或者芯片本身。如果 LED 能亮,但进入调度器后任务不执行、LED 不闪烁,那问题就在 FreeRTOS 的任务创建、调度器启动、中断优先级配置上。

这两种情况我都在实际项目中遇到过。有一次客户反馈“板子没反应”,我远程让他用万用表量 3.3V 对地阻值,结果发现只有十几欧,是电源短路。另一次是 LED 能亮但任务永远不运行,查到最后是中断优先级分组设置和 FreeRTOS 的要求冲突,PendSV 和 SysTick 的优先级没设成最低,导致调度器根本没法触发上下文切换。所以,“没反应”三个字背后可能藏着完全不同的病因,第一步永远是定性,而不是盲目排查。

1.3 建立自己的“最小可运行基准”

排查 STM32F103 这类问题,手边最好有一个“最小可运行基准”:一块确定是正品、能稳定跑 FreeRTOS 的板子,或者一个最精简的点灯程序(只初始化时钟和 GPIO,不进 RTOS)。遇到客户或自己板子出问题时,先用这个基准程序烧进去,通过是否点灯来判断问题层级。这比任何高深理论都管用。

我的习惯是:任何一块新板子到手,第一件事不是移植 FreeRTOS,而是先烧一个不带 RTOS 的 GPIO 翻转程序,确认下载链路、时钟、基本 IO 都正常。只有这一步通过了,才会开始往里加 FreeRTOS。很多人一上来就同时引入新板子、新芯片、新 RTOS,出了问题根本无法定位变量,这是排障的大忌。

2. 最小系统的“静默杀手”:电源、时钟、复位、BOOT

如果确认程序下载链路没问题,但上电后依然没反应,就得回到最小系统本身来查。STM32F103 的最小系统并不复杂:电源、时钟、复位、BOOT 引脚,四样东西缺一不可。但恰恰是这几个“最基础”的环节,藏着大量容易被忽略的故障点。

2.1 电源部分:VDD/VDDA 和去耦电容的“反直觉”故障

STM32F103 的电源引脚包括多个 VDD 和 VSS,以及 VDDA/VSSA(模拟电源)、VREF+(如果有的话)。很多人只接了 VDD 和 VSS,VDDA 直接悬空或者没接好,结果芯片工作异常、ADC 乱跳、内部复位不稳定,CPU 跑飞表现就像“没反应”。

另外一个大坑是去耦电容的位置和容值。STM32F103 的每个电源引脚旁边都应放一个 100nF 的陶瓷电容,且要尽量靠近引脚放置。我见过不少板子为了布线方便,把所有去耦电容集中放在电源入口处,距离芯片引脚几厘米远,高频噪声滤不掉,芯片偶尔上电启动不起来,但有时又正常——这种随机性故障最容易让人误以为是“芯片坏了”或者“买到假货”。

还有一个容易忽略的点:BOOT0 引脚内部有下拉电阻,但外部如果接了电容或者走线过长,可能导致上电时 BOOT0 电平不稳定。BOOT0 一旦上电瞬间被拉到高电平(哪怕只有几毫秒),芯片就会从系统存储器启动,用户 Flash 里的程序根本不会运行,表现同样是“没反应”。排查时用万用表量 BOOT0 的对地电压,正常应为 0V(跳线帽接 GND 时),如果量出来有 1V 以上,就要怀疑外部电路了。

2.2 时钟:8MHz 晶振不起振,系统卡死在启动阶段

STM32F103 上电默认使用内部 HSI(8MHz RC 振荡器),如果代码里配置了外部 HSE 晶振,且配置了“HSE 启动超时等待”,而外部晶振根本没起振,程序就会卡在等待 HSE 就绪的 while 循环里,表现出来就是“上电后完全没反应”。这在带 FreeRTOS 的项目里更隐蔽,因为很多人用 CubeMX 生成工程时,RCC 设置为 Crystal/Ceramic Resonator,默认就启用 HSE,如果晶振电路有问题,程序根本走不到 main 函数后面的任何逻辑。

排查方法不复杂:用示波器或逻辑分析仪量 8MHz 晶振的 OSC_IN/OSC_OUT 引脚,起振后应能看到类似正弦波的时钟信号,幅值通常在几百毫伏到 1V 以上。如果没有示波器,可以临时把代码里的时钟源切换到 HSI,或者把 Keil、IAR 里的调试配置改成 low-power 模式,观察是否能跳过 HSE 等待。如果切换到 HSI 后系统正常运行,问题几乎可以锁定在晶振电路。

晶振电路的电容负载也很关键。我的经验是 8MHz 晶振通常配 10~22pF 的负载电容,但这和晶振本身的 CL 值有关。如果负载电容和晶振不匹配,可能出现两种情况:要么完全不起振,要么起振但频率偏差大,导致串口波特率错乱、FreeRTOS 的时基不准,表现为任务调度异常、delay 超时,甚至看起来像死机。

2.3 复位电路:NRST 引脚的外部电容和干扰

STM32F103 的 NRST 引脚是低电平复位,内部有上拉电阻和复位电路,外部通常再接一个 100nF 电容到地,以增强抗干扰能力。但有些板子为了省成本,把这个电容省了,或者用了 1uF 的大电容,结果会导致上电复位时间异常,芯片偶尔无法正常启动。

还有一个不常见但很实际的问题:有些翻新片因为内部复位电路老化或损伤,对 NRST 的上电时序非常敏感。表现为第一次上电没反应,按一下复位按钮之后又能正常运行。这种“按复位才能启动”的现象,在很多旧料、拆机片中比较常见,遇到这种情况基本可以断定不是正品新片。

3. 下载环节的“至暗时刻”:SWD 连接失败与芯片锁死

在 STM32F103 的调试环节,最让人抓狂的报错就是“Cannot connect to target”和“RDDI-DAP Error”。这两个错误我以前遇到时总以为是板子坏了,后来才总结出它们各自的常见原因和针对性解法。

3.1 目标板供电与接线方式:SWD 不等于免供电

很多人第一次用 ST-Link 或 J-Link 调试 STM32F103 时,以为只要接 SWDIO、SWCLK、GND 三根线就能下载,完全没考虑目标板供电问题。SWD 接口本身虽然有电源引脚,但 ST-Link 的 3.3V 输出能力有限,如果你的目标板上有其他外设(比如传感器模块、OLED 屏、Wi-Fi 模块),下载器根本带不动,电压跌落会导致芯片上电不完全,表现为“能识别但下载超时”或“时好时坏”。

SWD 接线的抗干扰能力也经常被低估。SWCLK 和 SWDIO 这两根线的走线如果过长,或者和小电压、大电流的电源线平行,高速 SWD 通信就会被干扰。解决方法是降低 SWD 通信速率(在 Keil 的 Settings 里把 Max Clock 从 4MHz 降到 1MHz 或更低),或者把线束改成双绞线/屏蔽线。我调试飞线板时,习惯把 SWD 速率直接设到 1MHz,稳定性和速度的性价比最好。

3.2 SWD 引脚被代码占用:最经典的“自己锁死自己”

这种情况在跑了 FreeRTOS 之后更容易出现:初始化代码把 PA13/PA14 重映射成了普通 GPIO,或者 JTAG/SWD 引脚被设置为复用功能,导致调试器下一次无法连接。很多人以为“芯片坏了”,其实是 SWD 功能被禁用了。解决方法是用 J-Link 的“Connect under Reset”功能,或者把 BOOT0 拉高,强制从系统存储器启动,然后在复位期间连接调试器,擦除 Flash。

在 Keil 里,如果遇到无法连接,可以尝试以下几个步骤组合操作:

  1. 按住目标板复位键不放
  2. 点击 Keil 的 Download 按钮
  3. 在下载开始的瞬间松开复位键
  4. 如果时序正确,下载器会趁芯片运行在复位状态时建立连接,然后擦除 Flash

这个方法成功率很高,但需要点手速。更稳妥的办法是使用 J-Link 的“Reset”模式配置,选择“Hardware Reset”或“Connect under Reset”,让调试器在复位期间抢占 SWD 接口控制权。

3.3 读保护(RDP)与 Option Bytes:被忽略的“假死”原因

还有一类问题是读保护开启导致的。如果之前在调试选项里误开了读保护,或者芯片是二手料(比如从某工业设备上拆机下来的),Flash 可能处于 RDP Level 1 保护状态,此时 SWD 只能做全片擦除,不能读写 Flash。表现是下载时提示“Flash Download failed - Target DLL has been cancelled”或“Cannot access memory”。

处理方法是执行整片擦除(Full Chip Erase),这会解除读保护,但也会清空所有用户数据和 Option Bytes 设置。使用 ST-Link Utility 或 J-Link Commander 都能操作。这里有个常见的坑:某些 ST-Link 克隆版在解除读保护时不稳定,擦除到一半失败,导致芯片进入更深的保护状态,需要先用串口 ISP 方式(BOOT0 拉高接 USART1)连接,再执行擦除操作。如果你手里的“假芯片”是翻新料,它的 Option Bytes 区域很可能是混乱的,这种情况下用串口 ISP 也比 SWD 更可靠。

4. FreeRTOS 跑不起来的“伪死机”:启动文件、中断优先级与堆栈

好,如果硬件链路都查过了,芯片也确定能下载、能点灯,但一旦加上 FreeRTOS 就“死机”,那就进入了我最想聊的环节。这个环节里,很多问题的根源不是芯片本身,而是 FreeRTOS 在 STM32F103 上的移植细节没到位。但注意,兼容芯片和正品芯片在这些细节上的“容错能力”差异巨大,正品可能勉强能跑,兼容片直接挂,这也是很多人误判“芯片是假的”的原因。

4.1 启动文件选错,等于系统时钟根本没配置

STM32F103 有多个型号,例如 C8T6(64KB Flash,20KB RAM)、RCT6(256KB Flash,48KB RAM)、ZET6(512KB Flash,64KB RAM)。不同容量的芯片,对应的启动文件不同:小容量用 startup_stm32f10x_ld.s,中容量用 startup_stm32f10x_md.s,大容量用 startup_stm32f10x_hd.s。如果用错了,比如在 C8T6 上放了 hd 启动文件,运行时中断向量表会错位,程序一旦触发中断就会跑飞,表现就是“点灯正常,但 FreeRTOS 一跑就死”。

而且,启动文件里定义了初始堆栈大小(Stack_Size)和堆大小(Heap_Size)。如果 Stack_Size 设置太小(比如默认 0x400),而 FreeRTOS 的任务栈又比较大,系统一旦进入更深层次的函数调用,栈溢出会把相邻内存区域的数据踩掉,导致虚拟的“随机死机”。这在调试时比“完全没反应”更隐蔽,因为它是概率性发生的。

4.2 中断优先级:FreeRTOS 对 PendSV 和 SysTick 的硬性要求

这是 STM32F103 移植 FreeRTOS 时最“反直觉”的一个点。ARM Cortex-M3 内核里,FreeRTOS 要求 PendSV 和 SysTick 的中断优先级必须设置为最低(数值最大),同时还要把所有其他中断的优先级设置为数值小于等于某个值(通常是对应 PORT 宏定义里的 configMAX_SYSCALL_INTERRUPT_PRIORITY)。

原因在于:FreeRTOS 的上下文切换是借助 PendSV 完成的,而 PendSV 是一个可挂起的中断,它会在所有高优先级中断处理后,在最低优先级线程模式下完成切换。如果 PendSV 的优先级不是最低,那么在某个中断处理过程中触发了 PendSV,而 PendSV 优先级高于当前中断,就会出现“中断嵌套中的上下文切换”,导致堆栈错乱,系统跑飞。

STM32F103 上还有个特殊之处:它只使用了 NVIC 的 4 位优先级中的高 4 位,且它的优先级分组通常设置为 NVIC_PriorityGroup_4(全抢占优先级,无子优先级)。如果用 CubeMX 生成代码,默认就是这样。但如果你从网上下载了一个别人移植的工程,它的优先级分组可能被改成了 Group_2 或 Group_3,这会导致 FreeRTOS 内部的临界区逻辑失效,最终表现为随机死机。

我的建

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询