STM32 OTA Bootloader部分 demo流程学习

这篇具有很好参考价值的文章主要介绍了STM32 OTA Bootloader部分 demo流程学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

学习依据的源文链接:STM32 OTA应用开发——自制BootLoader

前言

什么是OTA?

OTA是“Over-the-Air”(空中升级)的缩写,指的是通过无线通信网络(如Wi-Fi、蓝牙、LoRa等)对嵌入式系统进行远程升级或更新。

在嵌入式系统中,OTA技术可以用于更新固件、软件或配置文件等。通过OTA技术,用户可以在不需要物理接触设备的情况下,对其进行升级和更新,从而提高系统的可靠性、安全性和灵活性。

----------我的理解:

所谓的OTA其实就是通过一些无线通信协议的方式,向嵌入式系统发送应用程序(以下简称APP)和升级指令,再由单片机设备上的BootLoader完成:接收新APP---擦除旧APP---写入新APP---跳转到新APP执行 的过程;

这个demo的实际上是通过USB的连接实现上述的APP升级过程,虽然有线连接不能严格称做OTA,但是二者的差异实际上只是不同(有线与无线)的通信传输过程,主要是学习程序升级的流程,故下文也将USB升级过程视为OTA升级;

什么是BootLoader?

BootLoader是一段程序,通常位于嵌入式系统的非易失性存储器(如Flash)中,用于在系统启动时加载和运行操作系统或其他应用程序。

在嵌入式系统中,BootLoader通常是一个小型的程序,主要负责以下几个方面的工作:

  1. 初始化硬件环境:BootLoader需要初始化硬件环境,包括CPU、存储器、外设、时钟等,以便系统能够正常运行。
  2. 加载操作系统或应用程序:BootLoader需要从存储器中加载操作系统或应用程序,并将控制权转交给操作系统或应用程序。
  3. 检查和修复系统错误:BootLoader需要检查系统的状态和完整性,以确保系统能够正常运行。如果发现系统错误,BootLoader需要尝试修复或恢复系统。
  4. 提供调试和测试功能:BootLoader可以提供调试和测试功能,例如单步执行、断点调试、查看寄存器状态等,以方便开发人员进行调试和测试。

而这个demo是通过自制bootloader,实现加载应用程序和OTA的功能;

BootLoader的OTA功能工作原理

MCU要实现OTA离不开Bootloader,它是一段引导程序,在OTA过程中,MCU启动时会先运行BootLoader,Bootloader会去判断是否需要升级,如果不需要升级就跳转到APP分区运行用户代码,如果需要升级则先通过一些硬件接口接收和搬运要升级的新固件,然后再跳转到APP分区运行新固件,从而实现OTA升级。

stm32 ota,stm32,学习,嵌入式硬件

 

BootLoader的OTA功能常见分区介绍

在没有加入Bootloader之前,MCU内部的flash可以看作一整块分区,我们运行的整个裸机程序都在其中:

stm32 ota,stm32,学习,嵌入式硬件

第一种分区方式——加入BootLoader,那么原本的Flash分区就可以划分为两个区域,Bootloader和Application,这种分区方式的好处在于既可以OTA升级,App又可以分到较大的空间,缺点是没有存放新固件的区域,需要从外部导入进来,而且一旦传输的过程被异常打断,那么原有的App代码也无法正常运行了:

stm32 ota,stm32,学习,嵌入式硬件

第二种分区方式——在第一种分区方式的基础上,将原本独属于APP的Flash空间中再分出一块作为Download分区来存放新的APP(同下文的固件),这种方式的优点是新固件是先存放到Download区的,哪怕搬运的过程中出现异常中断的情况,也不会“变砖”,缺点是需要单独划分一块内存跟APP区差不多的区域用来存放新固件,变相的减少了APP区的空间,对于内存较小的单片机来说内存压力会比较大:

stm32 ota,stm32,学习,嵌入式硬件

 第三种分区方式——这种方式其实与第二种分区方式一样,只是它把原本存放新APP的空间用来存放OTA升级前的旧APP,相当于在升级之前先将旧APP备份到Application2区域,再通过外部导入新APP覆盖写入Application1区域,优点在于升级了新固件以后,还保留了原来的旧版固件,必要的时候还可以进行版本的回退:

