天天看点

基于“ModBus写文件”实现STM32串口IAP升级固件(下)

STM32下位机这边分为两个程序,一个是BootLoader,一个是正常启动的APP

流程

正常启动流程

固件升级流程

上位机流程详情见上一篇博客

总的来说,下位机运行在APP是常态,通过ModBus指令,让其跳转回BootLoader。

在BootLoader中进行接收固件,覆盖APP程序,以达到固件升级的目的。

BootLoader程序

以SMT32F103ZET6为例,有512k flash,总共有0x80000个地址。

切割成两块。BootLoader占据64k,APP占据448k。

| 程序块 | start | size | end |

| ------------- |:-------------😐 -----😐

| BootLoader | 0x8000000 | 0x10000 | 0x8010000 |

| App | 0x8010000 | 0x70000 | 0x8080000 |

ROM配置

基于“ModBus写文件”实现STM32串口IAP升级固件(下)

main.c

#include "main.h"

uint8_t rx_buffer[USART_MAX_LEN];
uint8_t tx_buffer[USART_MAX_LEN];
uint16_t rx_buffer_len=0;

uint16_t otaStatus=0;				//OTA״̬
uint16_t softwareVersion=0;		//¹Ì¼þ°æ±¾
_W2Byte softwareLength;			//¹Ì¼þ´óС
uint16_t _recordNumber;			//¼Ç¼ºÅ


int main(void)
{ 
	HAL_Init();                    	 		//³õʼ»¯ HAL¿â     
	Stm32_Clock_Init(RCC_PLL_MUL9);   	//³õʼ»¯ ʱÖÓ,72M 
	IWDG_Init(IWDG_PRESCALER_64,2000);  //³õʼ»¯ ÄÚ²¿¿´ÃŹ· ·ÖƵÊýΪ64,ÖØÔØֵΪ1000,Òç³öʱ¼äΪ4s	
	SP706SE_Init();											//³õʼ»¯ Íⲿ¿´ÃŹ·
	BUZZ_Init();
	MX_USART1_UART_Init(); 							//³õʼ»¯ ´®¿Ú1
	USP_USART_RINGBUFFER_Init();	  		//³õʼ»¯ ´®¿Ú»·Ðλº³åÇø
	 
	Boot2App();  
	
	while(1)
	{
		HAL_Delay(10);
		IWDG_Feed();		//ι¹· ÄÚ²¿¿´ÃŹ·
		SP706SE_WDOG;		//ι¹· Íⲿ¿´ÃŹ· 
		
		USART_Receive_Data(&huart1,rx_buffer,&rx_buffer_len);
		if(rx_buffer_len>0)
		{
			ModbusTask();
		} 
	} 
}

void Boot2App(void)
{
	STMFLASH_Read(FLASH_OTA_STATUS_ADDR,&otaStatus,1);//¶ÁÈ¡µ±Ç°OTA״̬  
	if(otaStatus==0)
	{  
		DBG_DEBUG("Boot2App");
		if(((*(vu32*)(FLASH_APP_ADDR+4))&0xFF000000)==0x08000000)//ÅжÏÊÇ·ñΪ0X08XXXXXX.	 
			iap_load_app(FLASH_APP_ADDR);//Ö´ÐÐFLASH APP´úÂë
		else  
			DBG_ERROR("·ÇFLASHÓ¦ÓóÌÐò,ÎÞ·¨Ö´ÐÐ!\r\n");   
	}
	DBG_DEBUG("%d,BootLoader...",otaStatus);
}

void ModbusTask(void)
{
	uint16_t crc;
	uint8_t cmd;
	
	if(rx_buffer[0] == 0x09)	                        
	{
		crc = CRC16(rx_buffer, rx_buffer_len -2);
		if(crc == ((rx_buffer[rx_buffer_len-1]<<8)|rx_buffer[rx_buffer_len-2]))//УÑéCRC
		{
			cmd = rx_buffer[1];
			switch(cmd)
			{
				case 0x03:
					Modbus_Function_3();     
				break;
				case 0x10:
					Modbus_Function_10();
				break;
				case 0x15:
					Modbus_Function_15();
				break;
			}
		} 
	} 
}

