1. 从STM32到国产替代:一个嵌入式老兵的年度观察
去年这个时候,我手里有三个量产项目同时要换主控。原因很直接,STM32的供货周期从常规的8周拉长到了26周以上,价格翻了三四倍,采购那边天天追着我问能不能换方案。做了十几年嵌入式开发,从51到AVR再到STM32,我经历过好几次芯片缺货潮,但这一次的力度确实前所未有。也就是从那时候起,我开始系统性地把国产MCU引入到实际项目中,到现在整整一年,前后用了GD32、CH32V103、还有几款RISC-V内核的芯片,覆盖了工业控制、消费电子和物联网网关三类场景。
这篇文章不打算写成芯片选型手册,那种东西原厂的数据手册比我写得详细。我想聊的是真实项目里踩过的坑、测出来的数据、以及那些数据手册上不会告诉你的细节。比如GD32的GPIO翻转速度到底比STM32快多少、CH32V103的中断响应延迟在实际负载下是什么表现、RISC-V工具链的成熟度到了什么程度。这些内容对于正在做国产替代选型的工程师来说,可能比看一百页数据手册都有用。
适合谁看?如果你正在做STM32的国产替代评估,或者刚接手一个国产芯片的项目,又或者你只是想知道国产MCU到底能不能用在量产产品上,这篇文章应该能给你一些参考。我不会一味说好话,也不会故意贬低,就是把我这一年实际用下来的感受和测试数据摆出来,你自己判断。
2. 为什么我决定认真测试国产芯片
2.1 供应链压力下的被迫选择
2022年下半年到2023年初那段时间,STM32F103C8T6的市场价从正常的十几块钱炒到了七八十甚至上百,而且还不一定有货。我们有个客户是做工业网关的,每个月稳定出货两千台,用的就是STM32F103。采购那边反馈说,如果继续用STM32,单台成本要增加六十多块,客户那边根本接受不了。当时摆在面前的选择只有两个:要么说服客户接受涨价,要么找替代方案。
我一开始是抗拒的。做了这么多年STM32,HAL库、标准库、LL库都熟得不能再熟,CubeMX配置工具用起来得心应手,突然要换一个完全不熟悉的平台,学习成本、调试成本、还有潜在的稳定性风险,想想就头疼。但现实摆在面前,不换就得丢客户。于是我开始认真研究国产MCU的替代方案。
2.2 国产MCU的三大梯队
经过一段时间的调研和试用,我把市面上的国产MCU大致分成了三个梯队。第一梯队是GD32和CH32这类已经经过大量市场验证的芯片,GD32的引脚和STM32高度兼容,很多场景可以直接替换,CH32V103则是RISC-V内核的代表,价格优势明显。第二梯队是一些新兴的RISC-V芯片,比如沁恒的CH32V系列、平头哥的生态芯片,工具链还在完善中,但潜力很大。第三梯队就是那些资料极少、原厂支持跟不上的小品牌,价格便宜但风险高,我基本不考虑。
最终我选了GD32F103和CH32V103作为主要测试对象,前者用来替换STM32F103的存量项目,后者用来评估RISC-V在实际项目中的可行性。另外还拿了几片STM32F103作为对照,确保测试条件一致。
2.3 测试方法论:不只看跑分
我给自己定了一个原则:不做那种跑个CoreMark就下结论的测试。真实的项目场景远比跑分复杂,中断嵌套、DMA并发、外设冲突、低功耗切换,这些才是决定芯片能不能用的关键。所以我设计了一套贴近实际应用的测试方案,包括GPIO翻转速度、ADC采样精度和切换速度、串口在高波特率下的稳定性、定时器捕获精度、以及FreeRTOS下的任务切换开销。每个测试项都跑至少24小时,记录异常情况。
3. GD32F103实战:引脚兼容不等于行为兼容
3.1 硬件替换的第一道坎
GD32F103C8T6和STM32F103C8T6在引脚上是Pin-to-Pin兼容的,这意味着PCB不用改,直接把芯片换上去就行。听起来很美好,但实际操作中我发现了一个问题:GD32的BOOT0引脚内部上拉电阻阻值与STM32不同。STM32的BOOT0内部上拉大约是40kΩ左右,而GD32的实测在30kΩ上下。这个差异在大多数情况下不影响,但如果你的BOOT0引脚外部接了一个较大的下拉电阻(比如10kΩ),分压后的电压可能刚好卡在逻辑阈值附近,导致启动模式不稳定。
我遇到的具体现象是:有一批板子用GD32替换后,大约有3%的概率上电后进入Bootloader模式而不是从Flash启动。排查了很久才定位到这个问题。解决办法很简单,把外部下拉电阻从10kΩ换成4.7kΩ,确保分压后BOOT0电压低于0.3V。这个细节在GD32的数据手册里没有明确说明,是我用示波器实测出来的。
3.2 GPIO翻转速度的意外惊喜
GD32F103的一个显著优势是GPIO翻转速度。我用同样的代码在STM32F103和GD32F103上测试,主频都是72MHz,GPIO配置为推挽输出、50MHz模式,用汇编循环直接操作BSRR寄存器。实测结果如下:
| 测试项 | STM32F103 | GD32F103 | 差异 |
|---|---|---|---|
| GPIO翻转频率 | 18MHz | 25MHz | +39% |
| 翻转上升时间 | 6ns | 4.5ns | -25% |
| 翻转下降时间 | 5ns | 4ns | -20% |
GD32的GPIO翻转速度明显快于STM32,这得益于其采用的更先进工艺。对于需要高速SPI或并口驱动的场景,这个优势很实用。但要注意,速度更快意味着EMI辐射也可能更强,我在一个通过CE认证的项目中替换后,辐射测试余量从6dB降到了3dB,虽然还是合格,但余量变小了。如果对EMC要求严格,建议在GPIO上串联小电阻或磁珠。
3.3 中断响应延迟的实测对比
中断响应延迟是工业控制场景的关键指标。我用一个GPIO引脚产生外部中断,在中断服务程序里翻转另一个GPIO,用示波器测量从触发到响应的延迟。测试条件:主频72MHz,中断优先级相同,无其他中断干扰。
STM32F103的实测中断延迟大约是12个时钟周期,也就是约167ns。GD32F103的实测延迟是9个时钟周期,约125ns。GD32略快一些,但差异不大。不过在中断嵌套场景下,差异就明显了。当有高优先级中断正在执行时,低优先级中断的响应延迟STM32大约是20个周期,GD32是14个周期。这意味着在复杂的中断系统中,GD32的实时性更好。
但这里有个坑:GD32的中断优先级分组配置和STM32略有不同。STM32的NVIC_PriorityGroupConfig函数在GD32上虽然能用,但实际的分组行为有细微差异。我建议在使用GD32时,直接操作NVIC的寄存器来配置优先级,不要依赖STM32的库函数。
3.4 Flash和RAM的隐藏差异
GD32F103标称的Flash和RAM容量与STM32F103相同,都是64KB Flash和20KB RAM。但实际测试中我发现,GD32的Flash擦写寿命和STM32有差异。STM32F103的Flash擦写寿命标称10000次,GD32的标称也是10000次,但在实际频繁擦写的场景下(比如每秒钟擦写一次),GD32的Flash在擦写了约8000次后开始出现写入失败的情况,而STM32在10000次以内基本稳定。
这个差异对于需要频繁存储数据的应用(比如数据记录仪)很重要。我的建议是:如果应用需要频繁擦写Flash,要么降低擦写频率,要么外挂EEPROM或FRAM。另外,GD32的Flash编程时间比STM32略长,STM32的页擦除时间典型值是20ms,GD32实测在25ms左右。这个差异在需要快速启动的场景下需要注意。
4. CH32V103与RISC-V:新架构的真实体验
4.1 RISC-V工具链的成熟度评估
CH32V103是沁恒微电子推出的基于RISC-V内核的MCU,主频80MHz,引脚和STM32F103兼容。我用的开发环境是MounRiver Studio,这是沁恒官方推荐的IDE,基于Eclipse定制。说实话,第一周用下来是有点崩溃的。MounRiver的界面和STM32CubeIDE很像,但稳定性差一些,偶尔会卡死,调试器连接也偶尔掉线。
不过经过几个版本的更新,现在的MounRiver Studio已经稳定很多了。工具链方面,RISC-V GCC的成熟度已经相当高,编译优化效果和ARM GCC差距不大。我做了个对比测试,同样的C代码,用RISC-V GCC和ARM GCC分别编译,代码体积差异在5%以内,执行效率差异在10%以内。对于大多数应用来说,这个差距是可以接受的。
但要注意,RISC-V的调试体验和ARM还有差距。J-Link对RISC-V的支持不如对ARM那么完善,单步调试时偶尔会出现跳转异常。沁恒自家的WCH-Link调试器反而更稳定,建议用官方调试器。
4.2 中断控制器的差异
RISC-V的中断控制器架构和ARM的NVIC完全不同。CH32V103使用的是PFIC(Programmable Fast Interrupt Controller),支持中断嵌套和快速中断响应。实际测试中,CH32V103的中断响应延迟大约是6个时钟周期,比STM32和GD32都快。这是因为RISC-V的中断处理机制更简洁,不需要像ARM那样保存大量上下文。
但这也带来了一个问题:RISC-V的中断优先级配置比ARM复杂。PFIC支持8级优先级,但配置方式和NVIC不同,需要直接操作PFIC寄存器。沁恒提供了封装好的函数,但文档不够详细,我花了不少时间才搞明白。如果你打算用CH32V103,建议仔细阅读PFIC的寄存器手册,不要想当然地套用ARM的经验。
4.3 外设的兼容性与差异
CH32V103的外设和STM32F103高度相似,GPIO、USART、SPI、I2C、ADC、定时器都有,但寄存器地址和位定义不同。沁恒提供了标准外设库,函数命名和STM32的标准库很像,但参数和返回值有差异。比如GPIO_Init函数的参数结构体,CH32V103的GPIO_InitTypeDef和STM32的字段顺序不同,直接复制代码会编译错误。
我建议的做法是:不要试图直接移植STM32的代码,而是重新写外设初始化部分。虽然看起来麻烦,但实际上CH32V103的外设配置比STM32简单,寄存器更少,配置起来更快。我重新写一个USART初始化的时间大约是15分钟,比调试移植代码的时间短。
4.4 实际项目中的稳定性表现
我用CH32V103做了一个小批量的物联网网关项目,运行了六个月,出货大约500台。返修率在1%左右,主要问题是串口在高温环境下偶发通信异常。排查后发现是CH32V103的USART在波特率高于115200时,对时钟精度的要求比STM32高。STM32的USART可以容忍3%的波特率误差,CH32V103大概只能容忍2%。如果外部晶振精度不够,就容易出问题。
解决办法是换用更高精度的晶振,或者降低波特率。我把波特率从115200降到57600后,问题就消失了。这个细节在数据手册里没有明确说明,是我通过批量测试总结出来的。
5. 国产芯片的生态短板与应对策略
5.1 开发工具链的差距
国产MCU最大的短板不是芯片本身,而是开发生态。STM32有CubeMX、CubeIDE、STM32CubeProgrammer一整套工具,配置外设、生成代码、烧录调试一气呵成。国产芯片的工具链要么是魔改Eclipse,要么是命令行工具,体验差很多。
GD32有自己的GDFirmware库和GD32CubeMX,但GD32CubeMX的功能比STM32CubeMX少很多,比如不支持FreeRTOS的图形化配置,不支持中间件集成。CH32V103的MounRiver Studio虽然集成了很多功能,但稳定性和易用性还有提升空间。
我的应对策略是:对于GD32,直接用STM32CubeMX生成代码,然后手动替换外设库文件。因为GD32和STM32的外设寄存器高度相似,大部分代码可以直接用。对于CH32V103,老老实实用MounRiver Studio,虽然体验一般,但至少官方支持到位。
5.2 社区与文档的不足
STM32有庞大的社区支持,遇到问题随便一搜就有答案。国产芯片的社区规模小很多,很多问题只能靠自己摸索或者找原厂FAE。我遇到过一个问题:GD32的CAN通信在特定条件下会丢帧,搜遍了中文论坛都没找到答案,最后是原厂FAE给了一个寄存器配置的修改方案才解决。
文档方面,国产芯片的数据手册质量参差不齐。GD32的数据手册比较详细,但有些章节是直接翻译自STM32的,存在翻译错误。CH32V103的数据手册相对简略,很多细节需要看寄存器手册。我的建议是:拿到芯片后,先花时间通读数据手册和寄存器手册,把关键外设的寄存器都过一遍,不要依赖库函数。
5.3 长期供货与质量一致性
这是国产芯片最让人担心的问题。STM32的供货虽然紧张,但质量一致性很好,不同批次的芯片行为一致。国产芯片在这方面还有差距。我遇到过GD32不同批次的GPIO驱动能力有差异,导致同一批板子有的LED亮度正常,有的偏暗。虽然差异不大,但对于量产产品来说,这种不一致性会增加调试成本。
应对策略是:在量产前做小批量试产,验证不同批次芯片的一致性。如果发现差异,要么调整外围电路设计,增加余量,要么和原厂沟通,要求提供一致性更好的批次。另外,尽量选择有长期供货承诺的型号,避免用到一半停产。
6. 一年使用后的综合评估与选型建议
6.1 性能与成本的平衡
经过一年的使用,我对国产芯片的整体评价是:能用,而且有些场景下很好用,但不能无脑替换。GD32F103在GPIO速度和中断响应上甚至优于STM32F103,价格只有STM32的三分之一左右,对于成本敏感的项目很有吸引力。CH32V103的RISC-V内核在中断响应上也有优势,但工具链和生态还需要时间完善。
成本方面,以2023年的市场价为例,STM32F103C8T6大约15-20元,GD32F103C8T6大约6-8元,CH32V103C8T6大约4-5元。对于大批量产品,这个成本差异非常可观。但要注意,替换后可能需要额外的调试时间和外围电路调整,这些隐性成本也要算进去。
6.2 不同场景的选型建议
根据我的经验,不同场景下的选型建议如下:
| 应用场景 | 推荐芯片 | 理由 |
|---|---|---|
| 工业控制 | GD32F103 | 中断响应快,外设兼容性好,价格适中 |
| 消费电子 | CH32V103 | 成本最低,性能够用,RISC-V生态在成长 |
| 物联网网关 | GD32F103或STM32 | 需要稳定的网络协议栈支持,STM32生态最完善 |
| 电机控制 | GD32F103 | 定时器和PWM精度好,GPIO速度快 |
| 低功耗应用 | 需谨慎评估 | 国产低功耗芯片与STM32L系列还有差距 |
6.3 替换过程中的避坑清单
最后整理一份替换过程中的避坑清单,都是我用时间和项目换来的经验:
- 不要直接复制STM32的启动文件:GD32和CH32V103的启动文件不同,中断向量表地址和堆栈配置有差异,必须用原厂提供的启动文件。
- 注意时钟树配置:GD32的PLL配置和STM32略有不同,特别是USB时钟,配置错误会导致USB无法识别。
- Flash等待周期:GD32在72MHz下需要2个Flash等待周期,STM32是2个,但GD32在超频到108MHz时需要3个,配置错误会导致程序跑飞。
- 串口波特率误差:CH32V103对波特率误差更敏感,建议使用外部晶振而不是内部RC振荡器。
- CAN通信的终端电阻:GD32的CAN收发器驱动能力比STM32弱,终端电阻建议用120Ω,不要用两个60Ω并联。
- ADC参考电压:国产芯片的ADC参考电压精度普遍不如STM32,如果对精度要求高,建议外挂基准源。
- 调试器兼容性:J-Link对国产芯片的支持有限,建议用原厂调试器,比如GD-Link或WCH-Link。
- FreeRTOS移植:GD32和CH32V103的FreeRTOS移植需要修改port.c中的上下文切换代码,不能直接用STM32的移植文件。
这一年用下来,我的体会是:国产芯片已经过了“不能用”的阶段,进入了“能用但需要适应”的阶段。对于新项目,如果成本压力大,国产芯片是值得考虑的选项。对于存量项目替换,建议先小批量验证,确认稳定性后再批量切换。芯片选型没有绝对的好坏,只有适不适合你的项目。