stm32 ota,stm32,学习,嵌入式硬件

 第四种分区方式——这种方式基本上与第二种分区方式一样,只不过增加了一个区域用来存放OTA相关的一下参数和用户配置:

stm32 ota,stm32,学习,嵌入式硬件

BootLoader的制作

BootLoader的程序是从源文找到的参考的demo,下面的内容一方面整理Bootloader的编写过程,一方面也会去详细解析Bootloader的源代码执行流程

以上述的第四种分区方式去编写Bootloader,参考demo使用的设备是STM32F103,内存128K,其内存分区表如下:

name offset size
Bootloader 0x08000000 0x00003000
Setting 0x08003000 0x00001000
Application 0x08004000 0x0000E000
Download 0x08012000 0x0000E000

其中0x08000000是内存起始地址,那么128K大小的内存空间的结束地址为0x0801FFFF,最后Download分区为0x08012000+0x0000E000 - 0x1 =0x0801FFFF,这四个部分将128K的内存空间全部分配完成;

这里记录一下地址空间与大小的计算过程:0x0801FFFF - 0x08000000 + 0x1 = 0x00020000,即0x20000个byte的空间,转换成十进制就是131072 bytes,而 128 * 1024 = 131072,所以是128K内存空间;

BootLoader功能简述:
  1. Bootloader启动;
  2. 从Setting中读取参数,确定是否需要升级;
    • 需要升级——把Download分区固件搬运到Application分区;
    • 不需要升级——直接跳转到Application分区;

新固件的下载传输过程,在App里面去处理,这里不做拓展;

源码解析

主要针对demo中的main.c、bootloader.c、bootloader.h中的内容进行流程解析,源码中涉及到的flash、uart等原本ST驱动中带有的外设控制接口只做简要说明;

main.c

#include "hardware.h"
#include "bootloader.h"
#include "flash.h"
#include "type.h"

void print_boot_message(void)
{
    printf("---------- Enter BootLoader ----------\r\n");
    printf("\r\n");
    printf("======== flash pration table =========\r\n");
    printf("| name     | offset     | size       |\r\n");
    printf("--------------------------------------\r\n");
    printf("| boot     | 0x08000000 | 0x00003000 |\r\n");
    printf("| setting  | 0x08003000 | 0x00001000 |\r\n");
    printf("| app      | 0x08004000 | 0x0000E000 |\r\n");
    printf("| download | 0x08012000 | 0x0000E000 |\r\n");
    printf("======================================\r\n");
}

int main() 
{
    process_status process;
    uint16_t i;
    uint8_t boot_state;
    uint8_t down_buf[128];
    uint32_t down_addr;
    uint32_t app_addr;

    uart1_init();
    print_boot_message();

    boot_parameter.process = read_setting_boot_state();
    boot_parameter.addr = APP_SECTOR_ADDR;

    while (1) 
    {
        process = get_boot_state();
        switch (process) 
        {
            case START_PROGRAM:
                printf("start app...\r\n");
                delay_ms(50);
                if (!jump_app(boot_parameter.addr)) 
                {
                    printf("no program\r\n");
                    delay_ms(1000);
                }
                printf("start app failed\r\n");
                break;
            case UPDATE_PROGRAM:
                printf("update app program...\r\n");
                app_addr = APP_SECTOR_ADDR;
                down_addr = DOWNLOAD_SECTOR_ADDR;

                printf("app addr: 0x%08X \r\n", app_addr);
                printf("down addr: 0x%08X \r\n", down_addr);

                printf("erase mcu flash...\r\n");
                mcu_flash_erase(app_addr, APP_ERASE_SECTORS);  
                printf("mcu flash erase success\r\n");
            
                printf("write mcu flash...\r\n");
                // memset(down_buf, 0, sizeof(down_buf));
                for (i = 0; i < APP_ERASE_SECTORS * 8; i++)
                {
                    mcu_flash_read(down_addr, &down_buf[0], 128);
                    delay_ms(5);
                    mcu_flash_write(app_addr, &down_buf[0], 128);
                    delay_ms(5);
                    down_addr += 128;
                    app_addr += 128;
                    // printf("mcu_flash_write: %d\r\n", i);
                }
                printf("mcu flash write success\r\n");

                set_boot_state(UPDATE_SUCCESS);
                break;
            case UPDATE_SUCCESS:
                printf("update success\r\n");
                boot_state = UPDATE_SUCCESS_STATE;
                write_setting_boot_state(boot_state);
                set_boot_state(START_PROGRAM);
                break;
            default:
                break;
        }
    }
}
  1. 在bootloader的主函数中,首先初始化了uart串口方便输出log信息,再调用print_boot_message()输出分区信息表(main.c line29~30);
  2. 之后调用read_setting_boot_state()(bootloader.c line32~48)将0x08003000也就是Setting地址空间中存放的状态值读取赋值给boot_parameter.process,再把APP首地址0x08004000赋值给boot_parameter.addr作为后面跳转到APP程序的准备(main.c line32~33),而boot_parameter是bootloader.c定义的全局变量(bootloader.c line3),用于存放bootloader的相关参数与状态;
  3. 进入到while(1)的流程当中,针对boot_parameter.process的三种状态:START_PROGRAM、UPDATE_PROGRAM、 UPDATE_SUCCESS执行对应逻辑,也就是启动APP、升级APP、升级成功;
  4. 启动APP的case(main.c line40~49)当中,除开log信息,主要是调用jump_app()接口(bootloader.c line5~16)跳转到APP程序,而传入的参数就是APP程序的起始地址0x08004000;如果APP起始地址无程序,才会继续执行下面的log输出,不然就直接跳转到APP的程序当中,bootloader执行就结束了;
  5. 升级APP的case(main.c line50~77)当中,先按页擦除flash中APP地址区块(main.c line59)将旧APP清除,然后再从Download地址区块开始每128byte读取数据再写到APP地址区块中(main.c line64~73),最后把bootloader的状态置为UPDATE_SUCCESS,下次循环进入UPDATE_SUCCESS的case执行;
  6. 升级成功的case(main.c line78~83)当中,调用write_setting_boot_state()接口(bootloader.c line 50~64)将升级成功的标志UPDATE_SUCCESS_STATE写入到地址0x08003000也就是Setting地址空间,下一次循环就会在步骤2中走到步骤4的流程,从而启动APP;

