






















本文主要介绍XMODEM协议,一些常用工具(如SecureCRT、TeraTerm)的具体行为,便于我们用于制作Uart Bootloader.
XMODEM 是一种早期的、经典的串行通信文件传输协议,主要用于通过串口(如RS 232)在2台设备间可靠的传输数据. 于1997年由Ward Christensen提出,现在也常用于嵌入式系统、Bootloader等场景.
XMODEM 核心设计目标:在高误码率、低带宽的串行链路上,实现简单而可靠的数据传输.
主要特点:
XMODEM 采用发送方主动发送、接收方确认的方式(ARQ),流程如下:
所有数据传输结束后,
XMODEM每个数据块(也称 数据包),格式如下:
+--------+--------+--------+----------------+--------+
| SOH | BLK # | ~BLK # | Data | CHECK |
+--------+--------+--------+----------------+--------+
注意:BLK = Block Number(块序号)
| 字段 | 大小(byte) | 描述 |
|---|---|---|
| SOH | 1 | 数据块起始标志. SOH=0x01,Data长度128byte; STX=0x02,Data长度1Kbyte |
| BLK # | 1 | Block Number(块序号,1~255循环),确保数据(块)按顺序接收 |
| ~BLK # | 1 | 块序号的按位取反,用于简单验证序列号是否正确 |
| Data | 128/1024 | 实际的文件数据. 如果不足128/1024 byte,则用CPMEOF(0x1A)或NULL(0x00) 填充 |
| CHECK | 1/2 | 取决于接收方确定的校验模式: * 校验和模式,1byte,数据区所有字节之和; * CRC模式,2byte,16位CRC校验 |
对于经典XMODEM协议,数据块起始标志为SOH=0x01;而对于扩展的XMODEM-1K协议,数据块起始标志为STX=0x02.
XMODEM-1K:
XMODEM-1K将XMODEM的Data长度,由128byte 扩展到1024byte. XMODEM-1K 几乎总是配合 CRC 使用,很少再使用校验和.
发送端如何确认接收端是否支持XMODEM-1K呢?如果不支持怎么办?
XMODEM 并没有正式的协商机制,不过工程上通常采用:
'C',请求CRC模式;STX(1KB数据块)NAKSOH(128B数据块)这是事实上的标准,而非协议规范.
BLK 有3个作用:
1)确保数据块按顺序接收
第1个块BLK=0x01,第2个块BLK=0x02,...,依次类推,第255个块BLK=0xFF,第256个块BLK绕回0x01.
如此,接收方可判断接收到的数据块,是否为下一个期望的数据块.
2)检测重复块
当接收方已正确接收到某个块,并ACK;但是发送方未收到ACK(可能丢失),而重复发送数据块.
接收方可据此判断是否为重复块,如果是,则丢弃;如果不是,则正常接收.
3)与~BLK组成简单的一致性检验
~BLK是BLK按位取反:
~BLK = BLK ^ 0xFF
<=>
~BLK + BLK = 0xFF
<=>
~BLK = ~(BLK) & 0xFF // 求反
XMODEM支持2种错误检测机制:
1)校验和(Checksum)
CHECK 字段占 1byte,对 128bytes 数据逐字节相加取低 8bits . 原始的XMODEM协议使用该方式,需要接收方发送NAK启动传输.
2)CRC-16(XMODEM-CRC)
CHECK 字段占 2byte,可靠性强于校验和模式. 需要接收方在传输开始前,通过发送字符'C'启动传输.
多项式:0x1021,即生成多项式为:
0x1021 = 0b 0001 0000 0010 0001
按位映射为:
x^16 + x^12 + x^5 + 1
参考实现代码:
/**
* @brief Calculate CRC16 for input package.
*
* @note CRC-16 XMODEM
* polynomial: x^16 + x^12 + x^5 + 1
*
* see https://blog.csdn.net/u012028275/article/details/112067463
*/
uint16_t xmodem_calc_crc(const uint8_t *data, uint32_t length)
{
uint16_t crc = 0;
while (length) {
crc = crc ^ ((uint16_t)*data << 8u);
length--;
data++;
for (uint8_t i = 0; i < 8; i++) {
if (crc & 0x8000u) {
crc = (crc << 1) ^ 0x1021u;
}
else {
crc = crc << 1;
}
}
}
return crc;
}
接收方、发送方正常通信的时序图:
接收方 (Receiver) 发送方 (Sender)
───────────────── ─────────────────
| |
| NAK / 'C' (请求启动传输) |
|--------------------------------------------->|
| |
|<-- SOH | BLK | ~BLK | DATA[128] | CRC ------|
| |
| [本地处理] |
| 校验 BLK, ~BLK |
| 校验 CRC |
| |
| ACK |
|--------------------------------------------->|
| |
|<-- SOH | BLK+1 | ~(BLK+1) | DATA | CRC ------|
| |
| ... |
| |
|<-- EOT --------------------------------------|
| |
| ACK (传输结束) |
|--------------------------------------------->|
接收方CRC校验失败,发送方重传的时序图:
接收方 发送方
────── ──────
| |
|<-- SOH | BLK | ~BLK | DATA | CRC ------|
| |
| [本地处理] CRC 校验失败 |
| |
|--- NAK ------------------------------->|
| |
|<-- SOH | BLK | ~BLK | DATA | CRC ------| 整帧重传
| |
| [本地处理] 校验成功 |
| |
|--- ACK ------------------------------->|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。