国民技术N32G430开发笔记(14)-IAP升级 usart2接收数据

news2024/11/18 23:38:20

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【移动端网页布局】流式布局案例 ⑥ ( 多排按钮导航栏 | 设置浮动及宽度 | 设置图片样式 | 设置文本 )

文章目录 一、多排按钮导航栏样式及核心要点1、实现效果2、总体布局设计3、设置浮动及宽度4、设置图片样式5、设置文本 二、完整代码实例1、HTML 标签结构2、CSS 样式3、展示效果 一、多排按钮导航栏样式及核心要点 1、实现效果 要实现下面的导航栏效果 ; 2、总体布局设计 该导…

计算机网络笔记:DNS域名解析过程

基本概念 DNS是域名系统&#xff08;Domain Name System&#xff09;的缩写&#xff0c;也是TCP/IP网络中的一个协议。在Internet上域名与IP地址之间是一一对应的&#xff0c;域名虽然便于人们记忆&#xff0c;但计算机之间只能互相认识IP地址&#xff0c;域名和IP地址之间的转…

基于探路者算法的极限学习机(ELM)回归预测-附代码

基于探路者算法的极限学习机(ELM)回归预测 文章目录 基于探路者算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于探路者算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用探路者算法对极限学习机进行优化&…

算法 DAY45 动态规划07 70. 爬楼梯 322. 零钱兑换 279. 完全平方数 139. 单词拆分 多重背包

70. 爬楼梯 和377. 组合总和 Ⅳ (opens new window)基本就是一道题了。本题代码不长&#xff0c;题目也很普通&#xff0c;但稍稍一进阶就可以考察完全背包 class Solution { public:int climbStairs(int n) {vector<int> nums {1,2};vector<int> dp(n1,0);dp[0…

while语句和until语句顺便带点小实验

while语句和until语句 一、while用法二、Until循环语句三、趣味小实验猜价格的游戏&#xff08;价格是随机数&#xff09;写一个计算器脚本闲来无事去购物 一、while用法 for循环语句非常适用于列表对象无规律&#xff0c;且列表来源以固定&#xff08;如某个列表文件&#xf…

Android Studio开发图书管理系统APP

Android Studio开发项目图书管理系统项目视频展示&#xff1a; 点击进入图书管理系统项目视频 引 言 现在是一个信息高度发达的时代&#xff0c;伴随着科技的进步&#xff0c;文化的汲取&#xff0c;人们对于图书信息的了解与掌握也达到了一定的高度。尤其是学生对于知识的渴…

word构建基块:快速插入重复内容的高级剪切板

本文参考自 word录入技巧&#xff1a;如何用自动图文集快速插入重复内容 - 知乎 介绍 构建基块&#xff0c;它就是和剪切板一样&#xff0c;点一下就粘贴一份新的&#xff0c;用于解决大量重复内容的复制粘贴 构建基块包括自动图文集和快速表格&#xff0c;实际上都是构建基块…

Blender启动场景的修改

Blender启动场景的修改 1 使用版本2 现象描述3 解决方法4 启动场景路径5 清理场景资源5.1 空场景大小5.2 清理图片资源5.2.1 断开数据块关联5.2.2 断开伪用户关联5.2.3 断开多用户关联5.2.4 清理数据块5.2.6 文件校验 5.3 使用自建资源库 6 数据块类型 1 使用版本 Blender 3.3…

二叉树建立、遍历、打印(23春教学)

#include<stdio.h> #include <malloc.h> #include <conio.h> typedef char DataType; typedef struct Node {DataType data;struct Node *LChild;struct Node *RChild; }BitNode,*BitTree; void CreatBiTree(BitTree *bt)//用扩展先序遍历序列创建二叉树&am…

《LearnUE——基础指南:上篇—3》——GamePlay架构WorldContext,GameInstance,Engine之间的关系