至此,bootloader的OTA过程状态机形成闭环

bootloader.c文章来源地址https://www.toymoban.com/news/detail-763504.html

#include "bootloader.h"

boot_t boot_parameter = {START_PROGRAM, 0, 0, 0};

uint8_t jump_app(uint32_t app_addr) 
{
    uint32_t jump_addr;
    jump_callback cb;
    if (((*(__IO uint32_t*)app_addr) & 0x2FFE0000 ) == 0x20000000) {  
        jump_addr = *(__IO uint32_t*) (app_addr + 4);  
        cb = (jump_callback)jump_addr;  
        __set_MSP(*(__IO uint32_t*)app_addr);  
        cb();
        return 1;
    } 
    return 0;
}

void set_boot_state(process_status process) 
{
    boot_parameter.process = process;
}

process_status get_boot_state(void) 
{
    process_status process;
    process = boot_parameter.process;

    return process;
}

process_status read_setting_boot_state(void)
{
	process_status process;
	uint8_t boot_state;
    mcu_flash_read(SETTING_BOOT_STATE, &boot_state, 1);
    // printf("boot_state: %d \r\n", boot_state);
 
    if(boot_state != UPDATE_PROGRAM_STATE)
    {
       process = START_PROGRAM;
    }
    else
    {
       process = UPDATE_PROGRAM;
    }
	return process;
}

uint8_t write_setting_boot_state(uint8_t boot_state)
{
	uint8_t result;
	result = mcu_flash_erase(SETTING_BOOT_STATE, 1);
	if(result)
	{
		result = mcu_flash_write(SETTING_BOOT_STATE, &boot_state, 1);
		if(result != 1)
		{
			return result;
		}
	}
    
	return result;
}

