ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32换CKS32国产芯片:Keil烧录、调试与代码移植避坑指南

STM32换CKS32国产芯片:Keil烧录、调试与代码移植避坑指南 事情发生在上半年我把一块打样回来的板子焊好连上ST-Link准备点灯。Keil的下载按钮按下去进度条跑到一半弹出来一个Error: Flash Download failed - “Cortex-M3”。我还没当回事以为是接线松了重新插了一下再烧还是同样的报错。折腾了二十分钟我才注意到板子上那颗芯片的丝印不太对——不是STM32F103C8T6而是CKS32F103C8T6。是的采购那边在没通知我的情况下把主控换成了中科芯的CKS32替代料。原因很简单ST的芯片当时交期长、价格高国产Pin-to-Pin兼容方案能省不少成本。问题是我手里的Keil工程、Pack包、下载算法全都是按STM32配置的。这个项目我用了大半年STM32从来没想过“换芯片”这件事能给我带来这么大一堆麻烦。今天这篇就好好梳理一下从STM32切到CKS32之后工具链、Pack包、烧录、调试、代码移植这几个环节到底有哪些坑以及我是怎么一个个填平的。1. 替代芯片到底动了谁的奶酪1.1 硬件工程师和软件工程师看到的是两个世界CKS32和STM32在硬件上确实是高度兼容的引脚定义、封装、大部分外设寄存器地址都能对上甚至芯片的IDCODE都是同一个。硬件工程师只需要改PCB上个别去耦电容的摆放位置其他几乎不用动这也是采购敢直接切换的原因。但从软件开发的角度看事情就没那么简单。Keil MDK识别芯片靠的是一套CMSIS Pack机制芯片的型号、内核参数、Flash算法、SVD调试描述文件全部封装在Pack包里。Keil本身并不会自动认识“CKS32”这个型号它只认Pack里声明的device name。如果工程里的Device还是STM32F103C8而芯片实际是CKS32F103C8那编译链接没问题但一旦进入烧录环节Keil拿ST的Flash算法去擦写CKS32的Flash可能会因为ID校验、扇区参数不匹配而出错。我给一个画面感更强的类比STM32和CKS32就像两个长相几乎一样的人长得像说话声音也像但你拿A的身份证去B的柜台办业务系统还是会把B拦下来。问题不在人长得像不像而在系统认不认。1.2 CKS32到底是不是“拿来主义”这件事得客观说。CKS32是国产芯片厂商在Arm Cortex-M内核基础上做的兼容设计它的目标很明确在寄存器层面、引脚层面做到和ST的主流型号兼容让客户可以无痛切换。这对终端厂商来说是实打实的好处——供应链多了一个选择价格有了谈判空间。但“兼容”不等于“一模一样”。我实测下来CKS32F103系列在以下几点和STM32还是有区别的部分芯片的唯一ID寄存器地址不完全一样读唯一ID的代码要改。Flash编程的时序参数、等待周期配置有细微差异低频下没感觉跑高频或者做IAP的时候容易出问题。低功耗模式下的唤醒源行为不完全一致尤其RTC唤醒的初始状态。内置RC振荡器的精度和温度特性不同如果拿它当RTC时钟源走时误差会比ST明显。网上搜“STM32内部32kHz做RTC”就能看到很多调校帖子换成CKS32之后这个误差范围还要重新测量。所以如果你负责的是一个长期维护的项目建议从一开始就把芯片型号独立成一个宏定义CKS32就编译CKS32的分支STM32就编译STM32的分支不要混在一个代码路径里裸奔。2. 新建工程时找不到CKS32Pack包的正确打开方式2.1 先从Keil的芯片列表聊起接触Keil时间不长的朋友可能对Pack包没太多概念。打开Keil MDK点击工具栏上的Pack Installer图标可以看到右边有一大排厂商列表ARM、STM32、NXP、GD32、CKS32等都在这里。每个厂商下面有对应的Device系列选中某个具体型号右侧会显示该芯片的Flash大小、RAM大小、内核等参数。正常情况下新建工程时只需要在Select Device窗口里找到对应厂商和型号工程框架就搭好了。但如果你直接用STM32的Pack去建工程列表里自然不会有CKS32——这就相当于你装了一个“普通话输入法”却指望它能打出粤语拼音它没有这个字库。2.2 离线Pack包安装的完整步骤我在公司内网环境工作外网下载受限所以用的是离线安装方式。步骤如下从CKS32官网或者靠谱的芯片资料站下载对应型号的CMSIS Pack包文件名一般长这样CKS32F1xx_DFP_x.x.x.pack。把它放到一个单独的目录比如D:\Keil_Packs\别直接丢桌面Keil扫的时候有可能因为路径太长或带中文符号识别不了。打开Keil MDK选择Pack Installer点击左上角的File菜单选Import from Folder指向刚才的目录然后等待Keil解析。解析完成之后Pack Installer的列表中就会出现CKS32的条目同时在CKS32下面的Device列表里可以选择具体的型号。新建工程在Select Device窗口左侧找到CKS32选中你的具体型号OK。安装完成后我还习惯做一步验证打开C:\Users\用户名\AppData\Local\Arm\Packs目录确认CKS32的文件夹已经出现并且里面有Flash、SVD等子目录。这一步用来看Pack包的完整性CKS32对应的Flash算法文件就在Flash目录下。2.3 在线安装不行怎么办很多人会遇到在线Pack Installer里搜不到CKS32的情况。原因可能有几种Keil版本太老MDK 5.20之前的版本对新的Pack格式支持不完整建议至少升级到5.30以上。网络问题导致Pack包下载失败这种情况下Pack Installer会一直转圈但什么都不显示。厂商发布的Pack在Arm的索引服务器里更新不及时不是每个国产芯片厂商的Pack都能第一时间进到Keil的在线仓库里。我当时的处理方式比较简单直接找代理商的FAE要了一个离线Pack包。这里多说一句如果你在公司项目里使用CKS32建议让采购或硬件同事找原厂/代理商正规渠道要Pack包、数据手册、参考手册、勘误表这些文件必须归档。搜索引擎搜出来的第三方“补充Pack”有时候会捆绑一些来路不明的文件对开发工具链的安全性和稳定性都有隐患。3. 烧录报错才是真正折磨人的环节3.1 问题现象Flash Download failed把CKS32的Pack包装好之后我以为万事大吉直接在旧工程的Options对话框里把Device从STM32F103C8改成了CKS32F103C8重新编译0错误0警告然后点下载。报错来了。Error: Flash Download failed - Cortex-M3我当时一脸懵明明工程已经切到CKS32了怎么烧写还失败。后来才意识到工程设置里Device改了但Flash Download页面中的Programming Algorithm还是老的ST Flash算法。Keil不会因为Device变了就自动帮你换Flash算法它只是把原来的配置沿用下来。解决办法是在Options for Target-Utilities-Settings-Flash Download里把原来的STM32 Flash算法删掉然后点击Add从列表中选择CKS32对应的算法文件。这一步做完再烧录进度条正常走完问题解决。3.2 算法列表里没有CKS32的FLM怎么办正常情况下装了CKS32的Pack包之后Flash算法列表里会出现CKS32的FLM文件因为这些.flm文件都已经随Pack包安装到了Keil的ARM\Flash目录下。但如果你的Flash算法列表里仍然没有CKS32可以手动检查并添加打开Keil安装目录下的ARM\Flash文件夹确认是否存在CKS32F1xx_512.FLM之类的文件。如果没有回到Pack包解压出来的目录从Flash子目录里把对应的.flm文件复制过去。回到Keil的Flash Download页面点击Add如果列表里还是不显示那就点Add对话框右下角的Browse手动定位到刚才复制过去的FLM文件。这里有一个实操提醒FLM文件的名称和芯片型号是对应的不要随便把STM32F103的FLM改个名字冒充CKS32用。虽然两者原理类似但芯片ID校验、Flash扇区大小等参数如果有差异强行使用会在后续量产烧录时埋雷。3.3 调试器连接不稳定的排查思路烧录问题解决之后紧接着出现的是调试问题。我当时用ST-Link连接CKS32Keil提示No target connected但用万用表量SWDIO、SWCLK的电压都正常芯片供电也正常。后来排查下来是三个原因叠加ST-Link固件版本太旧对非ST芯片的ID识别支持不好。STM32和CKS32的IDCODE确实是同一个但有些老固件对目标芯片的ID读取时序比较挑剔。解决办法是升级ST-Link固件。SWD两根线的上拉电阻没焊。CKS32的SWD引脚内部上拉默认是开启的但有些情况下PCB上预留了外部上拉电阻的位置结果贴片时没贴导致SWD信号在高速模式下不稳定。补上10k上拉电阻之后好了很多。Keil的Debug页面里没有选对调试器接口比如把SW模式误设成了JTAG模式。另外提醒一点如果芯片烧录过一次程序且程序里把SWD引脚复用成了GPIO那之后再想连接调试器就会失败。STM32有个“禁用JTAG”的说法很多人在代码里调用GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE)来释放JTAG引脚当普通IO用这个函数只会禁用JTAG不会禁用SWD。但如果你的程序把SWDIO、SWCLK也配置成了GPIO输出那调试器就彻底连不上了只能通过串口ISP擦除或者用Bootloader恢复。4. 代码移植与引脚差异的实测记录4.1 能直接用的部分比你想的多CKS32和STM32的寄存器级兼容性做得很不错。我原来基于STM32标准外设库写的GPIO初始化、串口收发、定时器PWM输出、外部中断这些代码在CKS32上编译之后直接就能跑不需要改动。SPI、I2C、ADC这些外设的寄存器结构体也是对齐的用标准库或者HAL库操作时基本无感。如果你用的是寄存器操作那么还需要确认外设基地址是否一致。以CKS32F103系列为例GPIOA的基地址是0x40010800USART1的基地址是0x40013800这些和STM32F103是完全一致的。也就是说大部分情况下你的寄存器操作代码不需要改地址。4.2 几个容易踩的软性差异代码层面无感不代表没有任何差异。我在实际项目中遇到了几个比较典型的问题Flash等待周期。STM32F103在72MHz主频下需要2个Flash等待周期这个CKS32是一样的。但如果你把主频降下来跑比如24MHz或36MHz某些CKS32型号对Flash等待周期的要求会更严格配置不对会出现程序跑飞、随机死机。排查这种问题很痛苦因为代码逻辑没问题硬件连接没问题但就是偶尔跑几个小时死一次。后面我直接参考CKS32参考手册里的Flash接口章节按它给的等待周期表重新配置问题消失。RTC时钟源。原项目用的外部32.768kHz晶振这个没差别。但有一个低功耗项目为了省成本用了内部32kHz RC作为RTC时钟源在STM32上每天误差大概5~10秒换了CKS32之后误差变大了不少每天能差到30秒以上。后来只能改成外部晶振方案顺便在软件里做了温度补偿。如果你有类似需求建议别省这颗晶振的钱。唯一ID的读取。很多产品需要读取芯片唯一ID做加密、授权或者设备标识。STM32F103的唯一ID放在0x1FFFF7E8CKS32的存放位置不一定在同一个地址。这个必须对照手册确认我当时没确认读出来的ID全是0xFFFFFFFF排查了半天才发现是地址问题。4.3 SVD文件一定要换Keil在Debug模式下查看外设寄存器依赖SVD文件。如果你用STM32的SVD去调试CKS32会发现大部分寄存器能正常显示但个别寄存器的位域定义对不上查看时会出现“Unknown”或者错误的值。这个不影响编译和烧录但会影响调试效率。正确做法是在Options for Target-Debug-Settings-Debug标签下的SVD File路径里换成CKS32的SVD文件。CKS32的Pack包里带了对应的SVD安装好之后直接用Browse定位过去就行。5. 量产烧录与生产阶段的注意事项5.1 J-Flash和ST-Link Utility的兼容性除了Keil开发阶段要用到CKS32的Pack包之外产线批量烧录环节也一样要注意。如果产线用的是J-Flash那么需要先在J-Flash中确认有没有CKS32对应的Device。我实测用的J-Flash版本较新直接在Device列表里搜索CKS32能找到对应型号。如果你用的版本比较老找不到CKS32可以在烧录时选择同容量的STM32型号然后手动配置芯片ID但这种方法有风险如果烧录工具做了ID校验会直接拒绝烧录。ST官方有一个ST-Link Utility工具用于STM32的烧录、读取、选项字节配置。这个工具对CKS32的兼容性一般不建议在产线上作为主要烧录工具。如果你手头只有ST-Link可以用STM32CubeProgrammer它支持自定义外部Loader配合CKS32的算法文件也能完成烧录但配置过程比较繁琐。5.2 读保护与写保护千万别乱开CKS32的选项字节Option Bytes设计跟STM32有不少相似之处但具体的bit定义不是百分之百一致。我在一个量产项目里为了让固件不被轻易读出来打开了读保护RDP。在STM32上这个操作很常规但在CKS32上我遇到了一个情况打开RDP之后SWD接口依然能连上但读取Flash数据全是0xFF经过排查确认是读保护生效了。这里的坑在于如果你需要对CKS32做RDP降级从Level 1降到Level 0CKS32和STM32一样会自动执行一次全片擦除。也就是说千万别在没备份固件的情况下随便动选项字节否则降级操作会把整片Flash清掉。如果你在产线上用了错误的选项字节配置可能导致芯片锁定烧录工具无法连接。这时候有一些“软恢复”的办法比如用J-Link Commander执行unlock命令或者用串口ISP方式连接Bootloader重新擦除。但不同型号的CKS32在锁定状态下的恢复流程不完全一样最稳妥的办法还是先在一颗样品上把选项字节的配置验证完确认无误后再上产线。5.3 批量烧录时怎么保证一致性量产烧录环节我建议做到以下几点从芯片原厂或正规代理商获取量产烧录的算法文件优先使用厂商提供的FLM。烧录完成后做校验不要只依赖烧录工具默认的“烧录即成功”提示最好在固件里增加自检逻辑比如上电后校验Flash的CRC或者和外部通信时返回固件版本。如果芯片有多个批次混料注意同一批板子上可能既有STM32又有CKS32。这种混料状态在生产环境中很常见如果产线烧录工具只认一种芯片ID混料会导致部分板子烧录失败。这时候要么让产线分批次过站要么在烧录脚本里同时兼容两种芯片ID。6. 常见问题速查表问题现象可能原因解决办法新建工程时器件列表里找不到CKS32Keil没有安装对应的CMSIS Pack包从官网/代理商获取离线Pack用Pack Installer导入烧录报错Flash Download failedFlash编程算法还是STM32的在Flash Download页面删除旧算法添加CKS32的FLM烧录时进度条不走一直卡住目标芯片ID和FLM中的ID不匹配确认FLM和芯片型号严格对应不要混用能烧录但程序跑不起来Flash等待周期配置不对对照CKS32参考手册按主频重新配置Flash等待周期SWD连接不上Keil提示No target调试器固件旧/上拉电阻缺失/代码禁用SWD升级ST-Link固件补焊10k上拉进入Bootloader或用ISP擦除读取芯片唯一ID全是0xFF唯一ID寄存器地址和STM32不同查CKS32手册修改读取地址Debug模式下寄存器显示异常SVD文件不匹配换成CKS32自带的SVD文件打开读保护后芯片不可用选项字节配置不兼容或操作时序不对用J-Link解锁或ISP重擦量产前先验证选项字节配置内部RC做RTC时钟误差非常大CKS32内部RC精度和温度特性不如ST换外部晶振或者软件做温度补偿7. 替代芯片项目里的一点实在建议折腾完这一轮我对“国产替代”这件事有了更实际的感受。替换芯片绝不只是把焊盘上的丝印换一换那么简单它牵涉到工具链、调试方式、烧录产线、量产验证等多个层面。如果你所在的项目也准备从STM32切换到CKS32我的建议是第一拿到样片后第一步先做最小系统验证搭建一个最简单的点灯工程把时钟配置、Flash烧录、SWD调试跑通。这一步花不了多少时间但能排掉80%的工具链问题。第二别急着把整个项目代码切过去先把基础外设模块逐个验证GPIO、串口、定时器、中断、ADC、I2C、SPI每个模块的差异记录下来。最怕的是整个工程一股脑切过去然后出现问题不知道从哪里排查。第三和采购、硬件同事事先约定一个“备选芯片切换”的流程。这个流程里至少要包含芯片型号宏定义、启动文件切换、Pack包归档、烧录算法确认、量产烧录验证这几个环节。只要每个环节都有明确的操作指引替换芯片这件事就会从“踩坑”变成“常规操作”。Pack包的问题只是第一道坎过了这道坎后面还有时钟树、选项字节、产线兼容这些更细碎的事情等着你。但只要把验证流程建立起来国产芯片用起来并没有想象中那么可怕甚至在某些特定场景下CKS32的供货稳定性和原厂支持响应速度反而能给你带来不少便利。我现在手头这个项目已经把STM32和CKS32的代码分支统一管理了硬件上无论贴哪颗芯片固件都能自适应。这段经历让我收获最大的不是学会了怎么装Pack包而是明白了一个道理做嵌入式开发永远不要假设芯片型号会一成不变提前做好兼容设计比什么都重要。
返回列表