//¶Á¶à¸ö¼Ä´æÆ÷
void Modbus_Function_3(void)   
{
	u16 reg_addr;
	u16 reg_count; 
	u16 crc16;  
	u16 index=3;
	reg_addr = (rx_buffer[2]<<8) + rx_buffer[3];
	reg_count = (rx_buffer[4]<<8) + rx_buffer[5]; 
	
	if(reg_addr == 0xFF00 && reg_count==0x01)								
	{ //¶ÁÈ¡µ±Ç°OTA״̬  
		index=3;
		STMFLASH_Read(FLASH_OTA_STATUS_ADDR,&otaStatus,1);
		tx_buffer[index++] = otaStatus>>8;
		tx_buffer[index++] = otaStatus;
		DBG_DEBUG("otaStatus=%d",otaStatus);
	}
	if(reg_addr == 0xFF02 && reg_count==0x01)
	{ //¶ÁÈ¡¹Ì¼þ°æ±¾
		index=3;
		STMFLASH_Read(FLASH_SOFTWARE_VERSION_ADDR,&softwareVersion,1);
		tx_buffer[index++] = softwareVersion>>8;
		tx_buffer[index++] = softwareVersion;
		DBG_DEBUG("softwareVersion=%d",softwareVersion);
	}
	if(reg_addr == 0xFF04 && reg_count==0x02)
	{ //¶ÁÈ¡¹Ì¼þ´óС
		index=3;
		STMFLASH_Read(FLASH_SOFTWARE_LENGTH_ADDR,softwareLength.w,2);
		tx_buffer[index++] = softwareLength.b[0];
		tx_buffer[index++] = softwareLength.b[1];
		tx_buffer[index++] = softwareLength.b[2];
		tx_buffer[index++] = softwareLength.b[3];
		DBG_DEBUG("softwareLength=%d",softwareLength.w2);
	}
	
	tx_buffer[0] = rx_buffer[0];//modbusµØÖ·
	tx_buffer[1] = 0x03;
	tx_buffer[2] =  index-3; //×Ö½ÚÊý
	
	crc16 = CRC16(tx_buffer, index);
	tx_buffer[index++] = crc16;
	tx_buffer[index++] = crc16>>8;
	HAL_UART_Transmit(&huart1, tx_buffer, index, 3000); 
}

//дÈë¶à¼Ä´æÆ÷
void Modbus_Function_10(void)           
{
	u16 reg_addr, reg_count;
	u16 crc16, i;  
	
	reg_addr = (rx_buffer[2]<<8) + rx_buffer[3];
	reg_count = (rx_buffer[4]<<8) + rx_buffer[5];  
	
	if(reg_addr == 0xFF00 && reg_count==0x0001)  
	{	//дOTA״̬   
		otaStatus = (rx_buffer[7]<<8) + rx_buffer[8];
		STMFLASH_Write(FLASH_OTA_STATUS_ADDR,&otaStatus,1);
		DBG_DEBUG("дOTA STATUS : %d",otaStatus);
		Boot2App();
	}  
	if(reg_addr == 0xFF02 && reg_count==0x0001)  
	{	//д¹Ì¼þ°æ±¾
		softwareVersion = (rx_buffer[7]<<8) + rx_buffer[8];
		STMFLASH_Write(FLASH_SOFTWARE_VERSION_ADDR,&softwareVersion,1);
		DBG_DEBUG("дSoftware Version : %d",softwareVersion); 
	}  
	if(reg_addr == 0xFF04 && reg_count==0x0002)  
	{	//д¹Ì¼þ´óС 
		softwareLength.b[0] = rx_buffer[7];
		softwareLength.b[1] = rx_buffer[8];
		softwareLength.b[2] = rx_buffer[9];
		softwareLength.b[3] = rx_buffer[10];
		STMFLASH_Write(FLASH_SOFTWARE_LENGTH_ADDR,softwareLength.w,2);
		DBG_DEBUG("дSoftware Length : %d",softwareLength.w2); 
	}  
	
	for(i = 0; i < 6; i++)
		tx_buffer[i] = rx_buffer[i];
	
	crc16 = CRC16(tx_buffer, 6);
	tx_buffer[6] = crc16;
	tx_buffer[7] = crc16>>8; 
	
	HAL_UART_Transmit(&huart1, tx_buffer, 8, 3000); 
} 

