在工作中写Bootloader时,需要串口传输代码数据,为了保证传输数据时不丢帧,需要用到通信协议,我选择的是Xmodem协议。
1. 定义
Xmodem协议
是串口通信中广泛使用到的异步文件传输协议。以128字节块
的形式传输数据,并且每个块都使用一个校验过程来进行错误检测。在校验过程中如果接收方关于一个块的检验和与它在发送方的检验相同时,接收方就向发送方发送一个确认字节ACK
。如果有错则发送一个字节NAK
要求重发。以保证传输过程中的正确性,但是由于需要对每个块都要进行检验,显得效率比较低。
2. 控制字符
控制字符 | 值 | 说明 |
---|---|---|
SOH | 0x01 | Xmodem数据头 |
STX | 0x02 | 1K-Xmodem数据头 |
EOT | 0x04 | 发送结束 |
ACK | 0x06 | 认可响应 |
NAK | 0x15 | 不认可响应 |
CAN | 0x18 | 终止传送 |
CTRLZ | 0x1A | 填充数据包 |
3. 帧数据格式
Byte0 | Byte1 | Byte2 | Byte3~Byte130 | Byte131~Byte132 |
---|---|---|---|---|
数据头SOH |
序列号 | 序列号补码 | 128位数据 | CRC16位校验 |
Xmodem协议的传输数据单位为信息包,包含一个标题开始字符SOH
或者STX
,一个单字节包序号
,一个单字节包包序号的补码
,128个字节数据
和一个双字节的CRC16校验
。
4. 数据包说明
对于标准Xmodem协议来说,如果传送的文件不是128的整数倍,那么最后一个数据包的有效内容肯定小于帧长,不足的部分需要用CTRL-Z(0x1A)
来填充。
这里可能有人会问,如果我传送的是bootloader工程生成的.bin文件,mcu收到后遇到0x1A字符会怎么处理?其实如果传送的是文本文件,那么接收方对于接收的内容是很容易识别的,因为CTRL-Z不是前128个ascii码,不是通用可见字符,如果是二进制文件,mcu其实也不会把它当作代码来执行。哪怕是excel文件等,由于其内部会有些结构表示各个字段长度等,所以不会读取多余的填充字符。否则Xmodem太弱了。
5. 启动传输
Xmodem协议的传输由接收方启动,接收方向发送方发送C
或者NAK
(这里的NAK是用来启动传输的。下面我们用到的NAK是用来对数据产生重传机制)。其中接收方发送NAK
信号表示接收方打算用累加和校验;发送字符C
则表示接收方打算使用CRC校验。
LPUART_DRV_SendData(INST_LPUART1, &C, 1); //发送Xmodem帧传输开始命令
6. 传输过程
当接收方发送的第一个C
或者NAK
到达发送方,发送方认为可以发送第一个数据包了,传输启动。发送方接着接着应该将数据以每次128字节的数据加上包头,包号,包号补码,末尾加上校验和,打包成帧格式传送。发送方发了第一个包后就等待接收方的确认字节ACK
,收到接收方传来的ACK
确认,就认为数据包被接收方正确接收,并且接收方要求发送方继续发送下一个包;如果发送方收到接收方传来的NAK
(这里的表示重发),则表示接收方请求重发刚才的数据包;如果发送方收到接收方传来的CAN
字节,则表示接收方请求无条件停止传输。
如果发送方正常传输完全部数据,需要结束传输,正常结束需要发送方发送EOT
通知接收方。接收方回以ACK
进行确认。如果接收方发送CAN
给发送方也可以强制停止传输,发送方受到CAN
后不需要发送EOT
确认,此时传输已