0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

mm32-2nd-bootloader技术进阶设计:实现Ymodem更新代码

灵动MM32MCU 来源:灵动MM32MCU 2023-06-09 09:28 次阅读

需求

前文中实现了一款简单的 2nd Bootloader,能够跳转执行存储在 QSPI Flash 中的应用程序,但 2nd Bootloader 如果仅仅只是用于跳转执行程序的话,岂不是有些太简单了?从本章开始,将会讲解几种 2nd Bootloader 进阶设计,实现类似 ISP 更新固件的功能,以及在 OTA 升级时避免变“砖”等设计,以及讲解一些 2nd Bootloader 的程序设计思路。

本文将以 Ymodem 协议获取应用程序的二进制文件为例,实现类似 ISP 更新固件的功能。

需要注意:

下文中提到的 ISP 仅指由 2nd Bootloader 实现的定制 ISP,而非微控制器本身的 ISP。

上位机发送的文件是二进制(.bin)文件,而不是 Intel Hex 标准的 hex (.hex)文件。

目前仅考虑直接覆盖的方式烧写程序,即获取到一段二进制数据后,直接写入到 QSPI Flash 的对应位置。

Ymodem 介绍

Ymodem 协议是一个文件传输协议,通常用于在资源受限的设备中传输文件,它可以一次传输1024字节的信息块,同时还支持传输多个文件。

Ymodem 协议有较多的变种,本文使用的是常用的 Ymodem-1K 协议。

通信时序

通讯时序如图1:

dc51c724-05f0-11ee-962d-dac502259ad0.png

图1 Ymodem 通信时序

帧格式

Ymodem 有两种帧格式:

帧头为 SOH 时,信息块长度为128字节,总长度133字节。

帧头为 STX 时,信息块长度为1024字节,总长度1029字节。

两种帧的帧格式如表1所示:

dc6bd330-05f0-11ee-962d-dac502259ad0.png

表1 SOH / STX 帧格式

包号从0x00起始,每成功传输一帧数据后包号加1,计数到0xFF后,下一次包号重新从0x00开始计数。

包号反码是包号取反的数值,如0x00的包号,包号反码为0xFF,0x01的包号,包号反码为0xFE。

信息块是要传输的具体数据块,起始帧包含了文件名和文件大小,数据帧包含了分段的数据内容。

校验采用 CRC 校验,仅校验信息块的内容。

除了两种帧格式外,还有 ACK、NAK、CAN、EOT、字符 'C' 五种命令,长度仅有1字节。

起始帧、数据帧、结束帧

起始帧采用帧头为 SOH 的帧格式传输,包号为 0x00,信息块中包含文件名字符串和文件大小字符串 (十进制表示),字符串以0x00结尾,信息块剩余部分以0x00填充。

数据帧采用帧头为 STX 的帧格式传输,包号从0x01开始计数,信息块中包含分段的文件内容。

当最后一段要发送的数据块大小超过128字节但小于1024字节时,采用帧头 STX 的帧格式传输,信息块结尾用 0x1A 填充。小于128字节,采用帧头为 SOH 的帧格式传输,信息块结尾依然用 0x1A 填充。

结束帧和起始帧一样,唯一不同的是没有文件名和文件大小,即信息块的内容全为 0x00。

通讯指令

通讯指令如表2所示。

dc874642-05f0-11ee-962d-dac502259ad0.png

表2 Ymodem通讯指令

协议实现

CRC 校验:

Ymodem 协议中提供了 CRC 校验的 C 代码片段,但由于该协议发布时的 C 标准不同于现在,因此不能直接使用,此处提供一份 CRC 校验的实现代码,通过调用 crc_calc() 来实现对信息块内容的校验:

staticuint16_tcrc_update(uint16_tcrc,uint8_tdata)
{
uint32_tcrc32=crc;
uint32_tdata32=data;

for(uint32_ti=0u;i< 8u; i++)
    {
        if (0 != (crc32 & 0x8000u) )
        {
            crc32 <<= 1u;
            crc32 += ( ( (data32 <<= 1) & 0x0100u) != 0u);
            crc32 ^= 0x1021;
        }
        else
        {
            crc32 <<= 1u;
            crc32 += ( ( (data32 <<= 1) & 0x0100u) != 0u);
        }
    }

    return (uint16_t)(crc32 & 0xFFFFu);
}