到了这里,关于STM32 OTA Bootloader部分 demo流程学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32-OTA升级-基于STM32CubeMX+STM32F103(一)基础知识

    0 引言 对于一个项目而言,往往将远程升级作为程序的最后一步(基本所有功能都开发完成之后再考虑)。但是在我看来,我们在写单片机的程序之前,就要规划好FLASH的使用情况,因为code、全局变量等重要信息都是放在FLASH(常说的闪存)中的,SRAM是程序运行时的存放位置

    2024年02月04日
    浏览(51)
  • 调试笔记-stm32的OTA/IAP 通过485升级固件

    背景:最近需要在stm32上实现通过rs485升级固件功能。经过几天搜索和调试,实现了功能。 目标:使用cubeIDE实现stm32F407VGT6,通过RS485升级固件 调试记录: 步骤1. 在keil环境下的rs485升级固件(含源码):STM32 OTA应用开发——通过串口/RS485实现OTA升级(方式2)_stm32串口升级_柒壹漆

    2024年02月11日
    浏览(48)
  • STM32_通过Ymodem协议进行蓝牙OTA升级固件教程

    作为单片机进阶能力,IAP升级固件的学习是非常重要的。 想直接看如何操作的从第三条开始看。 蓝牙OTA(Over-The-Air)升级是指通过蓝牙无线技术,对设备中的固件或软件进行远程升级和更新的过程。蓝牙OTA升级在现代物联网和智能设备领域有着重要的应用和意义。 重要性:

    2024年02月04日
    浏览(42)
  • stm32 esp8266 ota升级-qt bin文件处理工具

    stm32 esp8266 ota系列文章: stm32 esp8266 ota-快速搭建web服务器之docker安装openresty stm32 esp8266 ota升级-tcp模拟http stm32 esp8266 ota升级-hex合并-烧录-bin生成 stm32 esp8266 ota升级-qt bin文件处理工具 stm32 esp8266 ota升级-自建mqtt和文件服务器动态AB面方式 stm32 esp8266 ota升级-自建mqtt和文件服务器全

    2024年02月05日
    浏览(78)
  • gd32f103vbt6 串口OTA升级5-combin部分

    本文主要是bin文件的组成进行一些简单介绍,方便理解升级的过程。 2.1 rk3399cpu+gd32f103 2.2 连接方式:串口(115200,8N1)或者iic(本文没有介绍iic) 3.1 单片机端分两个部分:iap(用于升级)和app(自己的应用)部分(这两个部分本文不做介绍)。 3.2 linux端做一个升级的app软件

    2024年02月16日
    浏览(55)
  • gd32f103vbt6 串口OTA升级3-linux端的部分

    本文主要是对linux端升级单片机程序的功能部分做一些介绍,包括一些软件流程。 2.1 rk3399cpu+gd32f103 2.2 连接方式:串口(115200,8N1)或者iic(本文没有介绍iic) 3.4.1  0 ~(0x5c00-1) : iap程序区,用于存放iap程序 3.4.2  0x5c00~(0x6000-1) : 这个1k用于存放一些标志位,以及程序的

    2024年02月17日
    浏览(67)
  • 【RT-Thread】使用RT-Thread Studio 配置BootLoader及App实现OTA功能

    由于项目需要实现OTA功能学习了一下具体实现方法,以备后期查看,有问题的地方随时指正修改 1.什么是OTA OTA是“over-the-air”的缩写,是一种无线技术,用于在不需要接触设备的情况下向移动设备或物联网设备提供更新、补丁或新版本的软件。OTA更新通常通过无线网络(如

    2024年02月09日
    浏览(38)
  • ESP32 OTA升级之https ota详解

    本文以 ESP32 官方demo例程 native_ota_example 为例,详细阐述如何采用https实现esp32的ota升级。 第一章节,为本文的前言部分,对文章内容进行大体概述; 第二章节,主要描述了如何在本地将demo例程跑起来,并附带了关于使用demo例程中遇到的相关报错的具体解决措施; 第三章节,

    2024年02月14日
    浏览(38)
  • STM32 usart bootloader 源代码 STM32 usart bootloader 源代码 STM32 usart bootloader 原代源码

    STM32 usart bootloader 源代码   STM32 usart bootloader 源代码  STM32 usart bootloader 原代源码,上位机C#,下位机c。 简单修改可以支持stm32全系列芯片。 支持串口升级 该版本为优化过的版本, 1.支持代码段保护; 2.支持烧写失败重置; 3.兼容我公司生产的配套wifi模块和w5500模块远程更新

    2024年01月23日
    浏览(44)
  • STM32duino-bootloader:STM32的开源Bootloader深入解析

    STM32微控制器广泛应用于各种嵌入式系统。一个常见的需求是能够远程更新固件,而这通常是通过Bootloader来实现的。在本文中,我们将深入解析一个叫做STM32duino-bootloader的开源项目,它为STM32微控制器提供了一个USB DFU (Device Firmware Upgrade) bootloader。 STM32duino-bootloader简介 STM32d

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包