//дÈëÎļþ
void Modbus_Function_15(void)           
{
	u8 refType;					//²Î¿¼ÀàÐÍ
	u16 fileNumber;			//ÎļþºÅ
	u16 recordNumber;		//¼Ç¼ºÅ 
	u16 recordLength;		//¼Ç¼³¤¶È
	u16 i; 
	
	refType = (rx_buffer[3]);
	fileNumber = (rx_buffer[4]<<8) + rx_buffer[5];
	recordNumber = (rx_buffer[6]<<8) + rx_buffer[7]; 
	recordLength = (rx_buffer[8]<<8) + rx_buffer[9]; 
	 
	if(refType!=0x06)
	{
		DBG_ERROR("дÎļþ ²Î¿¼ÀàÐÍ ERROR");
		return;
	}
	if(recordLength!=0xf0)
	{
		DBG_ERROR("дÎļþ ¼Ç¼ºÅ³¤¶È ERROR");		
		return;
	}
	if(softwareLength.w==0)
	{
		DBG_ERROR("дÎļþ ¹Ì¼þ´óСΪ¿Õ");		
		return;
	}
	
	if(recordNumber==0)
		_recordNumber=0;
	else
	{
		if(recordNumber-_recordNumber==1 || recordNumber==_recordNumber)
		{	//дÈëÏÂÒ»¸öÎļþ¼Ç¼
			_recordNumber=recordNumber; 
		}
		else
		{
			DBG_ERROR("дÎļþ ¼Ç¼ºÅ Error");
			return;
		}
	}  
	
	iap_write_appbin(FLASH_APP_ADDR+_recordNumber*0xf0,rx_buffer+10,recordLength);//¸üÐÂFLASH´úÂë   
	
	for(i = 0; i < rx_buffer_len; i++)
		tx_buffer[i] = rx_buffer[i];
	 
	
	HAL_UART_Transmit(&huart1, tx_buffer, rx_buffer_len, 3000); 
	
	if( (_recordNumber == (softwareLength.w2/0xf0-1) && (softwareLength.w2%0xf0==0)) ||
			(_recordNumber == (softwareLength.w2/0xf0) && (softwareLength.w2%0xf0!=0)) )
	{	//¼Ç¼ºÅ==¹Ì¼þ´óС£¬¹Ì¼þ½ÓÊÕÍê³É£¬¿ªÊ¼Éý¼¶
		otaStatus = 0; 
		softwareVersion=fileNumber; 
		
		STMFLASH_Write(FLASH_OTA_STATUS_ADDR,&otaStatus,1);
		STMFLASH_Write(FLASH_SOFTWARE_VERSION_ADDR,&softwareVersion,1); 
		Boot2App();
	}
} 

/* 
 * º¯ÊýÃû£ºCRC16
 * ÃèÊö  : ¼ÆËãCRC16
 * ÊäÈë  £ºaData---Êý¾Ý£¬ aSize---Êý¾Ý³¤¶È
 * Êä³ö  : УÑéÖµ
 */