static uint16_t crc_calc(uint8_t * buffer, uint32_t size)
{
    uint16_t crc = 0u;

    for ( uint32_t i = 0u; i < size; i++)
    {
        crc = crc_update(crc, buffer[i]);
    }
    crc = crc_update(crc, 0u);
    crc = crc_update(crc, 0u);

    return crc;
}

当我们需要对一段数据进行 CRC 计算时,调用 crc_calc() 函数,传入数据起始地址和数据长度即可计算出 CRC 校验值。

STX 包处理:

通过对 Ymodem 协议的介绍可知,STX 包只在接收数据的过程中使用,因此收到 STX 包时,仅需要进行如下处理:

CRC校验信息块。

计算信息块的有效数据长度(需要注意最后一帧数据的有效长度不定)。

存储数据。

发送 ACK 指令或 NAK 指令。

SOH 包处理:

SOH 包的处理要比 STX 包的处理复杂,因为包含了起始帧和结束帧的处理。

起始 / 结束帧和数据帧只能通过当前状态来判断,其中,除信息块长度不同外,数据帧的处理同 STX 包的处理一致。

由于 Ymodem 可以多文件传输的特性,处于该收到结束帧的状态时也有可能收到起始帧,因此起始帧和结束帧需要进行一个判断:信息块第一个字节是否为 0x00。如果不是 0x00 则为起始帧,否则为结束帧。

起始帧要携带文件名和文件大小,信息块的第一个字节一定是一个可显示的字符,当收到起始帧时,需进行如下处理:

读取文件名和文件大小。

进入读数据块的状态。

发送 ACK。

发送 字符 'C'。

结束帧的信息块全为0x00,收到结束帧时,需进行如下处理:

发送 ACK。

结束 Ymodem 传输。

EOT 指令处理:

EOT 代表本次文件传输结束(但不代表所有文件都已发送完毕),因此,收到 EOT 指令时,需将当前状态调整为起始状态,准备接收新的文件,具体处理如下:

进入起始状态。

发送 ACK。

发送字符 'C'。

CAN 指令处理:

CAN 是 cancel 的缩写,当收到 CAN 指令后,表示后续的 Ymodem 传输终止,该指令是双向的,既可以由 Host 发送, 也可以是 Device 发送,收到 CAN 指令后,具体操作如下:

退出 Ymodem 传输。

接收超时处理:

Device 在接收数据前,会先向 Host 发送字符 'C',但如果此时 Host还没有将文件准备好,则会卡死在准备接收状态。

Device 在接收数据过程中,如果少接收到某个字节数据,信息不完整,则会卡死在接收数据的过程中。

Device 发送某个指令后,Host 可能没有收到指令,不会继续下一帧数据的发送,Device 还是会卡死在接收的过程中。

因此,需要引入接收超时的操作。

当接收超时后,判断状态,如果是起始状态,且没有收到任何字节,则可能是 Host 还没有准备发送文件,重新发送字符 'C'。

如果数据没有接收完整,则可能是少收到几个字节的数据,发送 NAK,让 Host 重新发送数据。

如果没有收到数据,则 Host 可能没有收到回复的指令,重新发送上次发送的指令。

软件设计

就像是计算机进入 BIOS 设置,需要用户在开机的瞬间不停按下键盘上某个按键那样,为了使 2nd Bootloader 知道自己是该跳转执行应用程序,还是进入 ISP 等模式,需要外界有一个输入:这个输入可以是某个引脚的电平变化,也可以是在有限的时间里通过某种通信接口获取到一段外界指令,当 2nd Bootloader 读取到这个来自外界的输入后,才能知道自己接下来要干什么。因此,除了实现 ISP 下载的功能外,我们还需要实现选择工作模式的功能,如图2所示:

dcaaf9ca-05f0-11ee-962d-dac502259ad0.png

