STM32基于YModem协议串口升级程序的实现

   YModem协议是由XModem协议演变而来的,每包数据可以达到1024字节,是一个非常高效的文件传输协议。

Ymodem是一种错误纠正协议。使用较大数据块的调制解调采用这种协议,以获得更高的工作效率。采用Ymodem协议的调制解调器以1024字节数的块发送数据。成功接收的不会被确认。有错误的块被确认(NAK),并重发。Ymodem类似于Xmodem-1K,不同之处是提供批处理模式(batch mode)。在批处理模式下,可以使用一个命令发送一些文件。Ymodem使用循环冗余码校验作为错误校验方式。


1.1  YMODEM 帧格式
YMODEM有两种帧格式,主要区别是信息块长度不一样。


1.1.1  帧头
帧头表示两种数据帧长度,主要是信息块长度不同。 当帧头为SOH(0x01)时,信息块为128字节; 当帧头为STX(0x02)时,信息块为1024字节。

1.1.2 包序号
数据包序号只有1字节,因此计算范围是0~255;对于数据包大于255的,序号归零重复计算。

1.1.3  帧长度
以SOH(0x01)开始的数据包,信息块是128字节,该类型帧总长度为133字节; 以STX(0x02)开始的数据包,信息块是1024字节,该类型帧总长度为1029字节。

1.1.4  校验
YMODEM采用的是CRC16校验算法,校验值为2字节,传输时CRC高八位在前,低八位在后;CRC计算数据为信息块数据,不包含帧头、包号、包号反码。

1.2  YMODEM起始帧
YMODEM起始帧并不直接传输文件内容,而是先将文件名和文件大小置于数据帧中传输;起始帧是以SOH 133字节长度帧传输,格式如下:


其中包号为固定为0; filename为文件名称,文件名称后必须加0x00作为结束; filesize为文件大小值,文件大小值后必须加0x00作为结束; 余下未满128字节数据区域,则以0x00填充。 可以看出起始帧也是遵守1.1中YMODEM包格式的。

1.3  YMODEM数据帧
YMODEM数据帧传输,在信息块填充有效数据。 传输有效数据时主要考虑的是最后一包数据的是处理,SOH帧和STX帧有不同的处理。 (1)对于SOH帧,若余下数据小于128字节,则以0x1A填充,该帧长度仍为133字节。 (2)对于STX帧需考虑几种情况:

1)余下数据等于1024字节,以1029长度帧发送;

2)余下数据小于1024字节,但大于128字节,以1029字节帧长度发送,无效数据以0x1A填充;

3)余下数据等于128字节,以133字节帧长度发送;

4)余下数据小于128字节,以133字节帧长度发送,无效数据以0x1A填充。

1.4  YMODEM结束帧
YMODEM的结束帧采用SOH 133字节长度帧传输,该帧不携带数据(空包),即数据区、校验都以0x00填充。


1.5  YMODEM握手信号
握手信号由接收方发起,在发送方开始传输文件前,接收方需发送YMODEM_C (字符C,ASII码为0x43)命令,发送方收到后,开始传输起始帧。

1.6  YMODEM命令

1.7 官方一个YMODEM传输过程
 


1)其中“sb foo.*”指的是Linux中的sb命令,可在Linux终端执行 sb --help查看使用方法

2)上图中YMODEM协议传输的数据块是128字节,其实YMODEM协议还支持1024字节的数据块或者128节和1024字节混合模式。详情请查阅YMODEM协议手册。

3)SOH 表示本数据块大小为128字节

4)STX 表示本数据块大小为1024字节

5)本文中EOT指令仅有一次会话,即上图中的最后一次

1.7.1  起始帧的数据格式
YMODEM的起始帧的数据块大小为128字节,传输的是文件名、文件大小、文件修改日期等信息,其中文件名和文件大小信息是必须的。128字节的剩余部分用空字符填充(也就是0)。

SOH 00 FF foo.c 3232 NUL[118] CRCH CRCL
1)SOH:表示本帧数据块大小为128字节

2)00: 表示数据帧序号,初始是0,依次向下递增,FF是帧序号的取反

3)foo.c:是要传输的文件名,是ASCII字符串(以空字符结尾)

4)3232:表示文件的大小,是ASCII字符串(以空字符结尾)

5)NUL[118]:剩余部分用空字符填充

6)CRCH/L: 表示16位CRC校验码的高8位与低8位

