程序升级bootloader

文章目录

      • 概述
      • 什么是bootloader?为什么用?
      • bootloader启动流程图
        • 步骤
      • 下载过程
      • 代码
        • 获取本地配置信息
        • 获取主机传过来的配置信息
        • bootloader发送2给上位机,上位机发送文件给bootloader
        • 根据网站复制CRC
      • 烧写flash
        • erase
        • 启动
        • 编译问题

概述

用keil编写app,来用bootloader更新app,完成灯闪烁指令,升级app的新版本就是灯闪烁的更快了;
通过usb直接传输更新的配置给开发板,然他自己启动bootloder,擦除原来的app和配置信息,烧录新的app和配置信息;
image.png
image.png

什么是bootloader?为什么用?

运行时,bootloader会先启动,如果有程序升级,bootloader从RAM里面下数据烧录到flash的一块空间上面,就是app;
其中突然断电没烧录完也没事,bootloader等下次启动又会重新烧录,如果没有bootloader,app不是完整的也不能直接启动,就不能用了;
原本没有bootloader怎么运行的:
RAM如果很小,里面不会去在复制一个app进去,问题就是此时上点时是flash的app程序在从RAM下载烧录数据到flash的app,这直接把自己覆盖了呀,那会出错的;
image.png
RAM如果很大,那RAM存一个APP,运行是就用RAM的APP,然后把升级的app数据下载烧录到flash上把他覆盖,这样就不会出现上面的问题了,但是断电就会导致flash上的APP没烧录完整,下次通电先打开flash就打不开了;
通电先执行flash;
image.png
image.png

bootloader启动流程图

STM32H563RIV
image.png
image.png

cpu是ARM公司生产的,他们设定只能从0开始读,因此要设置映射关系,让cpu一开始在flash的地址0x0800 0000;
1、cpu从0开始读4个字节存入sp寄存器;
2、cpu从4这个地址读到4个字节存入pc寄存器
image.pngimage.png

发生中断时:
硬件会做的事:在异常向量表里面找到函数,执行
我们需要操作的是:告诉cpu异常向量表的基地址
image.png
下图为有无bootloader的异常向量表的首地址
image.png
要把这个//,因为这个是异常向量表,是flash开头的异常向量表
image.png
把flash开始烧录的地址移到0804000,前面的给bootloader;
image.png

步骤

image.png
传进来的参数是存在寄存器R0里面的;
把R0的数据写入寄存器VTOR
把R0的数值存入R1所指向的位置;
VTOR保存的是异常向量表的基地址;
image.png
从R0这里读取R1;
把R1的数值写给栈SP寄存器;
image.png
跳转到R0+4的位置

下载过程

1、bootloader发送“1”字符给上位机,请求固件信息;
2、上位机给bootloader发送固件信息:先发同步字符;
image.png
上位机发送的固件信息
a、长度信息
b、加载地址
c、校验码
d、文件名
e、版本号
image.png
3、bootloader决定升级
发送0x02给上位机;
4、上位机发送bin文件给bootloader
收到后bootloader会(1)计算CRC校验码,(2)与之前收到的固件信息比较;
5、bootloader开始烧写,同时可以发送烧写进度给上位机

生成设备信息
用这个create_firemware_info来生成脚本
image.png

代码

获取本地配置信息

#define CFG_OFFSET 0x081FE000//设备地址

file_len是判断配置信息有没有写
image.png

获取主机传过来的配置信息

image.png
先是usb传输发送1;
接收上机回应信号5个0x5a;
接收上机设备配置信息32个寄存器;
image.png

bootloader发送2给上位机,上位机发送文件给bootloader

上位机发送文件时就会发送一系列的数据,超时时间*10,给上位机充分时间发送
image.png

根据网站复制CRC

image.png

bootloaderTask
这里任务要等待一会
因为usb插到电脑上,要等电脑识别出来usb,才能进行传输,
image.png

获取固件失败的原因?
数据丢失,上位机发送数据给bootloader,是不是数据没有接收全,数据覆盖了,数据丢失了;
先看是不是数据接收不全,怎么看呢,我们是创建队列来接收的,队列初始化时的大小看一下,能不能装得下;
找到usb传输的队列只有200bit,但是传输的数据有5kb ,5x1024bit,把队列改成10kb=10240bit
image.png
image.png
BootTask整体流程:
无标题.png

#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os2.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "draw.h"
#include "stdio.h"
#include "draw.h"
#include "ux_api.h"
#include "modbus.h"
#include "errno.h"
#include "uart_device.h"
#include "semphr.h"

#include "bootloader.h"

#define UPDATE_TIMEOUT 1000//超时时间

#define CFG_OFFSET 0x081FE000