图2 软件设计

Ymodem 只是获取二进制文件的一种方式,除了 Ymodem,我们也可以采用 Xmodem,Zmodem协议,除了串口,还可以使用 CAN,甚至通过 USB 读取 U 盘里的文件等方式。

综上所述,在设计 2nd Bootloader 时,不能绑死选择工作模式的方式,也不能绑死 ISP 的工作方式,甚至,不能绑死 2nd Bootloader 只能在两种工作模式下二选一(不要使用 if & else 的语句区分工作模式,而应使用 switch 语句区分工作模式),因此,2nd Bootloader 的顶层应用逻辑,只能是下面的设计:

intmain(void)
{
......
switch(get_run_mode())
{
caseEXEC_QSPI:
jump_to_app(QSPI_BASE);
break;
caseISP:
isp();
break;
......
default:
jump_to_app(QSPI_BASE);
break;
}
......
}

如果我们期望从某种工作模式下切换到另一种工作模式,最好的做法是先让外界输入保持为目标工作模式的状态,然后让微控制器复位,再次进入 2nd Bootloader,这样的做法是能够保持微控制器切换工作模式后,仍然保持相对 “干净” 的环境状态,例如,微控制器前一次进入到了 ISP 模式,通过串口更新了应用程序,如果直接跳转到应用程序,则发现串口依然保持打开的状态,这对应用程序而言可能不是期望的结果,那提前关闭串口呢?还有 GPIO 引脚的配置没有改动……最简单省事的做法,其实就是直接让微控制器复位,而串口和串口的 GPIO 引脚也就会在微控制器复位之后,处于默认相对比较 “干净” 的状态。这也是为什么图x所示的流程图,ISP 模式的下一步是复位微控制器。

当然,如果在 get_run_mode() 的时候就用到了串口,那还是老老实实在 get_run_mode() 执行到 return 之前,就把串口和 GPIO 处理干净。

这里提一个比较“花”的设计方法,我们可以把 ISP 也做成应用程序,下载到片内 Flash 中 一块确认好的位置(假设起始地址为 ISP_BASE),然后同样使用 jump_to_app() 跳转,只是输入参数从 QSPI_BASE 变为了 ISP_BASE,这个做法会用在 USB DFU 模式上,因为一旦进入了 USB DFU 模式,USB 就不能再作为其它设备进行工作,当 USB 设备支持 USB DFU 时,就需要使用这种办法单独进入到 DFU 模式下。

测试

选择工作模式:

在这里,我们通过读取指定引脚的电平状态来确定该进入何种工作模式。

uint32_tget_run_mode()
{
......
if(GPIO_ReadInDataBit(BOARD_BOOT_GPIO_PORT,BOARD_BOOT_GPIO_PIN))
{
returnEXEC_QSPI;
}
else
{
returnISP;
}
......
}

ISP 模式:

当进入 ISP 模式后,开始使用 Ymodem 协议接收数据。

voidisp()
{
......
/*getnewappbin&writetoqspiflash.*/
ymodem_recv_start(&ym,100000);
while(0==(YMODEM_STATUS_DONE&ym.status))
{
ymodem_recv_byte_handler(&ym);
}

/*resetmcu.*/
__set_FAULTMASK(1);
NVIC_SystemReset();
}

生成应用程序的二进制文件:

我们仍然以 MindSDK 的 hello_world 样例工程为例,修改其 Linker 文件并检查代码,使其成为一个可存储在 QSPI Flash 上的应用程序,随后在 MDK 工程中,点击魔术棒(Options for Target...),点击 User 列表,如图3所示,在指定位置(红框中的 User Command)加入下面这句话,并在前面打上对勾:

fromelf.exe --bin -o "@L.bin" "#L"

然后编译工程,就能在工程文件所在的目录下找到生成的 bin 文件。

dcc84caa-05f0-11ee-962d-dac502259ad0.png

图3 生成二进制文件

本文使用 TeraTerm 软件进行 Ymodem 传输文件,如图4所示:

dcf15e56-05f0-11ee-962d-dac502259ad0.png