1.7.2  数据帧的数据格式
YMODEM的数据帧的数据块大小可以是128字节或者1024字节。

// 128字节的数据块 

SOH 01 FE data[128] CRCH CRCL
// 1024字节的数据块 

STX 01 FE data[1024] CRCH CRCL
一般会使用1024字节的数据块进行传输,这样可以加快传输速度,如果最后文件数据不足1024字节,则将其拆分为128字节的数据块进行传输,如果拆分后有不足128字节的数据依然按照128字节的数据块进行传输,但是剩余空间全部用0x1A填充,以表示文件结束。

1.7.3 结束帧数据结构
当文件传输结束时,除了发送EOT传输结束指令外,还需要发送一个结束帧。YMODEM的结束帧与起始帧的数据格式相同,数据块大小为128字节,但是结束帧的数据块要全用空字符填充。

SOH 3A C5 NUL[128] CRCH CRCL
 流程

1.     第一步先由接收方,发送一个字符'C'

2.     发送方收到'C'后,发送第一帧数据包,内容如下:

SOH 00 FF Foo.c  NUL[118] CRCH CRCL
3.     接收方收到第一帧数据包后,发送ACK正确应答,然后再发送一个字符'C'

4.     发送方收到'C'后,开始发送第二帧,第二帧中的数据存放的是第一包数据

5.     接收方收到数据后,发送一个ACK然后等待下一包数据传送完毕,继续ACK应答。直到所有数据传输完毕

6.     数据传输完毕后,发送方发EOT,第一次接收方以NAK应答,进行二次确认

7.     发送方收到NAK后,重发EOT,接收方第二次收到结束符,就以ACK应答

8.     最后接收方再发送一个'C',发送方在没有第二个文件要传输的情况下,发送如下数据

SOH 3A C5 NUL[128] CRCH CRCL
接收方应答ACK后,正式结束数据传输

STM32 串口升级程序下载:

基于Ymodem协议串口升级程序的实现过程-C文档类资源-CSDN下载

