STM32下位机这边分为两个程序,一个是BootLoader,一个是正常启动的APP
流程
正常启动流程
Created with Raphaël 2.3.0 开始 读取内部Flash OTA_STATUS==0? 跳转APP 等待固件升级 yes no
固件升级流程
上位机流程详情见上一篇博客
Created with Raphaël 2.3.0 接收串口数据(ModBus写寄存器) OTA_STATUS=1(修改内部Flash) 跳转回BootLoader
总的来说,下位机运行在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配置
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配置
生成bin文件
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);
}