图4 TeraTerm Ymodem 发送文件

但在测试时发现,当文件传输到 100% 时,TeraTerm 并没有结束传输,但对 2nd Bootloader 的代码进行分析后并没有发现存在逻辑问题,因此对 TeraTerm 的 Ymodem 协议产生了怀疑,如图5所示。

dd221fb4-05f0-11ee-962d-dac502259ad0.png

图5 TeraTerm 传输文件,总卡在 100% 处

使用两个 USB 串口模块,将其 TXD 与 RXD 相连,其中一个串口模块使用 TeraTerm 打开,另一个使用 SSCOM 打开(为了能够发送和显示一些非字符类的控制指令),使用 TeraTerm 的 Ymodem 协议发送文件, SSCOM 接收来自 TeraTerm 的数据,并按照 Ymodem 协议回复指令,模拟完整的 Ymodem 传输协议,如图6所示。

dd491560-05f0-11ee-962d-dac502259ad0.png

图6 模拟 Ymodem 协议传输文件过程

结果发现,TeraTerm 实现的 Ymodem 协议在发送单个文件的时候,存在以下问题:

发送 EOT 指令后,需接收两次 ACK 和字符 ‘C’。

没有发送 last block。

因此,我们需要针对 TeraTerm 的问题,对 Ymodem 的实现做一些改动,或者使用其它软件通过 Ymodem 传输二进制文件。修改后的时序图如下:

dd6fc30e-05f0-11ee-962d-dac502259ad0.png

图7 针对 TeraTerm 的 Ymodem 实现进行的改动

删去了对 last block 的接收,并且在收到 EOT 后,主动发送两次 ACK 和 字符 ‘C’,经过修改后测试,TeraTerm 的 Ymodem 能够按照传输完成的方式正常退出。

下载程序,如图8所示:

dd95af74-05f0-11ee-962d-dac502259ad0.png

图8 下载应用程序

运行应用程序,如图9所示:

ddb781c6-05f0-11ee-962d-dac502259ad0.png

图9 运行应用程序

结语

本文在 2nd Bootlaoder 的基础上实现了基于 Ymodem 协议的 ISP 功能,能够通过复位后指定引脚的电平状态来区分该执行应用程序还是进入 ISP 模式,进入 ISP 模式后,可以使用 TeraTerm 等软件,通过串口,使用 Ymodem 协议将二进制文件下载到与微控制器连接的 QSPI Flash 中,实现固件更新的功能。

但本文并没有对固件更新过程中可能出现的意外进行处理,所以这种 ISP 的办法不能直接用在 OTA 升级中,在下一章中,我们将会探讨 OTA 升级时可能会出现的意外情况,并且进行处理。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • FlaSh
    +关注

    关注

    10

    文章

    1550

    浏览量

    146646
  • ISP
    ISP
    +关注

    关注

    6

    文章

    457

    浏览量

    50844
  • 应用程序
    +关注

    关注

    37

    文章

    3136

    浏览量

    56391
  • bootloader
    +关注

    关注

    2

    文章

    230

    浏览量

    45049
  • Ymodem
    +关注

    关注

    0

    文章

    3

    浏览量

    3521

原文标题:灵动微课堂 (第259讲)|mm32-2nd-bootloader技术白皮书(8)——进阶:实现 Ymodem 更新代码