static struct UART_Device *g_pUpdateUART;


static uint32_t BE32toLE32(uint8_t *buf)
{
 return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | ((uint32_t)buf[2] << 8) | ((uint32_t)buf[3] << 0);
}


static int GetLocalFirmwareInfo(PFirmwareInfo ptFirmwareInfo)
{
	PFirmwareInfo ptFlashInfo = (PFirmwareInfo)CFG_OFFSET;
    if (ptFlashInfo->file_len == 0xFFFFFFFF)
        return -1;

    *ptFirmwareInfo = *ptFlashInfo;

	return 0;
}

static int GetServerFirmwareInfo(PFirmwareInfo ptFirmwareInfo)
{
	uint8_t data = '1';
	uint8_t buf[sizeof(PFirmwareInfo)];

	/*send 0x01 cmd to pc*/
	if(0 != g_pUpdateUART->Send(g_pUpdateUART, &data, 1, UPDATE_TIMEOUT))
		return -1;

	/*wait for response*/
	while(1)
	{
		if(0 != g_pUpdateUART->RecvByte(g_pUpdateUART, &data, UPDATE_TIMEOUT*10))
			return -1;

		if(data != 0x5a)
		{
			buf[0] = data;
			break;
		}
	}

	for(int i = 1; i < sizeof(PFirmwareInfo); i++)
	{
		if(0 != g_pUpdateUART->RecvByte(g_pUpdateUART, &buf[i], UPDATE_TIMEOUT))
			return -1;
		
	}

    ptFirmwareInfo->version = BE32toLE32(&buf[0]);
    ptFirmwareInfo->file_len = BE32toLE32(&buf[4]);
    ptFirmwareInfo->load_addr = BE32toLE32(&buf[8]);
    ptFirmwareInfo->crc32 = BE32toLE32(&buf[12]);
    strncpy((char *)ptFirmwareInfo->file_name, (char *)&buf[16], 16);

    return 0;



}

static int GetServerFirmware(uint8_t *buf, uint32_t len)
{
	uint8_t data = '2';


	/*send 0x01 cmd to pc*/
	if(0 != g_pUpdateUART->Send(g_pUpdateUART, &data, 1, UPDATE_TIMEOUT))
		return -1;

	/*上位机发送文件给bootloader*/
	for(int i = 0; i < len; i++)
	{
		if(0 != g_pUpdateUART->RecvByte(g_pUpdateUART, &buf[i], UPDATE_TIMEOUT*10))
			return -1;
	}
	return 0;
}

/* https://lxp32.github.io/docs/a-simple-example-crc32-calculation/ */
static int GetCRC32(const char *s,size_t n)
{
    uint32_t crc=0xFFFFFFFF;

    for(size_t i=0;i<n;i++) {
            char ch=s[i];
            for(size_t j=0;j<8;j++) {
                    uint32_t b=(ch^crc)&1;
                    crc>>=1;
                    if(b) crc=crc^0xEDB88320;
                    ch>>=1;
            }
    }

    return ~crc;
}





void BootLoaderTask( void *pvParameters )	
{
    struct UART_Device *pUSBUART = GetUARTDevice("usb");
    FirmwareInfo tLocalInfo;
    FirmwareInfo tServerInfo;
    int err;
    int need_update = 0;
    uint8_t *firmware_buf;

    vTaskDelay(10000); /* wait for pc ready */
    pUSBUART->Init(pUSBUART, 115200, 'N', 8, 1);

    g_pUpdateUART = pUSBUART;

    while (1)
    {
        /* read cfg info, to detect app's version */
        err = GetLocalFirmwareInfo(&tLocalInfo);
        if (err)
        {
            /* update */
            need_update = 1;
        }
        else
        {
            pUSBUART->Send(pUSBUART, (uint8_t *)"GetLocalFirmwareInfo Failed\r\n", strlen("GetLocalFirmwareInfo Failed\r\n"), UPDATE_TIMEOUT);
        }

        err = GetServerFirmwareInfo(&tServerInfo);

        if (!err)
        {
            /* compate version */
            if (tServerInfo.version > tLocalInfo.version)
            {
                /* update */
                need_update = 1;
            }
        }
        else
        {
            need_update = 0;
            pUSBUART->Send(pUSBUART, (uint8_t *)"GetServerFirmwareInfo Failed\r\n", strlen("GetServerFirmwareInfo Failed\r\n"), UPDATE_TIMEOUT);
        }


        if (need_update)
        {
            firmware_buf = pvPortMalloc(tServerInfo.file_len);
            if (!firmware_buf)
            {
                /* error */
                pUSBUART->Send(pUSBUART, (uint8_t *)"Malloc Failed\r\n", strlen("Malloc Failed\r\n"), UPDATE_TIMEOUT);
            }
            
            err = GetServerFirmware(firmware_buf, tServerInfo.file_len);
            if (!err)
            {
                /* calc CRC */                
                uint32_t crc = GetCRC32((const char *)firmware_buf, tServerInfo.file_len);
                if (crc == tServerInfo.crc32)
                {
                    /* OK */
                    /* burn */
                    pUSBUART->Send(pUSBUART, (uint8_t *)"Download OK\r\n", 13, UPDATE_TIMEOUT);
                }
                else
                {
                    pUSBUART->Send(pUSBUART, (uint8_t *)"GetCRC32 Failed\r\n", strlen("GetCRC32 Failed\r\n"), UPDATE_TIMEOUT);
                }
            }
            else
            {
                pUSBUART->Send(pUSBUART, (uint8_t *)"GetServerFirmware Failed\r\n", strlen("GetServerFirmware Failed\r\n"), UPDATE_TIMEOUT);
            }
        }
        else
        {
            /* start app */
        }
        
    }
}

