ARTICLE DETAIL

资讯详情

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

STM32F103C8T6迁移到RCT6:Keil工程启动文件、Flash算法与内存配置全攻略

STM32F103C8T6迁移到RCT6:Keil工程启动文件、Flash算法与内存配置全攻略 先抛一个问题你的项目在STM32F103C8T6上跑得正欢突然要加屏幕、加Modbus、加日志Flash只剩几个KB内存也天天告警怎么办很多人第一反应是“换个大芯片”然后打开Keil把Device从STM32F103C8T6改成STM32F103RCT6点编译。结果要么烧不进去要么上电就HardFault。C8T6和RCT6虽然都叫STM32F103内核也都是Cortex-M3但它们在存储容量、封装脚位、外设数量、启动文件、Flash烧写算法这几个维度上确实不是简单“替换型号”就能完事的东西。所谓的“无缝转换”我的理解是工程层面平滑切换而不是你拿C8T6的PCB直接焊一颗RCT6上去用。这篇就记录我把一个Keil工程从C8T6迁到RCT6的完整操作包含Device选择、启动文件替换、宏定义修改、Target内存配置、下载算法调整还有实际踩过的坑。1. 换芯之前先看明白C8T6和RCT6到底差在哪1.1 芯片资源差异表做转换之前先把两颗芯片的关键差异列出来心里才有数。项目STM32F103C8T6STM32F103RCT6内核Cortex-M3 72MHzCortex-M3 72MHzFlash64KB0x10000256KB0x40000SRAM20KB0x500048KB0xC000封装/引脚LQFP48LQFP64定时器TIM1、TIM2/3/4TIM1/TIM8、TIM2/3/4/5、TIM6/7串口USART1/2/3USART1/2/3 UART4/5ADCADC1/2ADC1/2/3密度等级Medium DensityHigh Density别看主频一样Flash和RAM直接翻了几倍。更重要的是RCT6从“中密度”跨到了“高密度”这个密度差异会牵扯到Keil工程里三样关键东西启动文件、预处理宏、Flash下载算法。这三样没对齐后面一定会出事。1.2 密度差异为什么是核心矛盾STM32F103家族在标准外设库和CMSIS里会按Flash和SRAM容量把芯片分成低密度、中密度、高密度。C8T6属于中密度RCT6属于高密度。这个分类不只是容量问题还会影响中断向量表、内置Flash编程的页大小、部分外设的数量和寄存器布局。举个例子高密度芯片的中断向量表里比中密度多了TIM5、TIM6、TIM7、TIM8、UART4、UART5、ADC3、SDIO等中断入口。你如果工程里还挂着中密度的启动文件这些新增中断入口根本不存在程序一旦触发这些中断就会跳进一个默认的弱定义里表现就是HardFault或者功能完全没反应。所以我把“替换启动文件”这件事排在所有修改里最前面你后面就明白为什么了。2. Keil工程切换从Device到链接脚本的核心配置2.1 在Device选项卡里更换目标芯片打开Keil工程点菜单栏的“Project - Options for Target”或者直接点工具栏那个“魔术棒”图标切到“Device”选项卡。在芯片树里找STMicroelectronics - STM32F1 Series - STM32F103 - STM32F103RCT6选中点OK。这一步看起来简单但有几个细节需要确认。第一你的MDK版本和Pack包要支持RCT6。建议用Keil MDK 5.37以上版本并且在Pack Installer里把STM32F1系列的Device Family Pack装好。如果Pack没装好Device列表里找不到RCT6或者选中后会弹一堆编译错误。第二选中RCT6后Device页面下方会显示这颗芯片的Flash和RAM描述先确认显示的是256KB Flash、48KB RAM再继续这是第一道保险。选完Device后如果你直接编译大概率会报错误或者警告因为工程里很多配置还是老C8T6的。接下来才是重点。2.2 替换启动文件与预处理宏换完DeviceKeil并不会自动替你删掉旧的启动文件。打开工程树找到STARTUP文件夹下的startup_stm32f10x_md.s这就是中密度启动文件。右键“Options for Group”或者直接“Manage Project Items”把它从工程里移除然后添加新的startup_stm32f10x_hd.s。添加HD启动文件的方式我推荐直接从标准外设库或者STM32Cube固件包里拿。标准外设库的路径一般在Libraries/CMSIS/Device/ST/STM32F10x/startup/arm/startup_stm32f10x_hd.s如果你用的是STM32CubeF1固件包路径类似Drivers/CMSIS/Device/ST/STM32F10x/Source/Templates/arm/startup_stm32f10x_hd.s添加完启动文件后还要同步修改预处理宏。如果工程是标准外设库写的打开“C/C”选项卡在Define里把STM32F10X_MD改成STM32F10X_HD。之前定义的USE_STDPERIPH_DRIVER等宏保留。这一步非常重要因为stm32f10x.h就是靠STM32F10X_HD来识别高密度芯片然后决定Flash页大小、外设地址、中断号等定义。不少人改完Device就忘了改宏结果编译能过但调用RCT6新增外设时要么编译不过要么运行异常。这种问题最隐蔽我建议你把“换启动文件”和“换宏”当成一组操作谁做都别拆开。2.3 修改Target内存参数含分散加载文件选完器件和宏下一步是检查“Target”选项卡里的内存范围。很多人忽略这个然后遇到链接错误。打开“Options for Target - Target”在Memory Areas区域做两处修改IROM1Start保持0x08000000Size从0x10000改成0x40000。IRAM1Start保持0x20000000Size从0x5000改成0xC000。如果你的工程勾选了“Use Memory Layout from Target Dialog”改这里就够了。但如果你的工程用了自定义的分散加载文件.sct那还得同步修改sct文件。一个典型的旧sct文件长这样LR_IROM1 0x08000000 0x00010000 { ER_IROM1 0x08000000 0x00010000 { *.o (RESET, First) *(InRoot$$Sections) .ANY (RO) } RW_IRAM1 0x20000000 0x00005000 { .ANY (RW ZI) } }换成RCT6后需要改成LR_IROM1 0x08000000 0x00040000 { ER_IROM1 0x08000000 0x00040000 { *.o (RESET, First) *(InRoot$$Sections) .ANY (RO) } RW_IRAM1 0x20000000 0x0000C000 { .ANY (RW ZI) } }改完编译后最好打开工程目录下生成的.map文件看最前面的“Memory Map of the image”确认ROM和RAM范围已经变成0x40000和0xC000。这一步是验证Target配置有没有生效的最直接方法。2.4 更新Flash下载算法这是很多人烧不进代码的元凶。C8T6默认用的下载算法是“STM32F10x Medium-density Flash 64K”但RCT6的Flash是256KB必须换成“STM32F10x High-density Flash 256K”。操作路径Options for Target - Debug - 选择调试器ST-Link、J-Link、DAP等 - Settings - Flash Download。在Programming Algorithm列表里把旧的Medium-density算法删掉点Add选择“STM32F10x High-density Flash 256K”。有朋友会问我明明用的是ST-Link为什么还要关心Flash算法因为Flash算法是由MDK和调试器的调试驱动管理的跟你用什么调试器品牌关系不大。算法里包含了芯片内部Flash的扇区大小、擦除命令、编程时序选错了算法轻则烧录失败重则擦写到一半卡死。如果你使用旧版MDKFlash Download可能在Utilities选项卡里路径不同但逻辑一样。反正就是找到当前调试器设置里的Flash Download或Programming Algorithm把算法改成High-density。3. 标准外设库和HAL库的转换差异3.1 SPL库宏定义与内部Flash编程如果你的工程用的是标准外设库前面的宏修改已经覆盖了主要问题。这里再单独强调一下Flash编程。如果项目里做bootloader或者参数存储会调用Flash擦写函数。在stm32f10x_flash.c里标准外设库会按STM32F10X_HD或STM32F10X_MD来选择Flash页大小和擦除逻辑。中密度和高密度的Flash页大小不一样中密度通常按1KB页处理高密度通常按2KB页处理。宏还是MD的话擦写Flash时可能只擦一半或者地址计算错误导致参数区数据损坏。这种问题不到现场很难抓。所以如果你在C8T6工程里写过内部Flash换到RCT6之后除了把宏改成STM32F10X_HD还要把你调用Flash擦写时的页大小参数重新核对一遍。别小看这几行函数项目一旦跑起来数据损坏就是灾难。3.2 HAL库CubeMX重生成还是手动改宏如果你用的是STM32CubeMX生成的HAL工程最省事的办法是打开CubeMX把芯片型号从STM32F103C8Tx改成STM32F103RCTx然后重新生成代码。生成的工程会自动把预处理宏设置成STM32F103xE也会自动更新启动文件和Flash算法省掉不少麻烦。如果你不想动CubeMX也可以手动改。C8T6的HAL工程里宏定义通常是STM32F103xB需要改成STM32F103xE。这个宏会影响stm32f1xx_hal_conf.h里的外设开关以及stm32f1xx.h里的芯片规格定义。如果宏不改RCT6上的TIM8、UART4/5、ADC3这些外设在HAL层可能没有对应的驱动实例强行调用会编译报错或者运行时访问非法地址。另外如果原来的C8T6工程里跑着FreeRTOS换了RCT6之后记得把FreeRTOSConfig.h里的configTOTAL_HEAP_SIZE调大一点。比如从2KB调到12KB反正内存翻了不止一倍堆大小可以大大方方扩容。用heap_4的话内存管理效率也会更高。3.3 中断向量与外设驱动的同步不管你是用SPL还是HAL换到高密度芯片后都要去看一下中断服务函数文件。C8T6工程里的stm32f10x_it.c可能只写了中密度设备的中断处理比如USART1、TIM2之类。RCT6新增的中断源比如TIM5、UART4、UART5、ADC3可能一个处理函数都没有。如果你打算用到这些新外设必须自己补对应的IRQHandler函数同时在启动文件里确认这些中断入口已经存在。很多时候你照着手册配置好了UART4但中断就是不触发查到最后发现是启动文件里根本没有UART4_IRQHandler这个入口。所以我的习惯是换完启动文件后打开文件搜一下IRQHandler看看我要用到的外设中断名在不在里面再做下一步。4. 引脚变化与外围设计核对清单4.1 LQFP48与LQFP64的IO差异C8T6是LQFP48RCT6是LQFP64物理封装不一样引脚数量也不一样。C8T6的GPIO大概37个RCT6大概是51个。多出来的主要是PC0~PC12这些C口引脚以及PD2等D口引脚。48脚封装上PC13、PC14、PC15是有的但PC0~PC12大部分没有引出来。所以原来在C8T6上不敢用的PC口资源到了RCT6就能光明正大地用了。这里有个很典型的例子USART3的重映射。C8T6是48脚封装PC10和PC11没有引出来所以如果你想把USART3重映射到PC10/PC11根本做不到。换到RCT6的64脚封装后PC10/PC11就出来了USART3的重映射选项变得完全可用。这种情况下代码层面可能只需要改一下GPIO初始化和AFIO重映射但前提是你的芯片封装真的把这些引脚引出来了。4.2 新增引脚和外设需要注意的复用关系换到RCT6后可以用的外设多了但也不是所有引脚都能随意复用。GPIO的复用映射在STM32F103的数据手册里有一张表里面写了每个引脚可以复用成哪些外设功能。比如TIM1_CH1通常是PA8但同时也可以从PE9复用过来但PE9在64脚封装上不一定有。同样ADC3的某些通道可能在PA口上也可能在PF口上PF口在64脚封装里基本没引出来所以能用到的ADC3通道有限。我的建议是配置新外设之前先打开对应封装的引脚图把你打算用的引脚和外设功能对照一遍。不要只看芯片是RCT6就以为所有资源都能用封装会把一部分功能“锁”在芯片肚子里。这是STM32F103选型时最容易踩的坑。4.3 硬件层面的电源、地、BOOT检查RCT6因为是64脚封装会有一些C8T6没有的引脚比如VREF、VREF-。在大多数开发板上VREF会接到3.3VVREF-接到GND。如果你是自己画板子记得把这些参考电压引脚处理好不然ADC精度会受影响。NRST、BOOT0、BOOT1这些引脚的接法和C8T6基本一致BOOT0拉低到GND走正常FLASH启动这个不用多改。如果你是想在C8T6原有的PCB上“无损替换”这里必须泼盆冷水C8T6和RCT6封装不同引脚不是一一对应的直接互换是不可能的。想硬件原位升级48脚封装应该选STM32F103CBT6但它的RAM依然是20KB只是Flash变成128KB。所以真正的跨档升级还是要换64脚或100脚的板子。5. 编译烧录中的“显眼包”错误与排查实录5.1 下载时提示“No Flash Device”或“Could not find device”这个现象在ST-Link和DAP下载器上都很常见。我排查过的项目里90%是因为Flash Download算法没有换成High-density。去Debug - Settings - Flash Download里看一眼如果列表里还是“STM32F10x Medium-density Flash 64K”直接换成“STM32F10x High-density Flash 256K”。换完重新上电下载一般就好了。如果算法换了还是报No Flash Device再检查BOOT0是不是拉低、复位电路是否正常、SWDIO和SWCLK有没有接对。有时候是调试器驱动问题重新拔插一次USB也能解决。5.2 程序跑起来就HardFault尤其是一开新外设这种问题我见过太多次。最常见的原因是启动文件还是旧的MD版本。工程树里如果挂着startup_stm32f10x_md.s即使你在C/C里把宏改成了STM32F10X_HD中断向量表里也不会自动多出UART4、TIM5、ADC3这些入口。一旦程序配置了这些外设并开启了中断CPU就会在中断响应时找不到入口最终跳进HardFault_Handler。排查方法很简单先把启动文件换成HD版本再查看map文件里是否有对应中断处理函数的地址。如果函数存在且地址落在向量表区域HardFault大概率就消失了。5.3 编译报“L6220E: Load region LR_IROM1 size exceeds limit”这个错误是链接器说你的代码超出了IROM1区域说白了就是Target里的Flash大小还没改。IROM1 Size还是0x10000而你的工程因为用了RCT6可能编译出来的代码量更大自然就超了。把IROM1 Size改成0x40000IRAM1 Size改成0xC000重新编译基本能解决。类似的还有“L6283E: RW area ... exceeds boundary”这通常是RAM大小没改。你把Target里的IRAM1改大之后这种错误也会消失。5.4 其他几个容易混的坑有一个坑和芯片关系不大但切换型号后特别容易出现Device Pack版本太旧。老工程用旧版CMSIS Pack在Keil新版本里打开会提示out of date不更新的话编译可能报一堆奇奇怪怪的错误。建议到Pack Installer里把STM32F1系列DFP更新到新版本同时把“C/C”里的C99 Mode打开。很多隐式声明的报错开了C99就没了。还有一个是调试器设置。换了芯片型号之后Debug选项卡里的调试器有时候会被重置。比如你原来用DAP打开调试时却提示“No ULINK Device found”一看原来是Device切回去没把调试器选对。重新在Debug下拉框里选回你的调试器再进Settings确认一下问题就没了。5.5 常见问题速查表现象主要原因解决办法下载失败/Flash算法错误下载算法未改为High-densityDebug-Settings-Flash Download换成High-density 256K编译提示启动文件找不到工程还引用MD启动文件替换为startup_stm32f10x_hd.s外设中断不响应启动文件中断向量没有入口换HD启动文件链接超ROM/RAMTarget内存范围没改IROM1改成0x40000IRAM1改成0xC000SPL库Flash操作异常宏仍是STM32F10X_MD宏改为STM32F10X_HDHAL库无法使用UART4/5宏仍是STM32F103xB宏改为STM32F103xEDebug报No ULINK Device调试器设置被重置Debug选项卡里重新选择对应调试器6. 转换过一次后我的几点体会这种“换大芯片”的操作我做过不止一次。第一次以为只要改一下CPU型号就行结果在Flash算法和启动文件上卡了小半天。后来学乖了每次做迁移前都会先备份一份原工程然后把启动文件、宏、Target内存、下载算法这四个点按顺序过一遍全部确认无误再编译。还有一个经验是换到RCT6之后不要急着把C8T6时代为了省资源而写的“抠门代码”全部重写。先跑通原来的业务逻辑再逐步启用新外设。比如原来用软件定时器节省硬件定时器现在有了TIM5、TIM6、TIM7可以把软件逻辑迁回硬件定时器但一次只迁一个功能测稳了再迁下一个。最后分享一个能提高效率的小技巧如果你是用标准外设库写的工程切换后想用UART4/5这些新串口别从零写驱动。先翻一下官方标准外设库里针对High Density芯片的示例代码把GPIO配置和USART初始化代码复制过来再根据实际引脚改一下复用映射基本半小时就能跑通。毕竟RCT6的资源比C8T6宽裕得多官方例程覆盖的外设也更全站在这些现成代码上改比硬自己搭框架省心不少。
返回列表