SENDER:发送方。(文件名:fileName.bin)
RECEIVER:接收方。
具体握手的步骤如下:
1、接收方发送一个字符‘C’,也就是十六进制‘43’。代表接收方已经处于接收数据的状态。
2、发送方接收到‘C’之后,发送头帧数据包,内容如下:
SOH 00 FF fileName.bin NULL[116] CRC CRC
数据包内容解释:2-1 SOH(第1字节):表示本数据区大小有128字节。(STX表示本数据包数据区大小1024字节)。2-2 00 (第2字节):数据块编号。 第一包为00,第二包为01,此后依次累加。FF后,继续从00循环。2-3 FF (第3字节):数据块编号的反码。 编号00—FF,01—FE,此后依次类推。2-4 fileName.bin NULL[116]:数据区。128字节。 fileName.bin是文件名,超级终端下,在文件名后面 还有文件大小。 数据区不足128字节的,用0x00补齐。2-5 CRC校验(最后2个字节):16位CRC校验,高位字节在前,地位字节在后。(注意:只有数据区参与了 CRC校验,不包含头、编码、编码反码)。
3、接收方收到数据包后,发送ACK正确应答,然后发送一个字符‘C’。
4、发送方收到‘C’后,开始发送第二帧数据。第二帧数据存放的是第一包数据。
5、接收方收好数据包后,发送ACK正确应答,然后等待下一包数据传送完毕,继续ACK应答。(循环)
6、数据传输完毕后,发送方第一次发EOT,第一次接收方以NAK应答,进行二次确认。
7、发送方收到NAK后,第二次发EOT。接收方第二次收到结束符,依次以ACK和C做应答。
8、发送方收到ACK和C之后,发送结束符—>SOH 00 FF 00…00[128个00] CRCH CRCL。
9、接收方收到结束符之后,以ACK做应答,然后通信正式结束。
/* Includes ------------------------------------------------------------------*/
#include "flash_if.h"
#include "common.h"
#include "ymodem.h"
#include "string.h"
#include "main.h"
#include "menu.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define CRC16_F       /* activate the CRC16 integrity */
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* @note ATTENTION - please keep this variable 32bit alligned */
uint8_t aPacketData[PACKET_1K_SIZE + PACKET_DATA_INDEX + PACKET_TRAILER_SIZE];/* Private function prototypes -----------------------------------------------*/
static void PrepareIntialPacket(uint8_t *p_data, const uint8_t *p_file_name, uint32_t length);
static void PreparePacket(uint8_t *p_source, uint8_t *p_packet, uint8_t pkt_nr, uint32_t size_blk);
static HAL_StatusTypeDef ReceivePacket(uint8_t *p_data, uint32_t *p_length, uint32_t timeout);
uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte);
uint16_t Cal_CRC16(const uint8_t* p_data, uint32_t size);
uint8_t CalcChecksum(const uint8_t *p_data, uint32_t size);/* Private functions ---------------------------------------------------------*//*** @brief  Receive a packet from sender* @param  data* @param  length*     0: end of transmission*     2: abort by sender*    >0: packet length* @param  timeout* @retval HAL_OK: normally return*         HAL_BUSY: abort by user*/
static HAL_StatusTypeDef ReceivePacket(uint8_t *p_data, uint32_t *p_length, uint32_t timeout)
{uint32_t crc;uint32_t packet_size = 0;HAL_StatusTypeDef status;uint8_t char1;*p_length = 0;status = HAL_UART_Receive(&UartHandle, &char1, 1, timeout);if (status == HAL_OK){switch (char1){case SOH:packet_size = PACKET_SIZE;break;case STX:packet_size = PACKET_1K_SIZE;break;case EOT:break;case CA:if ((HAL_UART_Receive(&UartHandle, &char1, 1, timeout) == HAL_OK) && (char1 == CA)){packet_size = 2;}else{status = HAL_ERROR;}break;case ABORT1:case ABORT2:status = HAL_BUSY;break;default:status = HAL_ERROR;break;}*p_data = char1;if (packet_size >= PACKET_SIZE ){status = HAL_UART_Receive(&UartHandle, &p_data[PACKET_NUMBER_INDEX], packet_size + PACKET_OVERHEAD_SIZE, timeout);/* Simple packet sanity check */if (status == HAL_OK ){if (p_data[PACKET_NUMBER_INDEX] != ((p_data[PACKET_CNUMBER_INDEX]) ^ NEGATIVE_BYTE)){packet_size = 0;status = HAL_ERROR;}else{/* Check packet CRC */crc = p_data[ packet_size + PACKET_DATA_INDEX ] << 8;crc += p_data[ packet_size + PACKET_DATA_INDEX + 1 ];if (HAL_CRC_Calculate(&CrcHandle, (uint32_t*)&p_data[PACKET_DATA_INDEX], packet_size) != crc ){packet_size = 0;status = HAL_ERROR;}}}else{packet_size = 0;}}}*p_length = packet_size;return status;
}/*** @brief  Prepare the first block* @param  p_data:  output buffer* @param  p_file_name: name of the file to be sent* @param  length: length of the file to be sent in bytes* @retval None*/
static void PrepareIntialPacket(uint8_t *p_data, const uint8_t *p_file_name, uint32_t length)
{uint32_t i, j = 0;uint8_t astring[10];/* first 3 bytes are constant */p_data[PACKET_START_INDEX] = SOH;p_data[PACKET_NUMBER_INDEX] = 0x00;p_data[PACKET_CNUMBER_INDEX] = 0xff;/* Filename written */for (i = 0; (p_file_name[i] != '\0') && (i < FILE_NAME_LENGTH); i++){p_data[i + PACKET_DATA_INDEX] = p_file_name[i];}p_data[i + PACKET_DATA_INDEX] = 0x00;/* file size written */Int2Str (astring, length);i = i + PACKET_DATA_INDEX + 1;while (astring[j] != '\0'){p_data[i++] = astring[j++];}/* padding with zeros */for (j = i; j < PACKET_SIZE + PACKET_DATA_INDEX; j++){p_data[j] = 0;}
}/*** @brief  Prepare the data packet* @param  p_source: pointer to the data to be sent* @param  p_packet: pointer to the output buffer* @param  pkt_nr: number of the packet* @param  size_blk: length of the block to be sent in bytes* @retval None*/
static void PreparePacket(uint8_t *p_source, uint8_t *p_packet, uint8_t pkt_nr, uint32_t size_blk)
{uint8_t *p_record;uint32_t i, size, packet_size;/* Make first three packet */packet_size = size_blk >= PACKET_1K_SIZE ? PACKET_1K_SIZE : PACKET_SIZE;size = size_blk < packet_size ? size_blk : packet_size;if (packet_size == PACKET_1K_SIZE){p_packet[PACKET_START_INDEX] = STX;}else{p_packet[PACKET_START_INDEX] = SOH;}p_packet[PACKET_NUMBER_INDEX] = pkt_nr;p_packet[PACKET_CNUMBER_INDEX] = (~pkt_nr);p_record = p_source;/* Filename packet has valid data */for (i = PACKET_DATA_INDEX; i < size + PACKET_DATA_INDEX;i++){p_packet[i] = *p_record++;}if ( size  <= packet_size){for (i = size + PACKET_DATA_INDEX; i < packet_size + PACKET_DATA_INDEX; i++){p_packet[i] = 0x1A; /* EOF (0x1A) or 0x00 */}}
}/*** @brief  Update CRC16 for input byte* @param  crc_in input value * @param  input byte* @retval None*/
uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte)
{uint32_t crc = crc_in;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;
}/*** @brief  Cal CRC16 for YModem Packet* @param  data* @param  length* @retval None*/
uint16_t Cal_CRC16(const uint8_t* p_data, uint32_t size)
{uint32_t crc = 0;const uint8_t* dataEnd = p_data+size;while(p_data < dataEnd)crc = UpdateCRC16(crc, *p_data++);crc = UpdateCRC16(crc, 0);crc = UpdateCRC16(crc, 0);return crc&0xffffu;
}/*** @brief  Calculate Check sum for YModem Packet* @param  p_data Pointer to input data* @param  size length of input data* @retval uint8_t checksum value*/
uint8_t CalcChecksum(const uint8_t *p_data, uint32_t size)
{uint32_t sum = 0;const uint8_t *p_data_end = p_data + size;while (p_data < p_data_end ){sum += *p_data++;}return (sum & 0xffu);
}/* Public functions ---------------------------------------------------------*/
/*** @brief  Receive a file using the ymodem protocol with CRC16.* @param  p_size The size of the file.* @retval COM_StatusTypeDef result of reception/programming*/
COM_StatusTypeDef Ymodem_Receive ( uint32_t *p_size )
{uint32_t i, packet_length, session_done = 0, file_done, errors = 0, session_begin = 0;uint32_t flashdestination, ramsource, filesize;uint8_t *file_ptr;uint8_t file_size[FILE_SIZE_LENGTH], tmp, packets_received;COM_StatusTypeDef result = COM_OK;/* Initialize flashdestination variable */flashdestination = APPLICATION_ADDRESS;while ((session_done == 0) && (result == COM_OK)){packets_received = 0;file_done = 0;while ((file_done == 0) && (result == COM_OK)){switch (ReceivePacket(aPacketData, &packet_length, DOWNLOAD_TIMEOUT)){case HAL_OK:errors = 0;switch (packet_length){case 2:/* Abort by sender */Serial_PutByte(ACK);result = COM_ABORT;break;case 0:/* End of transmission */Serial_PutByte(ACK);file_done = 1;break;default:/* Normal packet */if (aPacketData[PACKET_NUMBER_INDEX] != packets_received){Serial_PutByte(NAK);}else{if (packets_received == 0){/* File name packet */if (aPacketData[PACKET_DATA_INDEX] != 0){/* File name extraction */i = 0;file_ptr = aPacketData + PACKET_DATA_INDEX;while ( (*file_ptr != 0) && (i < FILE_NAME_LENGTH)){aFileName[i++] = *file_ptr++;}/* File size extraction */aFileName[i++] = '\0';i = 0;file_ptr ++;while ( (*file_ptr != ' ') && (i < FILE_SIZE_LENGTH)){file_size[i++] = *file_ptr++;}file_size[i++] = '\0';Str2Int(file_size, &filesize);/* Test the size of the image to be sent *//* Image size is greater than Flash size */if (*p_size > (USER_FLASH_SIZE + 1)){/* End session */tmp = CA;HAL_UART_Transmit(&UartHandle, &tmp, 1, NAK_TIMEOUT);HAL_UART_Transmit(&UartHandle, &tmp, 1, NAK_TIMEOUT);result = COM_LIMIT;}/* erase user application area */FLASH_If_Erase(APPLICATION_ADDRESS);*p_size = filesize;Serial_PutByte(ACK);Serial_PutByte(CRC16);}/* File header packet is empty, end session */else{Serial_PutByte(ACK);file_done = 1;session_done = 1;break;}}else /* Data packet */{ramsource = (uint32_t) & aPacketData[PACKET_DATA_INDEX];/* Write received data in Flash */if (FLASH_If_Write(flashdestination, (uint32_t*) ramsource, packet_length/4) == FLASHIF_OK)                   {flashdestination += packet_length;Serial_PutByte(ACK);}else /* An error occurred while writing to Flash memory */{/* End session */Serial_PutByte(CA);Serial_PutByte(CA);result = COM_DATA;}}packets_received ++;session_begin = 1;}break;}break;case HAL_BUSY: /* Abort actually */Serial_PutByte(CA);Serial_PutByte(CA);result = COM_ABORT;break;default:if (session_begin > 0){errors ++;}if (errors > MAX_ERRORS){/* Abort communication */Serial_PutByte(CA);Serial_PutByte(CA);}else{Serial_PutByte(CRC16); /* Ask for a packet */}break;}}}return result;
}/*** @brief  Transmit a file using the ymodem protocol* @param  p_buf: Address of the first byte* @param  p_file_name: Name of the file sent* @param  file_size: Size of the transmission* @retval COM_StatusTypeDef result of the communication*/
COM_StatusTypeDef Ymodem_Transmit (uint8_t *p_buf, const uint8_t *p_file_name, uint32_t file_size)
{uint32_t errors = 0, ack_recpt = 0, size = 0, pkt_size;uint8_t *p_buf_int;COM_StatusTypeDef result = COM_OK;uint32_t blk_number = 1;uint8_t a_rx_ctrl[2];uint8_t i;
#ifdef CRC16_F    uint32_t temp_crc;
#else /* CRC16_F */   uint8_t temp_chksum;
#endif /* CRC16_F */  /* Prepare first block - header */PrepareIntialPacket(aPacketData, p_file_name, file_size);while (( !ack_recpt ) && ( result == COM_OK )){/* Send Packet */HAL_UART_Transmit(&UartHandle, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT);/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F    temp_crc = HAL_CRC_Calculate(&CrcHandle, (uint32_t*)&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);Serial_PutByte(temp_crc >> 8);Serial_PutByte(temp_crc & 0xFF);
#else /* CRC16_F */   temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);Serial_PutByte(temp_chksum);
#endif /* CRC16_F *//* Wait for Ack and 'C' */if (HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK){if (a_rx_ctrl[0] == ACK){ack_recpt = 1;}else if (a_rx_ctrl[0] == CA){if ((HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)){HAL_Delay( 2 );__HAL_UART_FLUSH_DRREGISTER(&UartHandle);__HAL_UART_CLEAR_IT(&UartHandle, UART_CLEAR_OREF);result = COM_ABORT;}}}else{errors++;}if (errors >= MAX_ERRORS){result = COM_ERROR;}}p_buf_int = p_buf;size = file_size;/* Here 1024 bytes length is used to send the packets */while ((size) && (result == COM_OK )){/* Prepare next packet */PreparePacket(p_buf_int, aPacketData, blk_number, size);ack_recpt = 0;a_rx_ctrl[0] = 0;errors = 0;/* Resend packet if NAK for few times else end of communication */while (( !ack_recpt ) && ( result == COM_OK )){/* Send next packet */if (size >= PACKET_1K_SIZE){pkt_size = PACKET_1K_SIZE;}else{pkt_size = PACKET_SIZE;}HAL_UART_Transmit(&UartHandle, &aPacketData[PACKET_START_INDEX], pkt_size + PACKET_HEADER_SIZE, NAK_TIMEOUT);/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F    temp_crc = HAL_CRC_Calculate(&CrcHandle, (uint32_t*)&aPacketData[PACKET_DATA_INDEX], pkt_size);Serial_PutByte(temp_crc >> 8);Serial_PutByte(temp_crc & 0xFF);
#else /* CRC16_F */   temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], pkt_size);Serial_PutByte(temp_chksum);
#endif /* CRC16_F *//* Wait for Ack */if ((HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == ACK)){ack_recpt = 1;if (size > pkt_size){p_buf_int += pkt_size;size -= pkt_size;if (blk_number == (USER_FLASH_SIZE / PACKET_1K_SIZE)){result = COM_LIMIT; /* boundary error */}else{blk_number++;}}else{p_buf_int += pkt_size;size = 0;}}else{errors++;}/* Resend packet if NAK  for a count of 10 else end of communication */if (errors >= MAX_ERRORS){result = COM_ERROR;}}}/* Sending End Of Transmission char */ack_recpt = 0;a_rx_ctrl[0] = 0x00;errors = 0;while (( !ack_recpt ) && ( result == COM_OK )){Serial_PutByte(EOT);/* Wait for Ack */if (HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK){if (a_rx_ctrl[0] == ACK){ack_recpt = 1;}else if (a_rx_ctrl[0] == CA){if ((HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK) && (a_rx_ctrl[0] == CA)){HAL_Delay( 2 );__HAL_UART_FLUSH_DRREGISTER(&UartHandle);__HAL_UART_CLEAR_IT(&UartHandle, UART_CLEAR_OREF);result = COM_ABORT;}}}else{errors++;}if (errors >=  MAX_ERRORS){result = COM_ERROR;}}/* Empty packet sent - some terminal emulators need this to close session */if ( result == COM_OK ){/* Preparing an empty packet */aPacketData[PACKET_START_INDEX] = SOH;aPacketData[PACKET_NUMBER_INDEX] = 0;aPacketData[PACKET_CNUMBER_INDEX] = 0xFF;for (i = PACKET_DATA_INDEX; i < (PACKET_SIZE + PACKET_DATA_INDEX); i++){aPacketData [i] = 0x00;}/* Send Packet */HAL_UART_Transmit(&UartHandle, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE, NAK_TIMEOUT);/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F    temp_crc = HAL_CRC_Calculate(&CrcHandle, (uint32_t*)&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);Serial_PutByte(temp_crc >> 8);Serial_PutByte(temp_crc & 0xFF);
#else /* CRC16_F */   temp_chksum = CalcChecksum (&aPacketData[PACKET_DATA_INDEX], PACKET_SIZE);Serial_PutByte(temp_chksum);
#endif /* CRC16_F *//* Wait for Ack and 'C' */if (HAL_UART_Receive(&UartHandle, &a_rx_ctrl[0], 1, NAK_TIMEOUT) == HAL_OK){if (a_rx_ctrl[0] == CA){HAL_Delay( 2 );__HAL_UART_FLUSH_DRREGISTER(&UartHandle);__HAL_UART_CLEAR_IT(&UartHandle, UART_CLEAR_OREF);result = COM_ABORT;}}}return result; /* file transmitted successfully */
}/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __YMODEM_H_
#define __YMODEM_H_/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*//*** @brief  Comm status structures definition*/
typedef enum
{COM_OK       = 0x00,COM_ERROR    = 0x01,COM_ABORT    = 0x02,COM_TIMEOUT  = 0x03,COM_DATA     = 0x04,COM_LIMIT    = 0x05
} COM_StatusTypeDef;
/*** @}*//* Exported constants --------------------------------------------------------*/
/* Packet structure defines */
#define PACKET_HEADER_SIZE      ((uint32_t)3)
#define PACKET_DATA_INDEX       ((uint32_t)4)
#define PACKET_START_INDEX      ((uint32_t)1)
#define PACKET_NUMBER_INDEX     ((uint32_t)2)
#define PACKET_CNUMBER_INDEX    ((uint32_t)3)
#define PACKET_TRAILER_SIZE     ((uint32_t)2)
#define PACKET_OVERHEAD_SIZE    (PACKET_HEADER_SIZE + PACKET_TRAILER_SIZE - 1)
#define PACKET_SIZE             ((uint32_t)128)
#define PACKET_1K_SIZE          ((uint32_t)1024)/* /-------- Packet in IAP memory ------------------------------------------\* | 0      |  1    |  2     |  3   |  4      | ... | n+4     | n+5  | n+6  | * |------------------------------------------------------------------------|* | unused | start | number | !num | data[0] | ... | data[n] | crc0 | crc1 |* \------------------------------------------------------------------------/* the first byte is left unused for memory alignment reasons                 */#define FILE_NAME_LENGTH        ((uint32_t)64)
#define FILE_SIZE_LENGTH        ((uint32_t)16)#define SOH                     ((uint8_t)0x01)  /* start of 128-byte data packet */
#define STX                     ((uint8_t)0x02)  /* start of 1024-byte data packet */
#define EOT                     ((uint8_t)0x04)  /* end of transmission */
#define ACK                     ((uint8_t)0x06)  /* acknowledge */
#define NAK                     ((uint8_t)0x15)  /* negative acknowledge */
#define CA                      ((uint32_t)0x18) /* two of these in succession aborts transfer */
#define CRC16                   ((uint8_t)0x43)  /* 'C' == 0x43, request 16-bit CRC */
#define NEGATIVE_BYTE           ((uint8_t)0xFF)#define ABORT1                  ((uint8_t)0x41)  /* 'A' == 0x41, abort by user */
#define ABORT2                  ((uint8_t)0x61)  /* 'a' == 0x61, abort by user */#define NAK_TIMEOUT             ((uint32_t)0x100000)
#define DOWNLOAD_TIMEOUT        ((uint32_t)1000) /* One second retry delay */
#define MAX_ERRORS              ((uint32_t)5)/* Exported functions ------------------------------------------------------- */
COM_StatusTypeDef Ymodem_Receive(uint32_t *p_size);
COM_StatusTypeDef Ymodem_Transmit(uint8_t *p_buf, const uint8_t *p_file_name, uint32_t file_size);#include "main.h"
#include "common.h"
#include "flash_if.h"
#include "menu.h"
#include "ymodem.h"/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
pFunction JumpToApplication;
uint32_t JumpAddress;
uint32_t FlashProtection = 0;
uint8_t aFileName[FILE_NAME_LENGTH];/* Private function prototypes -----------------------------------------------*/
void SerialDownload(void);
void SerialUpload(void);/* Private functions ---------------------------------------------------------*//*** @brief  Download a file via serial port* @param  None* @retval None*/
void SerialDownload(void)
{uint8_t number[11] = {0};uint32_t size = 0;COM_StatusTypeDef result;Serial_PutString("Waiting for the file to be sent ... (press 'a' to abort)\n\r");result = Ymodem_Receive( &size );if (result == COM_OK){Serial_PutString("\n\n\r Programming Completed Successfully!\n\r--------------------------------\r\n Name: ");Serial_PutString(aFileName);Int2Str(number, size);Serial_PutString("\n\r Size: ");Serial_PutString(number);Serial_PutString(" Bytes\r\n");Serial_PutString("-------------------\n");}else if (result == COM_LIMIT){Serial_PutString("\n\n\rThe image size is higher than the allowed space memory!\n\r");}else if (result == COM_DATA){Serial_PutString("\n\n\rVerification failed!\n\r");}else if (result == COM_ABORT){Serial_PutString("\r\n\nAborted by user.\n\r");}else{Serial_PutString("\n\rFailed to receive the file!\n\r");}
}/*** @brief  Upload a file via serial port.* @param  None* @retval None*/
void SerialUpload(void)
{uint8_t status = 0;Serial_PutString("\n\n\rSelect Receive File\n\r");HAL_UART_Receive(&UartHandle, &status, 1, RX_TIMEOUT);if ( status == CRC16){/* Transmit the flash image through ymodem protocol */status = Ymodem_Transmit((uint8_t*)APPLICATION_ADDRESS, (const uint8_t*)"UploadedFlashImage.bin", USER_FLASH_SIZE);if (status != 0){Serial_PutString("\n\rError Occurred while Transmitting File\n\r");}else{Serial_PutString("\n\rFile uploaded successfully \n\r");}}
}/*** @brief  Display the Main Menu on HyperTerminal* @param  None* @retval None*/
void Main_Menu(void)
{uint8_t key = 0;Serial_PutString("\r\n======================================================================");Serial_PutString("\r\n=              (C) COPYRIGHT 2015 STMicroelectronics                 =");Serial_PutString("\r\n=                                                                    =");Serial_PutString("\r\n=  STM32L0xx In-Application Programming Application  (Version 1.0.0) =");Serial_PutString("\r\n=                                                                    =");Serial_PutString("\r\n=                                   By MCD Application Team          =");Serial_PutString("\r\n======================================================================");Serial_PutString("\r\n\r\n");/* Test if any sector of Flash memory where user application will be loaded is write protected */FlashProtection = FLASH_If_GetWriteProtectionStatus();while (1){Serial_PutString("\r\n=================== Main Menu ============================\r\n\n");Serial_PutString("  Download image to the internal Flash ----------------- 1\r\n\n");Serial_PutString("  Upload image from the internal Flash ----------------- 2\r\n\n");Serial_PutString("  Execute the loaded application ----------------------- 3\r\n\n");if(FlashProtection != FLASHIF_PROTECTION_NONE){Serial_PutString("  Disable the write protection ------------------------- 4\r\n\n");}else{Serial_PutString("  Enable the write protection -------------------------- 4\r\n\n");}Serial_PutString("==========================================================\r\n\n");/* Clean the input path */__HAL_UART_FLUSH_DRREGISTER(&UartHandle);__HAL_UART_CLEAR_IT(&UartHandle, UART_CLEAR_OREF);/* Receive key */HAL_UART_Receive(&UartHandle, &key, 1, RX_TIMEOUT);switch (key){case '1' :/* Download user application in the Flash */SerialDownload();break;case '2' :/* Upload user application from the Flash */SerialUpload();break;case '3' :Serial_PutString("Start program execution......\r\n\n");/* execute the new program */JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);/* Jump to user application */JumpToApplication = (pFunction) JumpAddress;/* Initialize user application's Stack Pointer */__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);JumpToApplication();break;case '4' :if (FlashProtection != FLASHIF_PROTECTION_NONE){/* Disable the write protection */if (FLASH_If_WriteProtectionConfig(FLASHIF_WRP_DISABLE) == FLASHIF_OK){Serial_PutString("Write Protection disabled...\r\n");Serial_PutString("System will now restart...\r\n");/* Launch the option byte loading */HAL_FLASH_OB_Launch();}else{Serial_PutString("Error: Flash write un-protection failed...\r\n");}}else{if (FLASH_If_WriteProtectionConfig(FLASHIF_WRP_ENABLE) == FLASHIF_OK){Serial_PutString("Write Protection enabled...\r\n");
Serial_PutString("System will now restart...\r\n");/* Launch the option byte loading */HAL_FLASH_OB_Launch();}else{Serial_PutString("Error: Flash write protection failed...\r\n");}}break;default:Serial_PutString("Invalid Number ! ==> The number should be either 1, 2, 3 or 4\r");break;}}
}

