
1. 项目概述当RL78/G23遇上蓝牙低功耗FOTA在物联网设备开发中最让人头疼的场景之一莫过于产品已经部署到成千上万的现场却发现了一个需要紧急修复的软件缺陷或者需要增加一个能带来新收入的功能。传统的召回或现场升级方案成本高昂几乎不可行。这时固件空中升级技术就成了救命稻草。FOTA不仅仅是“无线更新”这么简单它是一套融合了嵌入式系统、无线通信、密码学和固件管理的系统工程。其核心价值在于它让设备具备了“进化”的能力能够在整个生命周期内持续改进是产品从“一锤子买卖”转向“持续服务”的关键技术支撑。本次分享的项目基于瑞萨电子的RL78/G23系列微控制器和Dialog Semiconductor的DA14535/DA14531蓝牙低功耗模块实现了一套完整的FOTA解决方案。RL78/G23以其超低功耗和丰富的外设在电池供电的物联网终端中应用广泛而DA1453x则是业界知名的超低功耗蓝牙SoC。将两者结合利用蓝牙作为无线传输通道通过SUOTA服务协议进行固件升级是一个在消费电子、智能家居、工业传感器等领域非常典型的应用架构。这个方案的精髓不在于单个器件的使用而在于如何让MCU和蓝牙模块协同工作构建一个安全、可靠且对用户透明的升级流程。接下来我将拆解整个实现过程从硬件连接到软件架构再到每一步的实操细节和踩过的坑为你呈现一个可以直接复现的参考设计。2. 核心硬件平台与设计思路拆解2.1 为什么选择RL78/G23 DA1453x组合在启动一个FOTA项目前硬件选型是基石。我们选择RL78/G23作为主控MCU主要基于以下几点考量首先是极致的低功耗特性这对于常年靠电池或能量收集供电的物联网节点至关重要其次是其内置的Flash存储器支持自编程操作这是实现FOTA中“固件写入”功能的前提最后RL78/G23提供了UART、I2C、SPI等丰富的通信接口便于与各种无线模块连接。而选择Dialog的DA14535或DA14531蓝牙模块则是因为它们在单芯片上集成了蓝牙射频、ARM Cortex-M0内核和Flash功耗极低且Dialog提供了成熟的SUOTA协议栈大大降低了开发蓝牙FOTA功能的门槛。这个组合构成了一个典型的“主从”或“主机-协处理器”架构。RL78/G23作为主机负责核心业务逻辑、外设控制和最终的固件更新管理DA1453x作为蓝牙协处理器专门处理复杂的蓝牙协议栈并通过一个简单的串口指令集与主机通信。这种架构的优势在于职责分离MCU无需集成蓝牙协议栈节省了宝贵的Flash和RAM资源也降低了软件复杂性蓝牙模块则专注于其擅长的无线连接和数据传输。FOTA的数据流可以简单理解为手机App客户端通过蓝牙连接DA1453xDA1453x通过UART将接收到的固件数据包转发给RL78/G23最后由RL78/G23的Bootloader将新固件安全地写入自身的Flash中。2.2 硬件连接详解两线制与一线制的抉择硬件连接是项目成功的第一步也是最容易出错的地方。根据官方文档我们需要将DA1453x模块连接到RL78/G23-128p快速原型板的PMOD1接口上。这里有一个关键细节DA14535和DA14531的“Boot from Host”模式配置不同这直接影响了硬件连线。对于DA14535情况相对简单。它支持2-Wire UART模式这意味着我们需要使用标准的UART TX、RX两根线进行通信。连接时将DA14535模块的UTX引脚连接到RL78/G23的P143/RXD3URX引脚连接到P144/TXD3。此外还需要连接RST和UCTS引脚以实现硬件流控制和复位。具体连接如下表所示RL78/G23 FPB 引脚方向DA14535 模块引脚功能P143/RXD3输入UTX接收来自蓝牙模块的数据P144/TXD3输出URX向蓝牙模块发送数据P00输出RST复位蓝牙模块P142/SCK30输出UCTS蓝牙模块的UART清除发送流控制注意务必确保DA14535模块上的SW2开关设置为OFF以启用2-Wire UART模式。如果设置错误模块将无法正确进入主机引导模式。对于DA14531情况则复杂一些。它默认或在此应用场景下需配置为1-Wire UART模式。这种模式下数据发送和接收共用一根线因此无法直接连接到PMOD1的双线UART接口。你需要使用杜邦线进行飞线连接并且必须在RX/TX线上串联一个1kΩ的电阻。这个电阻的作用是防止信号冲突确保在单线双向通信时的信号完整性。连接方式如下将DA14531的UTX和URX引脚用一根线短接作为共用的数据线。在这根共用数据线和RL78/G23的P143/RXD3输入之间串联一个1kΩ电阻。同样在这根共用数据线和RL78/G23的P144/TXD3输出之间也串联一个1kΩ电阻。连接RST和UCTS引脚的方式与DA14535相同。这个硬件上的差异是第一个容易踩坑的地方。我曾因为忽略了这颗1kΩ电阻导致DA14531通信极其不稳定数据错乱排查了很久才定位到问题。所以在焊接或连接时请务必对照图纸确认。2.3 调试与日志输出连接为了方便调试和观察程序运行状态我们还需要连接一个USB-UART转换板到RL78/G23的UART2接口J8。这样MCU的调试打印信息就可以通过串口输出到PC上的终端软件如Tera Term。连接方式是将转换板的TXD连接到RL78/G23的P14/RXD2RXD连接到P13/TXD2。同时将转换板的JP1跳线帽设置为LCL-VCC使其从USB总线取电。最后用一根Micro USB线连接开发板的J12到PC为整个系统供电并用于调试器连接。3. 软件开发环境与关键工具链配置3.1 核心工具链安装与避坑指南工欲善其事必先利其器。这个项目涉及瑞萨和Dialog两套生态的工具安装和配置需要一些耐心。1. 集成开发环境与编译器项目使用的是瑞萨的e² studio版本为2025-10。这是一个基于Eclipse的IDE对RL78系列支持良好。编译器配套使用的是Renesas C Compiler for RL78 Family V1.15.01。安装过程比较常规但有一个关键编译器选项必须在项目属性中手动添加-langc99。这个选项告诉编译器使用C99标准否则项目中一些特定的语法可能无法通过编译。我建议在创建项目后第一时间在项目属性 - C/C Build - Settings - Tool Settings - Runtime Options中添加此选项。2. Python环境与加密库Python脚本在本项目中扮演了“固件打包匠”的角色。它负责将编译生成的二进制文件与加密密钥一起打包成Bootloader可识别的初始固件镜像或更新镜像。需要安装Python 3.12.7并在安装时务必勾选“Add python.exe to PATH”这样才能在命令行全局调用。安装完成后还需要安装一个关键的加密库pycryptodome。在命令行中执行pip install pycryptodome即可。如果遇到网络问题可以使用国内镜像源例如pip install pycryptodome -i https://pypi.tuna.tsinghua.edu.cn/simple。3. OpenSSL生成安全升级的钥匙FOTA的安全基石是数字签名。我们使用OpenSSL来生成一对非对称加密密钥私钥用于在PC端对固件进行签名公钥则被编译进MCU的Bootloader中用于验证接收到的固件镜像是否合法、未被篡改。这里使用的是Win64 OpenSSL v3.0.12。安装后不要使用系统自带的命令提示符而要从开始菜单找到“OpenSSL Win64”相关的命令提示符快捷方式并打开。在这个特殊的环境里openssl命令才是可用的。执行文中提到的三条命令来生成密钥对openssl ecparam -genkey -name secp256r1 -out secp256r1.keypair openssl ec -in secp256r1.keypair -outform PEM -out secp256r1.privatekey openssl ec -in secp256r1.keypair -outform PEM -pubout -out secp256r1.publickey生成的secp256r1.privatekey和secp256r1.publickey文件需要妥善保管尤其是私钥绝不能泄露。4. 瑞萨镜像生成器这是瑞萨提供的专用工具包含在“Firmware Update Module”样例代码包中。你需要从瑞萨官网下载这个模块解压后找到RenesasImageGenerator文件夹。里面的image-gen.py脚本就是核心它需要配合设备特定的参数文件如RL78G23_ImageGenerator_PRM.csv来工作。这个工具的作用是将普通的.mot或.hex文件按照Bootloader要求的格式进行重组、添加头信息和签名最终生成.mot初始镜像或.rsu更新镜像文件。5. 其他辅助工具Renesas Flash Programmer用于通过调试器接口如EZ-CUBE将初始固件烧录到MCU的Flash中。这是第一次烧录Bootloader和初始应用程序时必须的。Tera Term一个轻量级的串口终端软件用于查看来自UART2的调试日志是排查问题的重要窗口。SUOTA Mobile AppDialog提供的安卓手机应用用于发现设备、连接并推送更新固件。可以从Google Play商店下载。3.2 软件项目结构解析解压样例程序包后你会发现针对DA14535和DA14531有两个独立的文件夹但其内部结构是完全平行的。以da14535/ccrl_iar路径为例核心是三个e² studio工程boot_loader引导加载程序工程。这是整个FOTA系统的“守门人”。它常驻在Flash的起始地址设备上电后首先运行。它的职责包括验证应用程序区的固件签名是否有效。如果验证通过则跳转到应用程序执行。如果检测到缓冲区有新的、已验证的更新镜像则将其复制到应用程序区然后跳转执行。提供固件更新模块的底层驱动接口。fwup_main主应用程序工程。这是设备正常运行时执行的用户程序。它包含了蓝牙通信逻辑、业务功能以及最重要的SUOTA服务处理程序。这个程序通过UART与DA1453x模块交互接收来自手机的固件数据块并将其通过Firmware Update Module的API写入Flash的缓冲区。fwup_leddemo更新演示应用程序工程。这个工程编译后会生成一个与fwup_main功能略有差异的固件例如改变LED闪烁模式。我们将用它来生成.rsu更新文件用于测试FOTA流程是否成功。成功升级后设备的行为应该会改变。这三个工程通过一个预定义的内存映射表紧密协作。在“线性模式部分更新方法”下RL78/G23的Flash被划分为几个区域Bootloader区存放boot_loader工程代码。主程序区存放当前运行的应用程序fwup_main。缓冲区用于临时存放从手机接收到的、待更新的新固件镜像fwup_leddemo。Firmware Update Module区存放固件更新所需的底层驱动库。这种布局确保了在更新过程中即使断电原有的主程序依然完好只有缓冲区可能损坏下次可以从头开始传输提高了系统的鲁棒性。4. 固件更新流程深度剖析与实操4.1 密钥生成与初始固件构建安全是FOTA的生命线。我们的流程从生成密钥对开始这已经在工具链配置部分完成。接下来我们需要将公钥集成到Bootloader中。导入公钥到Bootloader工程打开boot_loader工程你需要找到用于存储公钥的源文件或头文件通常在r_fwup模块的配置中。将secp256r1.publickey文件中的公钥内容一段十六进制数组复制到工程指定的位置。务必确保格式正确通常需要去掉PEM格式的头尾标记-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----并将内容转换为C语言数组格式。编译boot_loader工程生成boot_loader.mot文件。编译主应用程序编译fwup_main工程生成fwup_main.mot文件。这个文件包含了你的业务逻辑和SUOTA服务。使用镜像生成器打包这是最关键的一步。我们需要使用Python脚本image-gen.py将Bootloader和主应用程序打包成一个初始固件镜像。命令大致如下python image-gen.py -i boot_loader.mot -a fwup_main.mot -prm RL78G23_ImageGenerator_PRM.csv -k secp256r1.privatekey -o initial_firmware.mot-i: 输入Bootloader镜像。-a: 输入应用程序镜像。-prm: 指定RL78/G23的参数文件其中定义了内存布局。-k: 指定私钥文件用于对整合后的镜像进行签名。-o: 输出的初始固件文件。这个脚本会执行以下操作将两个.mot文件按内存布局拼接计算整个镜像的哈希值使用私钥对哈希值进行签名将签名和公钥信息可选添加到镜像的特定头部位。最终生成的initial_firmware.mot就是一个包含了完整启动链的、已签名的固件包。烧录初始固件使用Renesas Flash Programmer通过调试器将initial_firmware.mot文件烧录到RL78/G23开发板的Flash中。烧录完成后复位设备你应该能通过Tera Term看到应用程序的启动日志并且蓝牙模块开始广播。4.2 更新固件准备与SUOTA过程全解析当我们需要发布一个新版本固件时流程如下编译更新应用程序修改fwup_leddemo工程例如改变LED闪烁频率然后编译生成fwup_leddemo.mot。生成更新镜像同样使用镜像生成器但这次模式不同。我们只对新的应用程序进行签名打包生成.rsu格式的更新文件。python image-gen.py -u fwup_leddemo.mot -prm RL78G23_ImageGenerator_PRM.csv -k secp256r1.privatekey -o update_firmware.rsu-u参数指定这是用于更新的应用程序镜像。输出的.rsu文件就是我们将要通过手机APP推送的文件。SUOTA移动端操作流程手机打开SUOTA App扫描并找到你的设备名称通常在fwup_main工程中配置。连接设备后App会自动读取设备的DIS服务信息如制造商、硬件版本、固件版本等。在App中选择准备好的update_firmware.rsu文件。点击开始更新。此时背后发生了一系列复杂的GATT通信SUOTA协议交互深度解析连接与发现手机连接后首先读取DIS服务信息用于UI展示和版本比对。会话启动手机向SUOTA服务的MEM_DEV特征写入SUOTAR_IMG_SPI_FLASH命令启动更新会话。设备收到后会初始化内部状态和缓冲区并回复SUOTAR_IMG_STARTED状态。参数协商手机读取PATCH_DATA_CHAR_SIZE和MTU特征确定每次能发送的最大数据块长度。然后写入PATCH_LEN特征设定一个“块大小”。例如设为500意味着设备每接收完500字节数据会向手机回复一个确认然后再接收下一块。这是一种流量控制机制防止手机发送过快导致设备缓冲区溢出。数据传输手机开始向PATCH_DATA特征写入固件数据。设备端fwup_main程序在BLE_SUOTA_SVCS_EVENT_PATCH_DATA_CTRL_WRITE_REQ事件中处理这些数据将数据块存入缓存累积到一个PATCH_LEN指定的大小后计算该块的CRC校验和然后调用Firmware Update Module的API将数据块写入Flash的缓冲区。写入成功后通过SUOTA_STATUS特征通知手机SUOTAR_CMP_OK手机则继续发送下一块。传输结束与验证整个.rsu文件发送完毕后手机向MEM_DEV特征写入SUOTAR_IMG_END命令。设备收到后会对缓冲区中完整的更新镜像计算全局CRC并与.rsu文件头中携带的CRC值进行比对。如果一致则回复SUOTAR_CMP_OK否则回复SUOTAR_CRC_ERR更新失败。重启与应用更新最后手机发送SUOTAR_REBOOT命令。设备收到后主应用程序会设置一个标志然后主动重启。重启后Bootloader开始工作它检查缓冲区是否存在一个已验证CRC正确的新镜像。如果存在则将其复制到主程序区覆盖旧的应用程序。复制完成后跳转到新的主程序区开始执行。至此FOTA全过程完成。关键心得在整个传输过程中fwup_main应用程序一直在运行。它负责接收数据并写入缓冲区。只有最后重启后Bootloader才执行“翻转”操作。这种设计保证了更新过程意外中断时如断电设备至少还能用旧版本启动具备了回滚能力。5. 关键代码实现与配置详解5.1 智能配置器关键设置在e² studio中使用Smart Configurator进行外设图形化配置能节省大量时间。针对本项目有几个关键配置点时钟配置主系统时钟和外围硬件时钟均设置为32MHz。确保系统时钟稳定这是UART通信波特率准确的基础。UART配置需要配置两个UART通道。UART2用于与USB-UART转换板通信输出调试日志。波特率设为115200时钟源fCLK/2。UART3用于与DA1453x蓝牙模块通信。波特率同样为115200时钟源fCLK/2。这里需要特别注意根据连接的模块是DA14535还是DA14531需要在r_ble_da1453x组件的配置中选择对应的“Boot from Host”模式2-Wire或1-Wire。引脚配置在Config_PORT中需要将P00、P142、P143、P144、P13、P14等引脚的功能正确配置为输出或输入并与UART功能映射。具体映射关系如前文硬件连接表所示。BSP配置使能R_BSP_SoftwareDelay函数后续代码中可能会用到微秒级延时。5.2 SUOTA服务回调函数剖析在fwup_main工程中处理蓝牙事件的核心是event_dis_cb回调函数。当手机APP进行各种读写操作时BLE协议栈会触发相应的事件并在此回调中处理。处理DIS服务读取请求当手机连接后查询设备信息时会触发如BLE_DIS_EVENT_MFR_NAME_READ_REQ等事件。我们需要在这些事件中调用app_read_cfm()函数返回在QE for BLE工具或代码中预设的字符串如制造商名称、硬件版本号等。这些信息对于手机APP识别设备型号和当前固件版本至关重要。处理SUOTA控制命令这是FOTA逻辑的核心。BLE_SUOTA_SVCS_EVENT_MEM_DEV_CTRL_WRITE_REQ处理手机发送的SUOTAR_IMG_SPI_FLASH等命令。收到SUOTAR_IMG_END时需要触发对缓冲区完整镜像的CRC校验。收到SUOTAR_REBOOT时应设置重启标志并调用系统重启函数。BLE_SUOTA_SVCS_EVENT_PATCH_LEN_CTRL_WRITE_REQ接收手机设定的数据块大小。这里需要做有效性检查比如不能为0也不能超过内部缓冲区大小(SUOTA_MAX_BLOCK_SIZE)。BLE_SUOTA_SVCS_EVENT_PATCH_DATA_CTRL_WRITE_REQ这是数据写入事件。代码需要将接收到的数据追加到缓存区并维护一个接收计数器。当累积数据达到PATCH_LEN指定的大小时需要计算该数据块的CRC。调用R_FWUP_Write()函数将数据块写入Flash缓冲区。这个函数是Firmware Update Module提供的它负责处理Flash擦除和编程的底层细节。如果写入成功通过app_write_cfm()或SUOTA_STATUS特征通知手机成功并重置块内计数器准备接收下一块。如果写入失败Flash操作错误、CRC错误等需要发送错误状态通知并可能中止整个更新流程。5.3 固件更新模块API调用Firmware Update Module是瑞萨提供的中间件它封装了Flash擦写、镜像验证、复制等复杂操作。在Bootloader和应用程序中都需要调用它。在Bootloader中R_FWUP_Init()初始化模块传入公钥等信息。R_FWUP_VerifyApplication()验证主程序区应用程序的签名。R_FWUP_CheckUpdate()检查缓冲区是否有待更新的有效镜像。R_FWUP_ExecuteUpdate()执行更新将缓冲区镜像复制到主程序区。在应用程序中R_FWUP_Open()以“用户模式”打开更新模块准备写入缓冲区。R_FWUP_Write()将接收到的数据块写入缓冲区的指定地址。需要自己管理写入的偏移地址。R_FWUP_Close()完成写入后关闭模块。注意事项Flash写入操作耗时较长毫秒级且在此期间必须禁止中断。R_FWUP_Write函数内部可能会处理这些但你在设计数据接收流程时需要确保在写入Flash期间蓝牙栈或其它中断不会导致数据丢失或系统异常。一种常见的做法是使用双缓冲区一个缓冲区用于接收下一块数据另一个缓冲区用于写入Flash。6. 实战调试与常见问题排查实录6.1 硬件连接与电源问题问题现象设备无法启动或蓝牙模块不广播串口无任何输出。排查步骤检查供电首先用万用表测量RL78/G23板和DA1453x模块的供电电压是否为稳定的3.3V。蓝牙模块对电源纹波比较敏感电压不稳会导致无法启动。检查串口连接确认TXD/RX交叉连接是否正确。一个快速验证方法是将USB-UART转换板的TX和RX短接在Tera Term中输入字符看是否能回显。如果可以说明转换板和PC端设置正常。检查DA1453x模式确认DA14535模块上的SW2开关位置是否正确2-Wire模式应为OFF。对于DA14531确认1kΩ电阻已正确串联在数据线上。检查复位信号示波器或逻辑分析仪查看P00引脚在设备上电或软件复位时是否有正确的复位脉冲输出到DA1453x的RST引脚。6.2 编译与链接错误问题现象工程编译失败提示链接错误例如找不到R_FWUP_xxx等函数或者内存区域溢出。排查步骤确认组件添加在Smart Configurator中确保已正确添加并配置了r_fwup固件更新模块和r_ble_da1453x蓝牙驱动模块组件。检查链接脚本Bootloader和应用程序工程使用不同的链接脚本.lsl文件它们定义了各自的内存区域。务必确保boot_loader工程的链接脚本将其代码定位在Flash起始地址如0x0000而fwup_main工程定位在偏移地址如0x4000。内存区域定义错误是导致链接失败或运行时崩溃的常见原因。检查编译器选项确认已在项目属性中添加了-langc99选项。6.3 蓝牙连接与SUOTA服务发现失败问题现象手机APP能扫描到设备但连接后无法发现SUOTA服务或者连接立即断开。排查步骤查看调试日志通过Tera Term查看UART2输出的日志。正常启动后程序应打印初始化成功信息并进入蓝牙广播状态。连接事件也会有相应打印。检查GATT数据库在fwup_main工程的代码中确认SUOTA服务和DIS服务的UUID、特征值是否正确添加到了GATT数据库。可以使用R_BLE_GATTS_AddService()等函数调用的返回值来判断服务添加是否成功。确认蓝牙模块固件确保DA1453x模块内运行的蓝牙固件是支持SUOTA功能的版本。有时需要先使用Dialog的SmartBond Flash Programmer工具更新模块本身的固件。6.4 固件传输中断或CRC校验失败问题现象手机APP传输固件到一半中断或最后报告CRC错误。排查步骤优化传输环境蓝牙传输易受环境干扰。确保手机和设备距离较近1米内避开Wi-Fi路由器等强干扰源。调整PATCH_LEN在手机APP或设备端代码中尝试减小PATCH_LEN块大小例如从500改为200。较小的块意味着更频繁的确认虽然总吞吐量可能下降但抗干扰能力更强。检查Flash驱动在R_FWUP_Write()函数调用前后添加详细日志打印写入的地址、数据和状态返回值。确保每次写入都成功。Flash写入前必须先擦除检查擦除操作是否成功。验证.rsu文件在PC端可以使用镜像生成器脚本的验证模式对生成的update_firmware.rsu文件进行离线CRC校验确认文件本身在生成过程中未损坏。缓冲区溢出检查在设备端代码中严格检查每次写入Flash的地址偏移量确保没有超出为缓冲区预留的Flash空间范围。超出会导致写入到其他程序区域引发致命错误。6.5 更新后设备“变砖”问题现象FOTA过程看似成功设备重启后无反应串口无输出仿佛“变砖”。排查步骤与挽救措施Bootloader存活是关键只要Bootloader区域没有被破坏设备就可以挽救。确保Bootloader工程编译后的大小严格限制在分配区域内且更新镜像的缓冲区区域与Bootloader区域无重叠。使用调试器连接通过e² studio和调试器如EZ-CUBE重新连接设备。如果Bootloader还在你通常可以在上电时暂停CPU查看PC指针是否停在Bootloader的起始地址。强制进入Bootloader模式在设计时可以预留一个硬件引脚如某个按键。当该引脚在上电时被拉低则强制进入Bootloader模式而不跳转到可能已损坏的主应用程序。在Bootloader中可以提供一个通过UART接收新固件的“急救”模式。重新烧录最直接的方法使用Renesas Flash Programmer通过调试接口重新烧录完整的initial_firmware.mot。这能覆盖整个Flash恢复设备。6.6 功耗优化考量在电池供电场景下FOTA过程的功耗需要关注。整个传输过程可能持续数十秒蓝牙和Flash擦写都是耗电大户。传输阶段DA1453x和RL78/G23都处于活跃状态。可以尝试在代码层面当蓝牙处于连接空闲非数据传输时让MCU进入合适的低功耗模式。Flash写入阶段R_FWUP_Write期间功耗较高。应避免在电池电量极低时触发更新或者在设计上由主应用程序先检测电池电压电压过低则拒绝更新请求。广播阶段在等待连接的广播阶段可以配置蓝牙模块使用更长的广播间隔来降低功耗。实现一个稳定可靠的FOTA功能是一个系统工程涉及硬件、底层驱动、通信协议和应用逻辑多个层面。本文基于瑞萨的RL78/G23和Dialog DA1453x方案提供了一个经过验证的实现路径。其中最大的体会是安全性、鲁棒性和用户体验必须贯穿设计始终。从密钥管理、传输校验到异常恢复每一个环节的疏忽都可能导致现场设备“失联”。希望这份详细的拆解和实录能帮助你在自己的物联网产品中成功部署这颗“远程修复与升级”的心脏。