目录 平行世界是真实存在的吗&#xff1f; 1.3.1 引言 1.3.2 世界管理局&#xff08;WorldContext&#xff09; 1.3.3 司法天神&#xff08;GameInstance&#xff09; 1.3.4 上帝&#xff08;Engine&#xff09; 1.4 总结 平行世界是真实存在的吗&#xff1f; 1.3.1 引言 …

DAY 51 LVS负载均衡——DR模式

数据包流向分析 &#xff08;1&#xff09;客户端发送请求到Director Server (负载均衡器)&#xff0c;请求的数据报文&#xff08;源IP是CIP&#xff0c;目标IP是VIP&#xff09;到达内核空间。 &#xff08;2&#xff09;Director Server 和Real Server 在同一个网络中&…

【五一创作】ERP实施-委外业务-委外采购业务

委外业务主要有两种业务形态&#xff1a;委外采购和工序外协&#xff0c;委外采购主要是在MM模块中实现&#xff0c;工序外协主要由PP模块实现&#xff0c;工序外协中的采购订单创建和采购收货由MM模块实现。 委外采购概念 委外采购&#xff0c;有些企业也称为带料委外或者分包…

【Spring框架全系列】方法注解@Bean的使用

&#x1f4ec;&#x1f4ec;哈喽&#xff0c;大家好&#xff0c;我是小浪。上篇博客我们介绍了五大类注解的使用方法&#xff0c;以及如何解决Spring使用五大类注解生成bean-Name的问题&#xff1b;那么&#xff0c;谈到如何更简单的读取和存储对象&#xff0c;这里我们还需要介…

如何防止系统发生异常时,别人传递过来的关键数据不丢失?(AOP + xxlJob)

需求 在开发中&#xff0c;客户每天需要定时调用我们的api去上传一些数据到数据库中&#xff0c;当数据库发生异常或者系统发生异常&#xff0c;上传的一些数据会丢失不做入库操作&#xff0c;现想防止数据库或系统发生异常&#xff0c;数据能不丢失&#xff0c;同时&#xff…

TryHackMe-AD证书模板

AD Certificate Templates SpecterOps 完成并作为白皮书发布的研究表明&#xff0c;可以利用配置错误的证书模板进行权限提升和横向移动。根据错误配置的严重性&#xff0c;它可能允许 AD 域上的任何低特权用户只需单击几下即可将其权限提升为企业域管理员的权限&#xff01; …

C语言宏使用

C语言宏 编译一个C语言程序的第一步骤就是预处理阶段&#xff0c;这一阶段就是宏发挥作用的阶段,编译完之后宏对二进制代码不可见。 使用 1. 宏常量 #define PI 3.142. 宏语句 #define Print printf("hello,world!\r\n")3. 宏函数 使用宏来定义函数&#xff0c…

基于灰狼算法的极限学习机(ELM)回归预测-附代码

基于灰狼算法的极限学习机(ELM)回归预测 文章目录 基于灰狼算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于灰狼算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用灰狼算法对极限学习机进行优化&#xff0c;并…

[stable-diffusion-art] 指北-3 inpainting

https://stable-diffusion-art.com/inpainting_basics/https://stable-diffusion-art.com/inpainting_basics/inpainting的应用主要是重绘&#xff0c;目前的模型换衣主要还是通过lora训练特定衣服来实现的。 模型权重&#xff1a; !wget https://huggingface.co/runwayml/sta…

一、spring Cloud Alibaba概述

spring Cloud Alibaba学习&#xff0c;第一篇spring Cloud Alibaba概述篇。 微服务是一种架构思想&#xff0c;spring Cloud Alibaba是微服务的系列化实现方式之一。 一、架构演变过程 架构粒度更加精细&#xff0c;拆分成不同的服务&#xff0c;每个服务直接互不影响&#…

基于海鸥算法的极限学习机(ELM)回归预测-附代码

基于海鸥算法的极限学习机(ELM)回归预测 文章目录 基于海鸥算法的极限学习机(ELM)回归预测1.极限学习机原理概述2.ELM学习算法3.回归问题数据处理4.基于海鸥算法优化的ELM5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;本文利用海鸥算法对极限学习机进行优化&#xff0c;并…