IAP升级 Usart2接收数据
1、之前有一节我们将PA6 PA7复用成了usart2的功能,这一节我们用usart2接收来自树莓派的升级请求,然后完成N32G430的Iap升级。
2、接线
PA9 PA10 接usb转串口模块A,A模块插入电脑。
PA6 PA7 接usb转串口模块B,B模块插入树莓派。
3、数据协议
串口升级协议如下:
cmd + data_lenght + data0 + …+ datax + checksum
1、获取版本号 0x01 0x02 0x00 0x00 checksum
2、升级
1、进入升级模式 0x02 0x02 0x00 0x00 checksum
2、升级文件大小 0x03 0x04 0x00 0x00 0x00 0x00 checksum
3、数据包发送 0x04 0x80 0x00 0x00 0x00 0x00 … checksum
4、数据包发送完成 0x05 0x02 0x00 0x00 checksum
checksum采用crc16的检验方法。
4、升级流程
1、树莓派发送进入升级模式命令,mcu进入升级模式,此时led1灯由1000ms闪烁一次变为100ms闪烁一次。
2、树莓派发送文件大小命令,mcu接收到文件大小命令,保存,并将download区域擦除。
3、树莓派分包发送升级文件数据,每包数据64个字节,mcu接收到数据后,分包写入download区域。
4、树莓派发送升级完成命令后,mcu将update_flag置为1,并重启mcu。
5、重启后,mcu进入bootloader后,读取update_flag,如果为1,将download区域数据拷贝到App区域,然后跳转到App执行,完成App区域的升级。如果update_flag不为1,不用拷贝,直接跳转APP。
5、Usart2的中断处理函数修改为:
相关逻辑处理放到了handle_uart_message函数里
static uint8_t RxBuffer1[128];//接收数据缓存区
static uint32_t RxCounter1 = 0;//接收数据长度
void USART2_IRQHandler(void)
{
if (USART_Interrupt_Status_Get(USART2, USART_INT_RXDNE) != RESET)
{
/* 读取数据并清除标志 */
USART_Interrupt_Status_Clear(USART2,USART_INT_RXDNE);
RxBuffer1[RxCounter1++] = USART_Data_Receive(USART2);
}
else if (USART_Interrupt_Status_Get(USART2, USART_INT_IDLEF) != RESET)
{
/* 清除IDLE标志*/
USART_Interrupt_Status_Clear(USART2,USART_INT_IDLEF);
if (RxCounter1 > 0)
{
handle_uart_message(RxBuffer1,RxCounter1);
RxCounter1 = 0;
}
}
}
4、Common目录下增加Update目录,并创建update.c update.h,
协议的解析都在update.c中处理。
#include <string.h>
#include "main.h"
#include "update.h"
#include "usart.h"
#include "settings.h"
#include "log.h"
#include "flash.h"
#include "core_cm4.h"
/*串口升级协议如下:
cmd + data_lenght + data0 + ....+ datax + checksum
1、获取版本号 0x01 0x02 0x00 0x00 checksum
2、升级
1、进入升级模式 0x02 0x02 0x00 0x00 checksum
2、升级文件大小 0x03 0x04 0x00 0x00 0x00 0x00 checksum
3、数据包发送 0x04 0x80 0x00 0x00 0x00 0x00 ..... checksum
4、数据包发送完成 0x05 0x02 0x00 0x00 checksum
*/
#define UPGRADE_DATA_PACKAGES_LENGHT 0x40
static MI_CHAR version[36] = {0};
static MI_U32 upgrade_file_size = 0;
static MI_U32 w_time = 0;
static MI_U16 packets_numer = 0;
static MI_U16 remain_packets_numer = 0;
static MI_U8 w_buff[UPGRADE_DATA_PACKAGES_LENGHT] = {0};
static void app_soft_reset(void)
{
__ASM volatile ("cpsid i");
NVIC_SystemReset();
}
static MI_U16 CRC16(MI_U8 * buf, MI_U16 len)
{
MI_U16 i;
MI_U16 crc = 0xffff;
if (len == 0) {
len = 1;
}
while (len--) {
crc ^= *buf;
for (i = 0; i<8; i++)
{
if (crc & 1) {
crc >>= 1;
crc ^= 0xA001;
}
else {
crc >>= 1;
}
}
buf++;
}
return(crc);
}
static MI_BOOL calculate_checksum_and_length(MI_U8 * buf, MI_U16 len)
{
MI_U16 crc16 = CRC16(buf,len-2);
if ((crc16 & 0x00ff) == buf[len-2] && ((crc16 >> 8) & 0x00ff) == buf[len-1])
{
if (buf[UART_CMD_LENGTH] == (len-2-2))
{
return MI_TRUE;
}
else
{
max_print("crc16 right ,but cmd error\r\n");
return MI_FALSE;
}
}
else
{
max_print("crc16 error and right crc16 = %x\r\n",crc16);
return MI_FALSE;
}
}
MI_BOOL handle_uart_message(MI_U8 *p_buff,MI_U32 len)
{
switch (p_buff[UART_CMD_INDEX])
{
case UART_GET_SYSTEM_VERSION_CMD/* constant-expression */:
/* 获取系统版本号 */
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
system_info_get_app_version(version);
Usart_SendString(USART2,(char *)version,strlen(version));
}
break;
case UART_ENTER_SYSTEM_UPDATE_MODE_CMD:
/* 进入升级模式命令 指示灯变为100ms闪烁一次*/
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
led_freq = LED_TOGGLE_100_MS;
w_time = 0;
packets_numer = 0;
upgrade_file_size = 0;
remain_packets_numer = 0;
isRunningUpdate = 1;
max_print("Mcu Receive Update Command and Wait Receive Data Packets \r\n");
max_print("Now to Erase Download Pages \r\n");
n32_flash_erase(DOWNLOAD_START_ADDRESS,DOWNLOAD_END_ADDRESS);
Usart_SendString(USART2,(char *)p_buff,len);
}
break;
case UART_GET_SYSTEM_FILE_SIZE_CMD:
max_print("Erase Download Pages \r\n");
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
int a = (int)p_buff[2];
int b = (int)p_buff[3];
int c = (int)p_buff[4];
int d = (int)p_buff[5];
upgrade_file_size = (a<<24) | (b<<16) | (c<<8) | (d);
if (upgrade_file_size % UPGRADE_DATA_PACKAGES_LENGHT == 0) //如果整除64
{
packets_numer = upgrade_file_size/UPGRADE_DATA_PACKAGES_LENGHT;
}
else
{
packets_numer = ((upgrade_file_size/UPGRADE_DATA_PACKAGES_LENGHT) + 1);
}
max_print("End Erase Download Pages Down\r\n");
max_print("\r\n");
max_print("receive upgrade file size %d\r\n",upgrade_file_size);
max_print("data packets number %d\r\n",packets_numer);
max_print("\r\n");
Usart_SendString(USART2,(char *)p_buff,len);
}
break;
case UART_RECEIVE_SYSTEM_UPDATE_CMD:
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
max_print("receive packets........................%d [100] \r\n",(((w_time + 1) * 100) / packets_numer));
memset(w_buff,0,sizeof(w_buff));
memcpy(w_buff,&p_buff[2],sizeof(w_buff));
n32_flash_write(DOWNLOAD_START_ADDRESS+(w_time * UPGRADE_DATA_PACKAGES_LENGHT),w_buff,sizeof(w_buff));
if (w_time + 1 == packets_numer)
{
led_freq = LED_TOGGLE_1000_MS;
max_print("receive packets........................ done!\r\n");
}
w_time ++;
Usart_SendString(USART2,(char *)p_buff,20);
}
break;
case UART_COMPLETE_SYSTEM_UPDATE_CMD:
if (calculate_checksum_and_length(p_buff,len) == MI_TRUE)
{
Usart_SendString(USART2,(char *)p_buff,len);
system_info_set_update_flag(1);
int flag;
system_info_get_update_flag(&flag);
max_print("Now Reboot %d!\r\n",flag);
app_soft_reset();
}
break;
default:
break;
}
return MI_TRUE;
}
update.h
#ifndef __UPDATE_H__
#define __UPDATE_H__
#define UART_CMD_INDEX 0x00
#define UART_CMD_LENGTH 0x01
#define I2C_CMD_INDEX 0x00
#define I2C_CMD_LENGTH 0x01
#define UART_GET_SYSTEM_VERSION_CMD_LENGTH 0x02
typedef enum uart_update_cmd
{
UART_GET_SYSTEM_VERSION_CMD = 0x01,
UART_ENTER_SYSTEM_UPDATE_MODE_CMD = 0x02,
UART_GET_SYSTEM_FILE_SIZE_CMD = 0x03,
UART_RECEIVE_SYSTEM_UPDATE_CMD = 0x04,
UART_COMPLETE_SYSTEM_UPDATE_CMD = 0x05,
}MI_UartUpdateCmd;
MI_BOOL handle_uart_message(MI_U8 *p_buff,MI_U32 len);
#endif
5、Bootloader 修改
#include <string.h>
#include "main.h"
#include "bsp_delay.h"
#include "flash.h"
#include "settings.h"
#include "log.h"
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
void Jump_To_App(uint32_t address)
{
if (((*(__IO uint32_t*)address) & 0x2FFE0000) == 0x20000000)
{
JumpAddress = *(__IO uint32_t*) (address + 4);
Jump_To_Application = (pFunction) JumpAddress;
__set_MSP(*(__IO uint32_t*) address);
Jump_To_Application();
}
}
int main(void)
{
MI_U8 update_flag;
SysTick_Delay_Ms(1000);
usart1_init();
system_info_get_update_flag(&update_flag);
max_print("system_info_get_update_flag == %d\r\n",update_flag);
max_print("\r\n");
if (update_flag == 1)
{
copy_download_to_app();
max_print("\r\n");
max_print("update success,and go to Application\r\n");
system_info_set_update_flag(0);
}
SysTick_Delay_Ms(1000);
Jump_To_App(APP_START_ADDRESS);
while(1)
{
SysTick_Delay_Ms(2000);
}
}
6、在falsh.c 增加copy_download_to_app()函数
MI_BOOL copy_download_to_app(void)
{
MI_U8 buffer[1024] = {0}; //每次从download读1K字节,然后写入1K
MI_U8 w_count = 0;
MI_U16 w_len = sizeof(buffer);
MI_U16 app_size = APP_SIZE;
w_count = app_size / w_len;
// 将App区域擦除
n32_flash_erase(APP_START_ADDRESS,APP_END_ADDRESS);
max_print("w_count == %d\r\n",APP_SIZE);
max_print("w_count == %d\r\n",w_len);
max_print("w_count == %d\r\n",w_count);
for (int i = 0;i < w_count;i++)
{
n32_flash_read(DOWNLOAD_START_ADDRESS + (w_len * i),buffer,w_len);
SysTick_Delay_Ms(50);
n32_flash_write(APP_START_ADDRESS + (w_len * i),buffer,w_len);
max_print("update.............................%d [100] \r\n",((i+1) * 100 /w_count));
}
return MI_TRUE;
}
7、整个升级的视频打印:
屏幕录制2023-05-03 14.16.12