基于YMODEM通信协议的,LL库,IAPSTM32下位机设计(移植自官方例程)

实验结果

基于YMODEM通信协议的,LL库,IAPSTM32下位机设计(移植自官方例程)_第1张图片

步骤

1 因为LL库里并没有Flash相关的库函数,为了方便,于是我就仿照LL库的风格写了一个Flash函数库,连接:Flash的函数
2 仿照HAL库,用LL库写USART相关的收发函数,方便移植。
3.YODEM协议下的IAP的代码移植自STM32091C_EVAL的官方应用,直接到ST的固件包里去找ST的例程,建立两个工程,一个是引导程序,一个是升级的程序,引导程序工程结构如下(本人的单片机是030C8T6)
基于YMODEM通信协议的,LL库,IAPSTM32下位机设计(移植自官方例程)_第2张图片
4.将相应的C文件添加进工程里,stm32f0xx_ll_usart_ex是我仿照HAL库里的串口收发函数写的文件。编译,因为单片机不同,记得调节分区规则,根据错误信息,将HAL库的函数修改成LL库。
5.打开另外一个工程,LED_blink,根据在引导程序里设置的跳转地址,设置程序的开始地址基于YMODEM通信协议的,LL库,IAPSTM32下位机设计(移植自官方例程)_第3张图片
补充:CRC校验要使用YMODEM.C里的函数,STM32外设CRC校验结果是16位的,向量偏移已经在引导函数里做过了。

YMODEM.C

/* Includes ------------------------------------------------------------------*/
#include "flash_if.h"
#include "common.h"
#include "ymodem.h"
#include "string.h"
#include "main.h"
#include "menu.h"

#include "stm32f0xx_ll_usart_ex.h"

#define CRC16_F /* activate the CRC16 integrity */

/* @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 LL_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 LL_StatusTypeDef ReceivePacket(uint8_t *p_data, uint32_t *p_length, uint32_t timeout)
{
	uint32_t crc;
	uint32_t packet_size = 0;
	LL_StatusTypeDef status;
	uint8_t char1;

	*p_length = 0;
	status = ReceiveToR_Data(COM, &char1, 1);

	if (status == LL_OK)
	{
		switch (char1)
		{
		case SOH:
			packet_size = PACKET_SIZE;
			break;
		case STX:
			packet_size = PACKET_1K_SIZE;
			break;
		case EOT:
			break;
		case CA:
			if ((ReceiveToR_Data(USART1, &char1, 1) == LL_OK) && (char1 == CA))
			{
				packet_size = 2;
			}
			else
			{
				status = LL_ERROR;
			}
			break;
		case ABORT1:
		case ABORT2:
			status = LL_BUSY;
			break;
		default:
			status = LL_ERROR;
			break;
		}
		*p_data = char1;

		if (packet_size >= PACKET_SIZE)
		{
			status = ReceiveToR_Data(USART1, &p_data[PACKET_NUMBER_INDEX], packet_size + PACKET_OVERHEAD_SIZE);

			/* Simple packet sanity check */
			if (status == LL_OK)
			{

				if (p_data[PACKET_NUMBER_INDEX] != ((p_data[PACKET_CNUMBER_INDEX]) ^ NEGATIVE_BYTE))
				{
					packet_size = 0;
					status = LL_ERROR;
				}
				else
				{
					/* Check packet CRC */
					crc = p_data[packet_size + PACKET_DATA_INDEX] << 8;
					crc += p_data[packet_size + PACKET_DATA_INDEX + 1];
					if (Cal_CRC16(&p_data[PACKET_DATA_INDEX], packet_size) != crc)
					{
						packet_size = 0;
						status = LL_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 LL_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;
									TransmissionT_Data(COM, &tmp, 1);
									TransmissionT_Data(COM, &tmp, 1);
									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 LL_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 */
		TransmissionT_Data(COM, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE);
		/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F
		temp_crc = Cal_CRC16(&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 (ReceiveToR_Data(COM, &a_rx_ctrl[0], 1) == LL_OK)
		{
			if (a_rx_ctrl[0] == ACK)
			{
				ack_recpt = 1;
			}
			else if (a_rx_ctrl[0] == CA)
			{
				if ((ReceiveToR_Data(COM, &a_rx_ctrl[0], 1) == LL_OK) && (a_rx_ctrl[0] == CA))
				{
					LL_mDelay(2);
					LL_USART_RequestRxDataFlush(USART1);
					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;
			}
			TransmissionT_Data(COM, &aPacketData[PACKET_START_INDEX], pkt_size + PACKET_HEADER_SIZE);
			/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F
			temp_crc = Cal_CRC16(&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 ((ReceiveToR_Data(COM, &a_rx_ctrl[0], 1) == LL_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 (ReceiveToR_Data(COM, &a_rx_ctrl[0], 1) == LL_OK)
		{
			if (a_rx_ctrl[0] == ACK)
			{
				ack_recpt = 1;
			}
			else if (a_rx_ctrl[0] == CA)
			{
				if ((ReceiveToR_Data(COM, &a_rx_ctrl[0], 1) == LL_OK) && (a_rx_ctrl[0] == CA))
				{
					LL_mDelay(2);
					LL_USART_RequestRxDataFlush(COM);
					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 */
		TransmissionT_Data(COM, &aPacketData[PACKET_START_INDEX], PACKET_SIZE + PACKET_HEADER_SIZE);
		/* Send CRC or Check Sum based on CRC16_F */
#ifdef CRC16_F
		temp_crc = Cal_CRC16(&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 (ReceiveToR_Data(COM, &a_rx_ctrl[0], 1) == LL_OK)
		{
			if (a_rx_ctrl[0] == CA)
			{
				LL_mDelay(2);
				LL_USART_RequestRxDataFlush(COM);
				result = COM_ABORT;
			}
		}
	}

	return result; /* file transmitted successfully */
}

你可能感兴趣的:(单片机)