ARTICLE DETAIL

资讯详情

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

从STM32到华大HC32F460:嵌入式项目移植的实战指南与避坑手册

从STM32到华大HC32F460:嵌入式项目移植的实战指南与避坑手册 1. 项目移植前的“心动”与“冲动”先说结论项目从STM32F411移植到华大HC32F460能跑通容易能跑稳很难能跑出原方案的性能则更难。这个项目最初是基于STM32F411设计的功能涵盖传感器采集、电机控制、串口通信和简单的UI交互代码量不算大但涉及的外设比较多。之所以要移植原因并不复杂芯片缺货和成本压力是主要推手。如果你的项目也正处在“要不要换国产芯片”的犹豫期这篇记录可能比官方手册更贴近实际战场。我会把移植过程中踩过的坑、填坑的思路、以及事后复盘出来的方法论全部摊开来讲。不管你是刚要动手做评估还是已经在移植路上被坑得怀疑人生这篇文章都值得你花十分钟读完。项目背景可以简单描述一下原方案用STM32F411CEU6主频100MHzFlash 512KBRAM 128KB跑的是裸机定时器轮询架构外加一个简单的状态机。外设用了USART、I2C、SPI、ADC、TIM、DMA、GPIO中断。华大HC32F460系列主频可以跑到200MHzFlash最大1MBRAM 192KB资源上整体是“升级”的但升级不等于兼容。真正动起手来你会发现国产芯片“引脚兼容”和“寄存器兼容”是两个完全不同的概念。HC32F460用的是华大自研的HAL库API风格和ST的标准库、HAL库都不一样这意味着从底层寄存器到上层驱动大部分代码都要重写。这也是很多人移植到一半想放弃的根本原因。2. 为什么选择HC32F460芯片选型的那笔账2.1 算力与资源的真实对比在决定移植之前我先做了一个粗颗粒度的资源对比这个对比表后来也成了项目立项评审的核心材料。项目STM32F411CEU6华大HC32F460差异分析内核Cortex-M4FCortex-M4F相同架构指令集兼容最高主频100MHz200MHz华大更高但高频下Flash等待需注意Flash512KB最大1MB华大容量翻倍UI资源更充裕RAM128KB192KB华大更大适合跑LVGL等图形库ADC12bit多个12bit最多3个单元华大ADC通道布局不同需改引脚USART最多5路最多4路略缩水但实际够用定时器通用TIM高级TIM多个16位/32位定时器功能类似但名字和配置方式全变价格参考相对较高相对更低批量成本可降低20%-30%选HC32F460不只是因为便宜更多是因为它在主频和Flash配置上确实有优势。如果你后续想在设备上做本地数据显示、简单菜单甚至轻量级GUIHC32F460的200MHz主频加1MB Flash是足够跑的。2.2 为什么不用GD32或者AT32聊选型时一定会有人问为什么不选GD32或AT32这两个系列在国内也很火。我的答案是看你手上团队的积累和你要用的中间件生态。GD32F4系列在引脚上确实做到了和STM32F4的高度兼容但GD32的库函数风格迭代太快不同批次芯片的内部Flash和USB模块版本还有微调这在量产时是个隐形风险。AT32的生态相对封闭社区资料偏少。HC32F460对我来说有一个不可替代的优势华大的DDL驱动库提供了一整套外设驱动示例而且它的库和裸机代码耦合度低移植FreeRTOS或者做状态机架构时非常顺手。这一点在后面的实操中会被反复验证。3. 移植前必备的准备工作3.1 硬件准备不只是换芯片那么简单很多人拿到HC32F460的样片第一件事就是把STM32F411的板子上的芯片拆下来换上。这个行为我只能说“勇气可嘉后果自负”。两款芯片虽然都是LQFP封装但引脚定义差异非常大。以我用的HC32F460KETA为例它和STM32F411CEU6的引脚兼容性极差除了电源和地几乎没有几个脚能直接对应。所以第一步必须是做转接板或重新画板而不是跳线飞线硬上。硬件上需要准备的东西包括HC32F460最小系统板或自制转接板注意晶振布局HC32F460的HSE和LSE引脚位置和ST完全不同调试器建议用J-Link或DAP-LinkHC32F460支持SWD接口但复位脚的处理和ST有区别USB转串口模块用于日志输出和固件升级测试逻辑分析仪或示波器I2C、SPI时序调试必备尤其是I2C的时序容错差异电源模块注意HC32F460的IO耐压和STM32F411一样是5V容忍但ADC参考电压配置不同不能直接照搬3.2 软件环境Keil和IAR都在用HC32F460的官方支持包在Keil MDK和IAR上都有推荐直接用Keil MDK 官方DDL库的方式。华大的DDL驱动库可以从官网下载安装后会在Keil的Pack Installer里自动识别。这里有个细节华大官方库的版本之间差异比较大。早期的V1.x和后来的V2.x、V3.xAPI名字甚至文件结构都有变化。建议直接下载最新版本并固定一个版本作为项目基线避免后续升级库导致代码大面积修改。项目里如果遇到某些外设驱动bug优先去官网论坛搜已知问题而不是自己硬啃寄存器。3.3 评估移植工作量提前画好“代码地图”在正式动手之前建议先对现有代码做一次“摸底盘查”。方法是打开你的工程按功能模块列出每个模块依赖的外设、引脚、中断、DMA通道和时钟树。我当时的模块清单大概是这样的功能模块依赖外设引脚/通道移植难度评估电源监测ADC DMAPA0等中ADC配置差异大传感器采集I2CPB6/PB7高I2C时序和容错要调电机控制TIM PWMPA8/PA9中PWM频率和极性配置需重来数据通信USART DMAPA2/PA3低串口移植相对简单状态显示GPIO 定时器多个低但要注意引脚上拉/下拉配置固件升级USART FlashPA2/PA3高Flash扇区大小和地址映射完全不同有了这张地图你才能知道时间该花在哪哪些模块可以复用逻辑哪些模块必须推倒重写。4. 核心外设移植实操逐个击破4.1 时钟树的移植第一步就差点翻车所有MCU移植的第一步都是时钟。STM32F411的内部RC和外部晶振配置在华大HC32F460上完全不一样官方库的SystemClock_Config函数只是参考必须根据自己的板子重新配。HC32F460的时钟树核心逻辑是外部高速晶振XTAL或内部高速RCHRC作为源经过PLL倍频得到系统时钟最高可到200MHz。需要注意的是HC32F460的Flash等待周期配置如果不对主频一高就会随机死机。我在配置200MHz主频时遇到了一个很诡异的现象程序能跑但跑几十秒就进入HardFault。排查了很久才发现是Flash等待周期没有设置到位。// HC32F460 时钟配置关键代码示例 void SystemClock_Config(void) { stc_clock_xtal_cfg_t stcXtalCfg; stc_clock_pll_cfg_t stcPllCfg; MEM_UNUSED(stcXtalCfg); MEM_UNUSED(stcPllCfg); /* 使能外部高速晶振 */ CLK_XtalCmd(ENABLE); /* 配置PLL外部晶振8MHz倍频到200MHz */ stcPllCfg.enSrc CLK_PLL_SRC_XTAL; stcPllCfg.pllmDiv 1u; stcPllCfg.plln 50u; // 8MHz * 50 / 2 200MHz stcPllCfg.pllpDiv 2u; stcPllCfg.pllqDiv 4u; stcPllCfg.enCkDiv CLK_PLL_ICK_DIV1; stcPllCfg.enPllCkDiv CLK_PLL_PLLCK_DIV1; CLK_PLLInit(stcPllCfg); /* 关键配置Flash等待周期为2个周期 */ EFM_FlashWaitCycleSet(EFM_WAIT_CYCLE2); /* 切换到PLL作为系统时钟 */ CLK_SetSysClkSource(CLK_SYSCLK_SOURCE_PLL, CLK_SYSCLK_DIV1); }关于Flash等待周期的常规经验是80MHz以下可以设置1个等待周期100MHz以上建议2个等待周期200MHz必须确认寄存器里设置的等待周期数足够。这个比STM32F411要敏感一些ST的库会自动帮你处理但HC32F460的DDL库在某些版本里不会自动配置必须你自己调用EFM_FlashWaitCycleSet。4.2 GPIO移植引脚重映射和复用功能GPIO的移植在STM32上用HAL库很舒服GPIO_InitTypeDef把模式、速度、上下拉一次配好。HC32F460的GPIO配置思路类似但函数名和配置结构体不同而且引脚复用功能AF的映射关系完全不一样。HC32F460的GPIO配置分为两个步骤设置引脚方向和输入输出类型通过GPIO_SetFunc函数设置引脚的复用功能通过GPIO_SetAFIO函数这里最容易踩的坑是STM32的AF配置是直接在GPIO_Init里搞定的HC32F460则是单独的AFIO配置函数。如果忘记调用GPIO_SetAFIO引脚默认作为普通GPIO工作外设信号根本送不出去。我移植UART的时候就是漏了这一步折腾了差不多一晚上查原理图、查焊接最后发现是复用功能没使能。// HC32F460 GPIO配置示例PA2作为USART1_TXPA3作为USART1_RX void GPIO_Config(void) { stc_port_init_t stcPortInit; /* 配置PA2为USART1_TX */ stcPortInit.enPinMode PIN_MODE_MUX; // 复用模式 stcPortInit.enPullUp PIN_PU_DISABLE; // 无上拉 stcPortInit.enInOut PIN_OUTPUT; // 输出方向 PORT_Init(PORTA, PIN_02, stcPortInit); PORT_SetFunc(PORTA, PIN_02, Func_Usart1_Tx, DISABLE); // 配置AF /* 配置PA3为USART1_RX */ stcPortInit.enPinMode PIN_MODE_MUX; stcPortInit.enPullUp PIN_PU_ENABLE; // 建议使能上拉 stcPortInit.enInOut PIN_INPUT; PORT_Init(PORTA, PIN_03, stcPortInit); PORT_SetFunc(PORTA, PIN_03, Func_Usart1_Rx, DISABLE); }注意PORT_SetFunc的最后一个参数是选择是否使能数字输入缓冲。如果是ADC输入引脚这个参数需要使能如果是普通输出脚保持DISABLE即可。我在移植ADC时就被这个参数坑过读取的ADC值一直是0或满量程就是因为输入缓冲没有开。4.3 UART移植从阻塞到中断超时串口是嵌入式项目的生命线也是日志和调试的基础。STM32F411的HAL_UART_Transmit和HAL_UART_Receive在华大HC32F460里对应的是UART_SendData和UART_ReceiveData但阻塞逻辑和中断处理方式有区别。实际项目中我用了“中断接收超时判断”的模式来解析不定长数据帧这块逻辑在两种芯片上基本可以复用但中断注册函数的名字完全变了。// HC32F460 UART1中断接收示例 void UART1_IRQHandler(void) { uint8_t data; if(UART_GetStatus(UART1, UART_RX_BUFF_FULL) SET) { data UART_ReceiveData(UART1); // 读取数据清除标志 // 将数据放入环形缓冲区 ring_buffer_write(uart1_rx_buf, data); } } // 主循环中判断帧完成通过定时器超时或字节间隔超时华大HC32F460的UART接收中断标志位和STM32也有微妙的差别。STM32的RXNE标志表示数据寄存器非空HC32F460的UART_RX_BUFF_FULL含义类似但如果开启了FIFO模式标志位的行为会不同。我最终选择关闭UART的FIFO功能保持寄存器级别的兼容逻辑减少调试复杂度。4.4 SPI移植Flash和显示屏驱动的适配SPI在这个项目里主要驱动外部Flash芯片和一块小尺寸LCD屏。SPI总线协议本身是标准化的但芯片的SPI控制器配置有差异。HC32F460的SPI支持Moto和TI两种帧格式默认是Moto格式这点和STM32一致。但要注意的是HC32F460的SPI时钟极性和相位CPOL/CPHA配置是通过一个联合体完成的不同外设对时序的要求各不相同。以我当时用的LCD屏为例它要求SPI模式0CPOL0CPHA0而外部Flash芯片支持模式0和模式3。ST的HAL库配置模式0很容易而HC32F460的配置方式稍微绕一点需要设置SPI_ClockConfig结构体里的各项参数。// HC32F460 SPI配置示例 void SPI_Config(void) { stc_spi_cfg_t stcSpiCfg; stcSpiCfg.enWorkMode SPI_MODE_MASTER; // 主机模式 stcSpiCfg.enTransMode SPI_MODE_FULL_DUPLEX; // 全双工 stcSpiCfg.enDataWidth SPI_DATA_WIDTH_8BIT; // 8位数据 stcSpiCfg.enClkPolarity SPI_CLK_POL_LOW_IDLE; // CPOL0 stcSpiCfg.enClkPhase SPI_CLK_PHASE_SAMPLE_1EDGE; // CPHA0 stcSpiCfg.enBitOrder SPI_MSB_FIRST; stcSpiCfg.enSSPin SPI_SS_PIN_SOFTWARE; // 软件控制片选 SPI_Init(SPI1, stcSpiCfg); SPI_Enable(SPI1); }如果SPI通信数据出现“错位”或者“多了半个字节”的情况优先检查CPHA配置其次检查片选引脚的模式是不是推挽输出。很多工程师在移植时只关注数据线忽略了CS引脚在ST和华大之间的GPIO默认电平差异导致初始化时Flash被误选中然后通信全乱。4.5 I2C移植这个坑最深I2C移植是我在整个项目里花时间最多的部分。STM32F411的硬件I2C本身就以“难用”著称很多人宁可软件模拟I2C也不碰硬件I2C。到了HC32F460上硬件I2C的用法又不一样而且官方库的示例代码质量参差不齐。HC32F460的I2C控制器支持主机模式和从机模式有独立的时钟配置寄存器和中断标志。表面上看和STM32的I2C差不多但对时序的要求更严格。尤其是Fast Mode400kHz下如果上拉电阻选得不对华为的I2C会频繁产生NACK。我当时遇到的现象是传感器偶发性读取失败用逻辑分析仪看波形发现SCL的上升沿很缓信号质量差。换用2.2k上拉电阻后问题明显缓解。// HC32F460 I2C起始条件发送示例以写传感器寄存器为例 uint8_t I2C_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t data) { I2C_GenerateStart(I2C1); // 等待起始条件发送完成 while(I2C_GetStatus(I2C1, I2C_FLAG_START_DONE) RESET); // 发送设备地址写标志 I2C_SendData(I2C1, (dev_addr 1) | 0); while(I2C_GetStatus(I2C1, I2C_FLAG_TX_EMPTY) RESET); // 发送寄存器地址 I2C_SendData(I2C1, reg_addr); while(I2C_GetStatus(I2C1, I2C_FLAG_TX_EMPTY) RESET); // 发送数据 I2C_SendData(I2C1, data); while(I2C_GetStatus(I2C1, I2C_FLAG_TX_EMPTY) RESET); // 产生停止条件 I2C_GenerateStop(I2C1); return 1; }建议在项目初期就搭建一个I2C总线扫描工具函数把所有挂在I2C总线上的设备地址全部扫一遍确认每个设备都能正确应答。这个看似简单的工具在排查硬件连接问题时能省下大量时间。4.6 ADC和DMA移植从单次采样到连续采样ADC模块的移植也要单独说。HC32F460的ADC单元支持多通道扫描配合DMA可以做到无CPU干预的连续采样。但它的DMA请求映射方式、数据对齐方式都和STM32F411有区别。我最初把ST代码里的DMA配置直接搬过来改名字结果发现ADC数据完全不对。排查后发现是数据宽度的问题STM32F411的ADC是12位DMA传输时以Half Word16位对齐HC32F460在右对齐模式下DMA也可以传16位数据但需要额外设置数据左对齐还是右对齐以及是否使用带符号的数据格式。// HC32F460 ADC DMA 连续采样配置关键步骤 // 1. ADC配置为扫描模式使能ADC转换完成中断或DMA请求 // 2. DMA配置为循环模式Circular数据宽度Half Word // 3. DMA传输计数 ADC通道个数 * 采样次数 // 4. 启动ADC软件触发或定时器定时触发踩了一个更隐蔽的坑HC32F460的ADC在首次上电后需要一段稳定时间如果在初始化后立即读取转换结果可能会得到无效值。这个在ST芯片上不明显但在HC32F460上如果不加延时前几次转换结果基本不能用。4.7 PWM和电机控制移植电机控制依赖PWM输出HC32F460的定时器输出PWM和STM32的思路类似但寄存器命名和计数器位数不同。需要特别注意互补PWM的死区配置HC32F460的定时器死区时间计算方式和STM32不一样如果照搬ST的死区配置公式电机驱动器的上下桥臂会在切换时发生直通。安全操作建议是先把死区时间调到比较保守的值比如1us以上用示波器确认波形没有交叠再逐步缩小死区时间直到波形出现轻微交叠的临界点然后回调10%-20%留出安全余量。5. 中间件与系统架构的迁移策略5.1 从裸机到轻量级任务管理原STM32F411项目用的是裸机状态机移植到HC32F460后我利用更强的主频和更大的RAM把架构升级成了轻量级时间片轮询事件驱动模型没有直接上FreeRTOS但保留了一个非常简单的任务调度器。这个调度器其实就是用一个定时器产生固定节拍然后在主循环里按时间片轮询各任务。好处是调试简单、资源占用低、实时性可预期比直接裸奔好维护多了。// 简单的任务调度器示例 typedef struct { void (*task_func)(void); uint32_t period_ms; uint32_t last_run; } task_t; task_t tasks[] { {sensor_read_task, 10, 0}, {motor_control_task, 1, 0}, {comm_process_task, 5, 0}, {display_refresh_task, 50, 0}, }; void TaskScheduler_Run(void) { uint32_t now get_tick_ms(); for(int i 0; i TASK_NUM; i) { if(now - tasks[i].last_run tasks[i].period_ms) { tasks[i].task_func(); tasks[i].last_run now; } } }这种架构在HC32F460上跑起来非常流畅200MHz的主频使得即使任务数增加也能轻松满足时序要求。5.2 FreeRTOS移植的参考路径如果你的项目需要上FreeRTOSHC32F460的移植路径也基本成熟。官方的示例工程和网络上都有移植教程核心步骤不外乎准备FreeRTOS源码推荐V10.x版本在工程中添加portable目录下的ARM_CM4FCortex-M4F移植文件配置SysTick或定时器作为系统节拍实现vApplicationStackOverflowHook等钩子函数FreeRTOS移植到HC32F460有个注意点HC32F460的SysTick和ST的SysTick是一个核的东西但是中断向量表的名字和优先级分组方式有细微差别需要检查startup文件里的中断向量是否正确映射了SysTick_Handler。如果漏了这一步FreeRTOS会一直卡在启动第一个任务的地方。另外如果考虑跑LVGL做图形界面HC32F460的200MHz主频加1MB Flash完全可以支撑起一个简单的仪表盘界面。LVGL本身和芯片无关只要保证TICK和帧缓冲FrameBuffer的分配合理即可。5.3 固件升级Bootloader方案移植原项目里实现了基于YMODEM协议的串口固件升级功能这部分在HC32F460上也成功移植了。但需要重点注意的是Flash操作差异STM32F411的Flash扇区大小是16KB/32KB/64KB不等由低地址到高地址逐渐变大HC32F460的Flash扇区配置不同通常是8KB/56KB等分段方式扇区擦除粒度不同如果你的Bootloader里有按扇区擦除的逻辑一定要根据HC32F460的扇区映射表重新计算否则擦除时会误伤Bootloader自身区域。// HC32F460 Flash擦除示例以扇区为单位 void Flash_EraseSector(uint32_t sector_addr) { EFM_Unlock(); // 检查地址是否合法避免擦除到Bootloader区域 if(sector_addr APP_START_ADDR) { EFM_SectorErase(sector_addr); } EFM_Lock(); }固件升级还有一个隐含风险HC32F460在跳转到APP之前需要重新配置中断向量表的偏移地址这通过SCB-VTOR寄存器设置。但HC32F460的DDL库在启动阶段可能会覆盖VTOR值所以最好在跳转函数里重新写一次。6. 移植过程中遇到的经典Bug与排查实录6.1 随机进入HardFault的问题这个问题前面提到过这里展开详细说。现象是程序在上电后运行时间不定可能几分钟也可能几小时突然进入HardFault_Handler。排查过程第一步利用硬件调试器保存的故障现场读出LR寄存器和PC指针第二步在HardFault_Handler里把堆栈内容打印出来找到触发故障的函数地址第三步最终定位到Flash等待周期配置问题HC32F460在200MHz主频下Flash等待周期必须是2个周期我在初始化时钟时只配了1个周期导致Flash读取偶尔出错指令执行到非法地址触发HardFault。修复方式是加上了EFM_FlashWaitCycleSet(EFM_WAIT_CYCLE2)问题彻底消失。6.2 I2C总线死锁I2C总线死锁的经典场景是通信过程中某个从设备拉低了SDA主机检测不到总线空闲。这个问题在STM32上用硬件I2C也存在但HC32F460上更频发。排查发现两个原因第一设备复位过程中I2C线悬空需要给I2C配套一个空闲检测机制在死锁时切换GPIO方式产生9个时钟脉冲来解锁总线第二HC32F460的I2C在错误状态下不会自动释放总线需要在错误处理里调用I2C_DeInit和I2C_Init重新初始化// I2C 总线死锁恢复函数 void I2C_BusRecovery(void) { I2C_DeInit(I2C1); // 将SCL配置为普通GPIO输出 PORT_SetFunc(PORTB, PIN_08, Func_Port, DISABLE); // 模拟9个时钟脉冲 for(int i 0; i 9; i) { GPIO_Toggle(PORTB, PIN_08); delay_us(5); } // 重新初始化I2C I2C_Init(I2C1, stcI2cCfg); }用逻辑分析仪确认SDA线最终回到了高电平再重新发起通信问题就解决了。6.3 UART接收数据错位串口接收数据错位通常和波特率误差有关。HC32F460的UART波特率发生器和STM32不一样如果照搬ST库的波特率配置参数会产生比较大的误差。解决方法是参考芯片手册里的波特率计算公式手动算出分频系数和BRR值。300MHz的PCLK下115200波特率对应的分频值要用整数运算精确计算必要时用示波器测量实际波形对比理论值。6.4 低功耗模式下无法唤醒项目后期增加了低功耗需求发现HC32F460进入低功耗模式后无法通过UART唤醒。排查后确认是UART的异步唤醒功能没有使能。HC32F460的UART在低功耗模式下需要配置为“边沿唤醒”或“地址匹配唤醒”模式只靠普通接收中断是不够的。另外进入低功耗前要把不用的GPIO全部配置为模拟输入或高阻态否则漏电流会比较大。还可以进一步测量各部分电流定位异常耗电的模块。7. 移植后的性能验证与稳定性测试7.1 老生常谈的“跑分”与真实负载测试移植完成后不能直接宣布完工。我在HC32F460上跑了一遍CoreMark分数比STM32F411高了不少但真正有效的是整机压力测试。测试内容包括连续72小时运行观察有无死机或逻辑故障传感器采集和电机控制在最高负载下连续工作用示波器监测关键信号边沿是否满足要求串口长时间大量数据传输统计误码率I2C总线连续读写一小时统计重试次数异常断电和重新上电测试验证Flash数据和配置的可靠性这些测试中往往能暴露一些隐藏问题比如DMA缓冲区越界、中断优先级配置不合理导致的响应延迟、任务调度器里某个任务的执行时间超出周期导致任务堆积等。7.2 中断优先级配置的坑HC32F460和STM32F411的中断优先级分组虽然都是Cortex-M4F标准但不同外设的中断优先级默认值不同。在没有统一规划优先级的情况下DMA传输中断和UART接收中断互相抢占会导致数据丢失或错乱。建议在初始化时统一设置NVIC分组方式并为每个中断明确分配优先级中断源优先级说明系统定时器最高0任务调度基准UART接收高1保证通信不丢字节DMA传输完成中2数据传输可靠定时器PWM更新中3电机控制节拍ADC转换完成低4允许延迟处理按键外部中断高1人机交互及时响应7.3 老芯片新芯片的功耗对比HC32F460在运行模式下的功耗略高于STM32F411但在低功耗模式下两者差距不大。如果项目对功耗敏感需要注意HC32F460的外设时钟门控比ST做得更细每个外设的时钟使能/失能是独立的需要在外设初始化后自行关闭不需要的时钟。用实际测量数据看HC32F460在200MHz全速运行时的电流大约是几十毫安级别而在睡眠模式下的电流可以降到微安级别完全满足电池供电的物联网设备需求。8. 关于移植这件事的一些心得收尾整个移植项目从评估到量产我自己的感受是芯片移植与其说是技术问题不如说是工程管理问题。技术层面的坑几乎所有都能在手册和官方例程里找到答案难的是你不知道它在哪里等你。工程管理层面的坑才是决定项目成败的关键。选型时有没有留够评估时间团队里有没有人能把两种芯片的差异摸透文档和代码注释是否及时更新这些都会直接影响移植质量。我的最后一个建议是移植完成后一定要把移植过程中修改过的配置项、踩过的坑、借鉴过的官方代码整理成一份团队的内部文档。这份文档在后续维护、升级、甚至下一个项目移植时价值比代码本身还大。如果你也在做类似的国产芯片替代记住一句话不要把“移植”做成了“重写”也不要觉得“能用就行”。用系统的方法梳理差异用足够的耐心处理细节这个坎没有那么难迈。
返回列表