uint16_t CRC16(uint8_t *ptr,uint16_t len)
{
	 unsigned char i;
	 unsigned short crc = 0xFFFF;
	 if(len==0)
	 {
		 len = 1;
	 }
	 while(len--) 
	 {
		 crc ^= *ptr;
		 for(i=0; i<8; i++)
		 {
			 if(crc&1)
			 {
				 crc >>= 1;
				 crc ^= 0xA001;
			 }
			 else
			 {
					crc >>= 1;
			 }
		 }
		 ptr++;
	 }
	 return(crc);
} 


           

APP程序

ROM配置

基于“ModBus写文件”实现STM32串口IAP升级固件(下)

生成bin文件

基于“ModBus写文件”实现STM32串口IAP升级固件(下)
D:\Keil_v5\ARM\ARMCC\bin\fromelf.exe   --bin -o  ..\OBJ\RTU_V1_0.bin ..\OBJ\RTU_V1_0.axf
           

main.c

#include "main.h"

uint8_t rx_buffer[USART_MAX_LEN];
uint8_t tx_buffer[USART_MAX_LEN];
uint16_t rx_buffer_len=0; 


int main(void)
{ 
	SCB->VTOR = ((uint32_t)0x08010000);
	
	HAL_Init();                    	 		//³õʼ»¯ HAL¿â     
	Stm32_Clock_Init(RCC_PLL_MUL9);   	//³õʼ»¯ ʱÖÓ,72M 
  IWDG_Init(IWDG_PRESCALER_64,2000);  //³õʼ»¯ ÄÚ²¿¿´ÃŹ· ·ÖƵÊýΪ64,ÖØÔØֵΪ1000,Òç³öʱ¼äΪ4s	
	SP706SE_Init();											//³õʼ»¯ Íⲿ¿´ÃŹ·
	BUZZ_Init();
  MX_USART1_UART_Init(); 							//³õʼ»¯ ´®¿Ú1
  USP_USART_RINGBUFFER_Init();	  		//³õʼ»¯ ´®¿Ú»·Ðλº³åÇø 
	 
	while(1)
	{
		HAL_Delay(10);
		IWDG_Feed();		//ι¹· ÄÚ²¿¿´ÃŹ·
		SP706SE_WDOG;		//ι¹· Íⲿ¿´ÃŹ·
		 
		DBG_WARN("APP..."); 
		
		USART_Receive_Data(&huart1,rx_buffer,&rx_buffer_len);
		if(rx_buffer_len>0)
		{
			ModbusTask();
		} 
	} 
}

void APP2Boot(void)
{
	uint16_t otaStatus=0; 
	STMFLASH_Read(FLASH_OTA_STATUS_ADDR,&otaStatus,1);//¶ÁÈ¡µ±Ç°OTA״̬  
	if(otaStatus==1)
	{  
		DBG_DEBUG("APP2Boot");
		iap_load_app(FLASH_BOOT_ADDR);//Ìøת»ØBOOT³ÌÐò 
	}
}

void ModbusTask(void)
{
	uint16_t crc;
	uint8_t cmd;
	
	if(rx_buffer[0] == 0x09)	                        
	{
		crc = CRC16(rx_buffer, rx_buffer_len -2);
		if(crc == ((rx_buffer[rx_buffer_len-1]<<8)|rx_buffer[rx_buffer_len-2]))//УÑéCRC
		{
			cmd = rx_buffer[1];
			switch(cmd)
			{
				case 0x03:
					Modbus_Function_3();     
				break;
				case 0x10:
					Modbus_Function_10();
				break; 
			}
		} 
	} 
}