烧写flash

对比flash上面的版本比主机发过来的版本小,或者flash上面的配置信息坏了,就启动升级:
1、erase 擦除flash
2、烧写

flash有两个栈区,bank1和bank2 128个栈区x 每个栈区8k
把中间蓝色圈APP擦除再烧录,只是更新APP,以及把配置文件的信息改成对应的最新的;
image.png

erase

image.png
1、擦除app并烧录
擦除bank1和bank2的APP的,APP的长度可能延伸到了bank2有if进行判断,传入的地址是bootloader后的,也就是APP开头地址
3.png
2、擦除配置文件并烧录
image.png
3、bootloadertask
下载完成主机发送过来的配置文件就用1、2这两个函数进行擦除烧录;
image.png

启动

触发软件复位
1.png
复位最终会调用main
image.png
如果是复位的话就会得到flash上面这个应用程序的基地址,然后调用这个汇编函数start_app来启动程序
2.png
注意:
image.png

编译问题

non-ASCLL表示引入了中文字符
image.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Halcon 产品周围缺口检测

*读取一张图像read_image (Image, 原图.jpg)*获取图像大小get_image_size(Image, Width, Height)*关闭已经打开的窗口dev_close_window ()*打开新窗口dev_open_window(0, 0, Width, Height, black, WindowHandle) //打开指定大小的窗口*对图像进行阈值操作threshold (Image, R…

【eMTC】eMTC 窄带以及带宽的关系

1 概述 eMTC 传输进行通信时&#xff0c;一般采用1.4M带宽&#xff0c;在和LTE小区联合部署时&#xff0c;需要将LTE的带宽分割成以1.4M带宽为粒度的单位&#xff0c;这个单位在协议上叫做窄带。 2 窄带定义 3 参考文献 36.211

图片高效管理神器,随机高度切割,一键生成灰色图片,个性化处理随心所欲

在数字化时代&#xff0c;图片已成为我们生活和工作中不可或缺的一部分。然而&#xff0c;面对海量的图片资源&#xff0c;如何高效管理、快速处理&#xff0c;成为了许多人头疼的问题。今天&#xff0c;我们为您带来了一款全新的图片高效管理神器_——首助编辑高手&#xff0c…

【沐风老师】3DMAX样条线增强工具SplinePro使用方法详解

3DMAX样条线增强工具SplinePro使用教程 3DMAX样条线增强工具SplinePro&#xff0c;允许创建选定的多条样条曲线形状的轮廓并删除交叉点。 【适用版本】 3dMax2019 - 2025 【安装方法】 1.解压缩后&#xff0c;确认SplinePro-0.2.0.mse和logo.png两个文件在同一文件夹中。 2.…

python+django 环境搭建以及post接口封装

1、搭建pythondjango环境 python 3.7.9的版本 具体参考之前的安装教程 django 使用 pip install django 会自动安装 检验安装版本&#xff1a; python -m django --version 2、创建django项目 django-admin startproject projectname 启动项目&#xff1a;python manage.py…

verilog读写文件注意事项

文章目录 想要的16进制数是文本格式提供的文件&#xff0c;想将16进制数提取到变量内&#xff0c;想要的16进制数是文本格式提供的文件&#xff0c;想将16进制数提取到变量内&#xff0c;想要的16进制数是二进制格式提供的文件&#xff0c;想将16进制数提取到变量内&#xff0c…

大模型在营销领域的探索及创新

1 AIGA介绍 2 AIGA在营销领域的 应用和探索 3 总结与展望

【WPF】桌面程序开发之xaml页面基础布局方式详解