基于Ymodem协议串口升级程序的实现过程-C文档类资源-CSDN下载

网盘下载:

  1. 链接:https://pan.baidu.com/s/1eu5yzMwSNFWisqr-T7aJPw

  2. 提取码:w30a

     CRC xmodem计算:

                CRC(循环冗余校验)在线计算_ip33.com

https://github.com/caoliuchao/STM32F103-UartIAP/blob/master/IAP/Src/ymodem.c

STM32F103-UartIAP/ymodem.c at master · caoliuchao/STM32F103-UartIAP · GitHub

stm32f4_SerialPort_bootloader/ymodem.c at master · RdMaxes/stm32f4_SerialPort_bootloader · GitHub

https://github.com/Gooost/STM32-IAP/blob/master/User/ymodem.c

  1. STM32F103代码远程升级(三)基于YModem协议串口升级程序的实现_Tweedle Dee的博客-CSDN博客_ymodem串口在线升级

【YModem】YModem串口IAP升级例程+YModem串口工具_lunei的博客-CSDN博客_ymodem工具

STM32 CUbeIDE 使用Ymodem协议进行串口IAP升级_跳墙网https://www.tqwba.com/x_d/jishu/235595.html

【开源】串口YMODEM实现IAP程序升级(附工程源码)_freemote的博客-CSDN博客_ymodem源码

以上两段代码为YModem协议接收数据及处理数据的过程,在此之前我们需先初始化系统以及结构,同时需要注意以下几点:
1、Bootloader中尽可能不使用中断,因此此处串口接收数据采用查询接收方式;
2、Bootloader中不要让程序卡死或者进入某个死循环,应在适当的地方进行软件复位;
3、在Keil环境下涉及内存拷贝时,尽量不用memcpy();
4、注意数组长度越界或者溢出错误;
5、注意YModem协议第一包数据的包号为00。
 

switch (packet_length)
{
/* Abort by sender */
case - 1:
Send_Byte(ACK);
return 0;
/* End of transmission */
case 0:
if(flag_EOT==0) //first EOT
{
Send_Byte(NACK);
flag_EOT = 1;
}
else if (flag_EOT==1) //second EOT
{
Send_Byte(ACK);
Send_Byte('C');
file_done = 1;
}
break;


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部