//¶Á¶à¸ö¼Ä´æÆ÷
void Modbus_Function_3(void)   
{
	u16 reg_addr;
	u16 reg_count; 
	u16 crc16;  
	u16 index=3;
	reg_addr = (rx_buffer[2]<<8) + rx_buffer[3];
	reg_count = (rx_buffer[4]<<8) + rx_buffer[5]; 
	if(reg_addr == 0xFF00 && reg_count == 0x0001)								
	{ //¶ÁÈ¡µ±Ç°OTA״̬ 
		uint16_t otaStatus=0; 
		index=3;
		STMFLASH_Read(FLASH_OTA_STATUS_ADDR,&otaStatus,1);
		tx_buffer[index++] = otaStatus>>8;
		tx_buffer[index++] = otaStatus;
	}
	if(reg_addr == 0xFF02 && reg_count == 0x0001)
	{ //¶ÁÈ¡¹Ì¼þ°æ±¾
		uint16_t softwareVersion=0;
		index=3;
		STMFLASH_Read(FLASH_SOFTWARE_VERSION_ADDR,&softwareVersion,1);
		tx_buffer[index++] = softwareVersion>>8;
		tx_buffer[index++] = softwareVersion;
	}
	if(reg_addr == 0xFF04 && reg_count == 0x0002)
	{ //¶ÁÈ¡¹Ì¼þ´óС
		_W2Byte softwareLength;
		index=3;
		STMFLASH_Read(FLASH_SOFTWARE_LENGTH_ADDR,softwareLength.w,2);
		tx_buffer[index++] = softwareLength.b[0];
		tx_buffer[index++] = softwareLength.b[1];
		tx_buffer[index++] = softwareLength.b[2];
		tx_buffer[index++] = softwareLength.b[3];
	}
	
	tx_buffer[0] = rx_buffer[0];//modbusµØÖ·
	tx_buffer[1] = 0x03;
	tx_buffer[2] =  index-3; //×Ö½ÚÊý
	
	crc16 = CRC16(tx_buffer, index);
	tx_buffer[index++] = crc16;
	tx_buffer[index++] = crc16>>8;
	HAL_UART_Transmit(&huart1, tx_buffer, index, 3000); 
}

//дÈë¶à¼Ä´æÆ÷
void Modbus_Function_10(void)           
{
	u16 reg_addr, reg_count;
	u16 crc16, i;  
	
	reg_addr = (rx_buffer[2]<<8) + rx_buffer[3];
	reg_count = (rx_buffer[4]<<8) + rx_buffer[5];  
	
	if(reg_addr == 0xFF00 && reg_count == 0x0001)  
	{	//дOTA״̬   
		uint16_t otaStatus=0; 
		otaStatus = (rx_buffer[7]<<8) + rx_buffer[8];
		STMFLASH_Write(FLASH_OTA_STATUS_ADDR,&otaStatus,1);
		DBG_DEBUG("дOTA STATUS : %d",otaStatus);
		APP2Boot();
	}   
	
	for(i = 0; i < 6; i++)
		tx_buffer[i] = rx_buffer[i];
	
	crc16 = CRC16(tx_buffer, 6);
	tx_buffer[6] = crc16;
	tx_buffer[7] = crc16>>8; 
	
	HAL_UART_Transmit(&huart1, tx_buffer, 8, 3000); 
}  

/* 
 * º¯ÊýÃû£ºCRC16
 * ÃèÊö  : ¼ÆËãCRC16
 * ÊäÈë  £ºaData---Êý¾Ý£¬ aSize---Êý¾Ý³¤¶È
 * Êä³ö  : УÑéÖµ
 */
uint16_t CRC16(uint8_t *ptr,uint16_t len)
{
	 unsigned char i;
	 unsigned short crc = 0xFFFF;
	 if(len==0)
	 {
		 len = 1;
	 }
	 while(len--) 
	 {
		 crc ^= *ptr;
		 for(i=0; i<8; i++)
		 {
			 if(crc&1)
			 {
				 crc >>= 1;
				 crc ^= 0xA001;
			 }
			 else
			 {
					crc >>= 1;
			 }
		 }
		 ptr++;
	 }
	 return(crc);
} 


           
基于“ModBus写文件”实现STM32串口IAP升级固件(下)

继续阅读