STM32使用Y-Modem协议进行程序升级

版权声明:本文为博主原创文章,未经博主允许不得转载,转载请添加出处 https://blog.csdn.net/u012953523/article/details/78911800

STM32 Ymodem协议串口升级

为了解决模块不拆机,通过串口对STM32进行程序升级,采用Y-modem 协议进行升级。STM32内存划分为IAP段和APP段。IAP段存储使用Y-Modem协议的下位机程序,APP则为正常使用的软件。

文件传输过程

1、文件传输过程的开启:  

(1)开启是由下位机开启传输,它发一个大写字母"C(0x43)"开启传输。然后进入等待(SOH)状态,如果没有回应,就会超时退出

(2)上位机开始时处于等待过程中,等待"C(0x43)"。收到"C(0x43)"以后,发送(SOH)数据包开始信号,发送序号(00),补码(FF),“文件名”,“0x00”“文件大小”“除去序号外,补满128字节(用0x00 补充)”,CRC校验两个字节。进入等待(ACK(0x06))状态。  

(3)下位机收到以后,CRC校验满足,则发送ACK(0x06)。上位机接收到ACK(0x06),又进入等待“文件传输开启”信号,即重新进入等待"C(0x43)"的状态。   

(4)前面下位机只是收到了一个文件名,现在正式开启文件传输,Ymodem支持128字节和1024字节一个数据包。128字节以(SOH)开始,1024字节以(STX)开始。

(5)下位机又发出一个"C(0x43)"信号,开始准备接收文件。进入等待"SOH"或者"STK"状态。  

(6)上位机接收到"C(0x43)"以后,发送数据包,(STX)(01序号)(FE补码)(1024位数据)(CRC校验),等待下位机"ACK(0x06)",序号依次递增,不足1024位数据用0x00补充

  (7)文件发送完以后,上位机发EOT(0x04),第一次下位机以NAK(0x15)应答,进行二次确认。上位机收到NAK(0x15)后,重发EOT(0x04),下位机第二次收到结束符,就以ACK(0x06)应答。最后下位机再发送一个"C(0x43)",接着上位机会发出一个“全0数据包”(以SOH 开始的数据包头),下位机"ACK(0x06)"以后,本次通信正式结束。

注:只有数据部分参与CRC校验,数据包头不参与CRC校验。

2、数据包格式

2.1文件名数据包

数据包头

数据(SOH 128 Byte)

CRC校验

 

序号

补码

文件名

 

文件大小

0x00 补齐

2Byte

SOH

 

 

 

00

 

高位在前

文件名 例:DM105_IAP.bin 文件大小 12456

除去用0x00补齐的数据,数据包头、校验码,数据包为

44 4D 31 30 35 5F 49 41 50 2E 62 69 6E 00 31 32 34 35 36

2.2 传输数据包

数据包头

数据(STX1024 Byte)

CRC校验

 

序号

补码

从 bin 文件中读取的数据(读取的数据不满足1024 Byte 用0x00补齐)

2Byte

STX

 

 

高位在前

注:不足1024Byte时,不一定用0x00补齐,因为下位机不是根据这个来判断文件结束的,而是上位机给出文件结束信号,所以可以用0x00-0xFF进行补齐都可以。

2.3 文件传输结束全0数据包

数据包头

数据(SOH 128 Byte)

CRC校验

 

序号

补码

128Byte都是00

2Byte

SOH

00

FF

高位在前

注:因为数据都是0,所以CRC校验也是00

2.4 Ymodem协议中宏定义

SOH (0x01)  //128字节数据包开始

STX (0x02)  //1024字节的数据包开始

EOT (0x04)  //结束传输

ACK (0x06)  //回应

NAK (0x15)  //没回应

C (0x43)  //'C' == 0x4

注:下位机回复NACK的时候,上位机需要重新发送一次数据包

以下提供CRC校验的C语言算法

/*******************************************************************************
  * @函数名称	UpdateCRC16
  * @函数说明   更新输入数据的CRC校验
  * @输入参数   crcIn
                byte
  * @输出参数   无
  * @返回参数   CRC校验值
*******************************************************************************/
uint16_t UpdateCRC16(uint16_t crcIn, uint8_t byte)
{
    uint32_t crc = crcIn;
    uint32_t in = byte|0x100;
    do
    {
        crc <<= 1;
        in <<= 1;
        if (in&0x100)
            ++crc;
        if (crc&0x10000)
            crc ^= 0x1021;
    }
    while (!(in&0x10000));
    return crc&0xffffu;
}

/*******************************************************************************
  * @函数名称	UpdateCRC16
  * @函数说明   更新输入数据的CRC校验
  * @输入参数   data :数据
                size :长度
  * @输出参数   无
  * @返回参数   CRC校验值
*******************************************************************************/
uint16_t Cal_CRC16(const uint8_t* data, uint32_t size)
{
    uint32_t crc = 0;
    const uint8_t* dataEnd = data+size;
    while (data<dataEnd)
        crc = UpdateCRC16(crc,*data++);

    crc = UpdateCRC16(crc,0);
    crc = UpdateCRC16(crc,0);
	
    return crc&0xffffu;
}
以下是我VS2015中C#的CRC校验,根据上面修改的
public UInt16 UpdateCRC16(UInt16 crcIn, byte data)
        {
            UInt32 crc = crcIn;
            UInt32 indata = (UInt32)(data | 0x100);
            do
            {
                crc <<= 1;
                indata <<= 1;
                if ((indata & 0x100) == 0x100)
                    ++crc;
                if ((crc & 0x10000) == 0x10000)
                    crc ^= 0x1021;
            }
            while ((indata & 0x10000) == 0);
                UInt16 redata = (UInt16)(crc & 0xffff);
            return redata;
        }
        public UInt16 Cal_CRC16(byte[] data, UInt32 size)
        {
            UInt16 crc = 0;
            for(UInt32 i =0; i< size; i++)
	        {
		        crc = UpdateCRC16(crc, data[i]);
            }


            crc = UpdateCRC16(crc,0);
            crc = UpdateCRC16(crc,0);
            UInt16 redata = (UInt16)(crc & 0xffff);
            return redata;
        }
以上所有为本人自己进行数据跟踪得到,如果有错误,欢迎指出。


展开阅读全文

没有更多推荐了,返回首页