RT-Thread论坛
直播中

zhongnian

9年用户 1453经验值
擅长:MEMS/传感技术
私信 关注
[问答]

请问OTA是否一定依赖于ymodem协议?

1,目前使用通用bootloader是可以成功实现的。
2,ymodem既然是个传输协议,那么是不是说只需要将打包好的固件放入“downloader”里面就能更新?目前尝试过但没有成功,不知道是不是缺少什么步骤,通过对比发送的固件内容(日志打印)与“downloader”内容一致。
3,现在的需求是通过串口2,接收上位机发送过来的固件包更新。不依赖于ymodem等任何协议。不知这种想法是否成立。


回帖(2)

李泓翔

2025-9-17 17:03:02
ymodem协议自然不是唯一选择,至少还有别的协议,例如 zmodem。如果自己设计传输协议的话,最好还是不要直接简单发送文件,至少要有一定的校验机制,避免传输出错导致写入的固件不对。

那么是不是说只需要将打包好的固件放入“downloader”里面就能更新?
这个是由 bootloader 的设计决定的。                        
举报

醉清歌

2025-9-23 16:58:27

你的思路完全正确!OTA 并不依赖于 YMODEM 或者其他任何特定的传输协议。 YMODEM 只是一种在特定场景(如串口)下广泛使用的、可靠的文件传输协议,它被许多 Bootloader 采纳是因为它提供了校验、重传和文件信息等实用功能。


分析你的情况和问题:




  1. 通用 Bootloader 成功实现 OTA: 这证明了核心功能(接收新固件、擦写 Flash、验证、跳转)是没问题的。关键点在于 Bootloader 如何接收这个新固件。




  2. 固件内容一致但更新失败: 这正是问题的核心。仅仅将固件二进制数据写入 download 区域(我理解是你 Bootloader 预留的用于存放新固件的 Flash 区域)通常是不够的。失败的原因几乎肯定在于 Bootloader 启动时的决策逻辑



    • 缺少“更新请求”标志: Bootloader 在重启后,第一件事就是检查某个特定位置(通常在 Flash 的固定地址、RTC Backup Register、备份 SRAM 或特定 Flash 页等非易失性存储区域)是否有被设置的特殊标志(例如 0xA5A5A5A5)。这个标志告诉 Bootloader:“download 区域有新固件,请验证并更新”。如果你只是把数据写进去,但没有设置这个标志,Bootloader 会直接跳过更新流程,尝试启动旧的主程序。

    • 缺少必要的元数据: 即使 Bootloader 检查了更新标志,它通常还需要知道:

      • 固件起始地址: 新固件在 download 区域的哪个位置开始?

      • 固件大小: 新固件有多大?需要校验多少字节?

      • 固件 CRC/哈希值: Bootloader 需要用这个值来验证 download 区域的数据是否传输完整且没有损坏。

      • 固件版本号(可选但推荐): 用于防止回滚或记录。


    • 元数据存储位置: 这些元数据通常也存储在非易失性存储中,紧跟在更新标志之后,或者与更新标志存放在同一结构体/页面上。Bootloader 需要通过这个元数据才能正确地找到、验证和复制固件。

    • 写入位置错误: 确保上位机写数据的起始地址确实是 Bootloader 期望的 download 区域的起始地址。偏移了哪怕一个字节,Bootloader 找到的数据就不对。

    • 验证失败: 即使设置了标志,Bootloader 计算下载区域的 CRC/Hash 与元数据中存储的值不匹配,更新也会中止(防止损坏的固件启动)。确保上位机在写入数据后,计算出的校验值能被正确地写入元数据区域。

    • 内存布局/中断向量表问题(在复制后): Bootloader 把新固件复制到主程序区后,新的主程序的初始化和中断向量表设置是否正确?特别是如果主程序区地址与下载区地址不同。

    • 看门狗复位: 接收过程耗时较长,如果启用了看门狗且没有及时喂狗,会导致复位。

    • Cache 一致性(如果使能了 Cache): 在写入 Flash 后,如果 CPU 有 Cache,需要确保 Cache 被正确刷新或无效化,Bootloader 才能读取到刚写入的最新数据。




  3. 通过串口2直接接收更新(无 YMODEM): 这种想法完全成立,并且是更底层、更灵活的方式。 你需要实现的是:



    • 一个简单的自定义协议: 这个协议的核心是可靠地传输固件二进制数据块。它不需要像 YMODEM 那么复杂,但至少需要有:

      • 帧结构: 起始标志 + 地址 + 数据长度 + 数据 + 校验(如 CRC16/CRC32) + 结束标志。例如:...

      • 数据分块: 将大固件分成小块传输(如 128/256/512/1024 字节一块),降低单次传输错误的影响,方便重传。

      • 差错控制:

        • 校验: 每块数据必须有强校验(CRC32 推荐)。

        • 超时: 接收一块数据等待超时。

        • 确认/重传(ACK/NAK): 最简单的流程:Bootloader 接收完一块 -> 校验 -> 校验通过发送 ACK -> 上位机发下一块;校验失败或超时发送 NAK -> 上位机重发当前块。


      • 握手与流程控制: 起始握手(例如 Bootloader 发送 'C' 等待固件)、传输结束确认。


    • Bootloader 端的接收处理:

      • 初始化串口2。

      • 接收上位机的握手信号或指令,进入固件接收模式。

      • 按照自定义协议接收数据块。

      • 对接收到的每块数据进行校验。

      • 校验通过,将数据写入 download 区域的正确地址

      • 发送 ACK 请求下一块;校验失败或超时,发送 NAK 请求重发当前块。

      • 接收完成后(接收到结束帧且所有块校验通过):

        • 计算整个固件的校验值(可选但推荐)。

        • 写入元数据:

          • 设置“更新请求”标志 (0xA5A5A5A5)。

          • 写入固件起始地址(在 download 区内)。

          • 写入固件大小。

          • 写入固件整体 CRC/Hash 值。

          • (可选) 写入固件版本号。


        • 通知上位机更新完成,并执行软复位(或等待用户复位)。



    • Bootloader 启动流程(加电/复位后):

      • 检查“更新请求”标志是否被设置。

      • 如果设置,读取元数据(大小、校验值)。

      • 根据元数据中的地址和大小,计算 download 区域中固件的校验值。

      • 比较计算值与存储值:

        • 匹配:将固件从 download 区复制到主程序区(应用起始地址)。

        • 不匹配:清除更新标志(可选),尝试启动旧程序或进入错误状态。


      • 清除“更新请求”标志(防止下次启动重复更新)。

      • 跳转到主程序起始地址执行。