文章出处:【微信号:MindMotion-MMCU,微信公众号:灵动MM32MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    stm32 Bootloader设计(YModem协议)(转)

    位的win7下超级终端没办法使用。 不过SecureCRT工具到是可以在64位win7使用,但是官方代码不对其支持。SecureCRT下支持的是最原始的YModem协议,第一帧数据包中不包含总字节数
    发表于 01-22 15:12

    谈谈STM32F4 IAP BOOTLOADER YMODEM

    STM32F4 IAP BOOTLOADER YMODEM XModem、YModem、ZModem
    发表于 08-23 07:22

    基于ymodem协议的Bootloader是怎样通过串口进行传输的呢

    STM32的Bootloader该如何去实现呢?基于ymodem协议的Bootloader是怎样通过串口进行传输的呢?
    发表于 12-06 06:26

    求助,使用OTA更新APP代码后运行FAL分区识别不了

    使用OTA更新APP代码后跳转到APP程序运行时FAL分区识别不了。具体执行流程如下。1、无OTA程序时APP程序编写运行串口信息输出如下2、使用RTT官方的IOT进行BootLoader
    发表于 04-22 09:33

    基于MM32F0140系列MCU实现UDS Bootloader的设计

    而言,如果程序内置有基于FlexCAN Bootloader,则每次更新 ECU 的固件可不必再使用烧录器进行烧录,而可直接通过 CAN总线来更新程序,而且随着汽车智能化的普及,甚至可以对 ECU 进行远程升级。有无
    发表于 09-15 16:35

    BK7252更新ymodembootloader功能

    提示: 如果板子还能正常启动,可以直接更新RBL文件,一、更新ymodembootloader 固件硬件准备:麻雀1号开发板,配套的无线编程器,typeC 线,PC 电脑软件准
    发表于 09-27 10:55

    使用OTA升级的方法更新ymodem bootloader的rbl文件

    前言上次分享了一个需要使用无线编程器烧录带 ymodem 功能的 bootloader ,有些朋友反馈说手上没有无线编程器,so 建议造一个可以通过 ota 更新的带 ymodem
    发表于 09-27 10:59

    通过Ymodem创建IAP应用程序

    更新。以上3个步骤,我们就可以得到一个.bin的APP程序,通过bootloader程序即可实现更新。3.4 MCU 与上位机通信流程1. MCU与上位机通过
    发表于 11-03 20:11

    使用bootloader进行ymodem_ota升级失败是何原因

    问题描述:在使用官方提供的bootloader进行ymodem_ota升级时发现,在不更新的情况下,boot每次上电都会引导先从download区将程序写入app区,在运行。测试环境:使用官方提供
    发表于 11-16 10:48

    基于ARM核的Bootloader代码的分析与设计

    Bootloader 是系统上电或复位后首先运行的一段代码Bootloader 代码(即启动代码)的好坏对整个系统的运行效率有着重要的影响
    发表于 08-15 09:45 47次下载

    Bootloader 系统使用新应用代码和/或数据管理组件闪存的更新流程

    Bootloader 系统使用新应用代码和/或数据管理组件闪存的更新流程
    发表于 10-09 16:17 4次下载
    <b class='flag-5'>Bootloader</b> 系统使用新应用<b class='flag-5'>代码</b>和/或数据管理组件闪存的<b class='flag-5'>更新</b>流程

    Bootloader系统使用新应用代码和/或数据管理组件闪存的更新流程

    Bootloader系统使用新应用代码和/或数据管理组件闪存的更新流程
    发表于 10-10 08:24 12次下载
    <b class='flag-5'>Bootloader</b>系统使用新应用<b class='flag-5'>代码</b>和/或数据管理组件闪存的<b class='flag-5'>更新</b>流程

    bootloader如何更新

    BootLoader就是单片机启动时候运行的一段小程序,这段程序负责单片机固件的更新,也就是单片机选择性的自己给自己下程序。可以更新,也可以不更新
    发表于 11-10 08:22 7309次阅读
    <b class='flag-5'>bootloader</b>如何<b class='flag-5'>更新</b>

    mm32-2nd-bootloader配置软硬件环境

    MM32F5 系列微控制器具备 QSPI 接口,可以外接 QSPI Flash,扩大可使用的 Flash 空间,从而满足那些需要大 Flash 空间应用的需求,让 Flash 空间的大小不再成为限制应用开发的瓶颈。
    的头像 发表于 03-08 13:51 514次阅读

    mm32-2nd-bootloader技术白皮书(5)——编译可在QSPI Flash上运行的程序

    mm32-2nd-bootloader技术白皮书(5)——编译可在QSPI Flash上运行的程序
    的头像 发表于 10-24 16:14 230次阅读
    <b class='flag-5'>mm32-2nd-bootloader</b><b class='flag-5'>技术</b>白皮书(5)——编译可在QSPI Flash上运行的程序