使用Visual Studio开发工具&#xff0c;我们可以编写在Windows系统上运行的桌面应用程序。其中&#xff0c;WPF&#xff08;Windows Presentation Foundation&#xff09;项目是一种常见的选择。然而&#xff0c;对于初学者来说&#xff0c;WPF项目中xaml页面的布局设计可能是一…

MySQL8.0在windows下的下载安装及详细使用

下载mysql8.0二进制包 下载地址&#xff1a;MySQL :: Download MySQL Community Server 编辑my.ini配置文件 解压二进制包&#xff0c;新建/编辑my.ini配置文件(如果不存在则新建) [client] #客户端设置&#xff0c;即客户端默认的连接参数 # 设置mysql客户端连接服务端时…

Python【打包exe文件两步到位】

Python打包Exe 安装 pyinstaller&#xff08;pip install pyinstaller&#xff09; 执行打包命令&#xff08;pyinstaller demo.py&#xff09; 打完包会生成 dist 文件夹&#xff0c;如下如

openrestry中的hello world

目录 概述实践部署openrestry脚本效果验证 概述 此篇将在 k8s 运行起一个 openrestry   环境&#xff1a;k8s&#xff1a;1.27.9 &#xff0c;openrestry(docker镜像版本)&#xff1a; 1.25.x &#xff0c;k8s 与 ingress 请参考我的其它文章 离线镜像包请参考&#xff1a;op…

2024暑假集训

Day1——枚举 Day2——测试 Day3——贪心 Day4、5——测试 ——————————————————————————————————————————— Day3T7&Day5T7:没思路 Day3T8:不知道怎么排序筛选 Day5T5:没有算法难度&#xff0c;但是不知道怎么处理2队奶牛的情…

【TB作品】51单片机 Proteus仿真 超声波LCD1602ADC0832 身高体重测量仪

00024 超声波LCD1602ADC0832 实验报告&#xff1a;基于51单片机的身高体重测量仪设计 背景介绍 本实验设计并实现了一个基于51单片机的身高体重测量仪。该系统利用超声波传感器测量高度&#xff0c;通过ADC0832模数转换芯片获取重量数据&#xff0c;并使用LCD1602显示屏显示…

MySQL 中的 DDL、DML、DQL 和 DCL

文章目录 1. 数据定义语言&#xff08;DDL&#xff09;2. 数据操作语言&#xff08;DML&#xff09;3. 数据查询语言&#xff08;DQL&#xff09;4. 数据控制语言&#xff08;DCL&#xff09;总结 在 MySQL 数据库管理系统中&#xff0c;SQL 语句可以根据其功能分为不同的类别&…

电源纹波相关

什么是纹波&#xff1f;什么是噪声&#xff1f; 这种叠加在直流稳定量上的交流分量就称为纹波。 纹波的危害 电源纹波能影响设备性能和稳定性 纹波会导致电器上产生谐波&#xff0c;降低电源的使用效率&#xff1b; 高频电源纹波可能会产生浪涌电压或电流&#xff0c;影响设…

VSCode神仙插件——CodeSnap (好看的代码截图)

1 安装 2 使用 选中要截图的代码,右键 此时右侧会出现代码截图的预览图 如果要将截图保存到本地,则点击上图红色框中的图标 也可以点击下面截的图,CtrlC复制,然后就可以CtrlV粘贴到其他应用程序里了

拉曼光谱入门:3.拉曼光谱的特征参数与定量定性分析策略

1.特征参数 1.1 退偏振率 退偏振率&#xff08;p&#xff09;是一个衡量拉曼散射光偏振状态的参数&#xff0c;它描述了拉曼散射光的偏振方向与入射光偏振方向之间的关系。退偏振率定义为垂直偏振方向的拉曼散射强度与平行偏振方向的拉曼散射强度之比。退偏振率&#xff08;p&…

shark云原生-日志体系-filebeat高级配置(适用于生产)-更新中

文章目录 1. filebeat.inputs 静态日志收集器2. filebeat.autodiscover 自动发现2.1. autodiscover 和 inputs2.2. 如何配置生效2.3. Providers 提供者2.4. Providers kubernetes2.5. 配置 templates2.5.1. kubernetes 自动发现事件中的变量字段2.5.2 配置 templates 2.6. 基于…

微信小程序简历Demo

微信小程序简历Demo 使用介绍最后获取源码 bilibili视频介绍 使用介绍 使用微信小程序实现的一个简历实现Demo 拖动马里奥&#xff0c;到指定Name下方 向上顶就可以显示对应的简历样式 点击头像可拨打电话 点击信息处可显示当前位置 最后 这是一个简单并且有趣的微信小程…

el-table 树形数据与懒加载 二级数据不展示

返回的数据中 children和hasChildren只能有一个&#xff0c;不能同时存在&#xff0c;否则加载数据会失败