总结与建议:



  1. 思路正确: 不依赖 YMODEM,通过串口2自定义协议实现 OTA 是完全可行且常见的做法。

  2. 失败原因诊断: 你之前失败的核心原因极有可能是 没有正确设置“更新请求”标志和必要的元数据(大小、校验值),导致 Bootloader 在启动时不知道有新固件存在,或者知道存在但无法验证。

  3. 下一步行动:

    • 仔细研究你的 Bootloader 源码: 找到它是如何判断是否需要更新(检查哪个地址的标志?)。找到它更新时从哪里获取固件信息(大小、校验值、起始地址)。通常这些逻辑在 main() 函数最开始或 check_for_update() 之类的函数里。

    • 设计并实现简单的自定义协议:

      • 定义帧结构(起始、地址、长度、数据、校验、结束)。

      • 实现分块传输(块大小如 512 Bytes)。

      • 实现 CRC32 校验(推荐)。

      • 实现 ACK/NAK 机制。


    • 修改 Bootloader 接收端:

      • 添加通过串口2接收固件的模式。

      • 实现协议解析、校验、写入 download 区。

      • 关键:接收完成后,务必在非易失性存储中设置“更新请求”标志,并写入固件大小和 CRC 等必要元数据。


    • 修改上位机程序:

      • 按照自定义协议将固件文件分块打包发送。

      • 处理 ACK/NAK 进行重传。


    • 调试:

      • 使用调试器或串口日志,在 Bootloader 启动时打印它检查标志、元数据和校验的结果。

      • 仔细比对上位机发送的数据和最终写入 download 区的数据(不仅是内容,还包括写入的起始地址和大小)。

      • 确保元数据被正确地写入 Bootloader 期望的位置。




核心要点:Bootloader 需要在重启后“知道”两件事:(1) 是否需要更新? (2) 如果需要更新,新固件在哪(地址)?它有多大?如何验证它是否完整正确(校验值)? 你之前缺少的就是让 Bootloader “知道”需要更新以及如何验证的信息(标志和元数据)。解决这个问题,你的方案就能成功。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分