STM32后备寄存器在OTA升级中的妙用

一、后备寄存器介绍

1、STM32后备寄存器概述

后备寄存器(Backup Registers)是STM32微控制器中一组特殊的存储单元,用于在系统掉电或复位时保存关键数据。这些寄存器通过后备电源(如电池)供电,确保数据在低功耗模式下或主电源失效时不会丢失。

2、后备寄存器的特点

  • 掉电保持:通过VBAT引脚连接后备电源(如3V电池),在主电源关闭时保持数据。
  • 独立访问:需通过RTC或备份域接口访问,避免意外修改。
  • 数量与位宽:不同型号的STM32后备寄存器数量不同(如STM32F1系列有20个16位寄存器,STM32F4系列有32个32位寄存器)。

3、启用后备寄存器的步骤

  1. 使能电源和备份接口时钟
    通过RCC寄存器使能PWR和BKP(或BKPSRAM)时钟:

    __HAL_RCC_PWR_CLK_ENABLE();
    
  2. 允许访问备份域
    调用库函数解除备份域的写保护:

    HAL_PWR_EnableBkUpAccess();
    
  3. 配置RTC时钟(可选)
    若需RTC功能,需配置时钟源:

    RCC_RTCCLKConfig(RCC_RTCCLKSource_HSE_Div128);
    RCC_RTCCLKCmd(ENABLE);
    
  4. 读写后备寄存器
    通过库函数或直接访问寄存器读写数据:

    HAL_RTCEx_BKUPWrite(BKP_DR1, 0xA5A5); // 写入数据
    uint16_t data = HAL_RTCEx_BKUPRead(BKP_DR1); // 读取数据
    

4、注意事项

  • 电源管理:确保VBAT电源稳定,避免数据丢失。
  • 复位影响:除电源复位或VBAT断电外,后备寄存器数据通常不会清除。
  • 寄存器用途:部分寄存器可能被RTC或硬件占用,需查阅手册确认。

5、典型应用场景

  • 系统配置保存:存储校准参数或设备设置。
  • RTC相关数据:保存时间戳或闹钟配置。
  • 低功耗模式:在待机模式下记录唤醒事件。

二、OTA升级中的妙用

在OTA升级中我们可以使用后备寄存器在程序复位后值不复位的特性来判断是否进入bootloader更新程序。具体流程如下:

1、升级逻辑对比

一般 Bootloader 实现的逻辑如下:
在这里插入图片描述
这种方式适合于简单的裸机程序或可控的 OS 程序(即所有外设硬件都可把控),在准备环境的时候将其全部关闭。
但对于一些复杂的或者 OS 中轮子已造好的程序,有一些因素不花时间研究无法把控,在准备环境时很可能就会遗漏一些未关闭导致出各种各样的问题。
使用后备寄存器逻辑如下:
在这里插入图片描述
该方法可以使 Bootloader 就作为一个 OS 应用程序开发,需要跳转的时候就操作一下寄存器并软件复位即可。不会造成bootloaderapp同时设置寄存器值的情况。

2、实现是否进入bootloader判断

值定义:

typedef enum
{
    bkpPowerOn = 	0x00000000,                //初次上电
    bkpStayBoot = 	0x5555AAAA,            //从APP层跳转过来需要停留
	bkpJumpToApp = 	0xA5A55555,				//直接跳转到APP
	bkpUpgrade = 	0x5555A5A5,				//需要进入bootloader升级
    bkpMax,
}bkpTypedef;
typedef void (*boot_app_func)(void);
void ota_start_application(void) 
{
    __HAL_RCC_RTC_ENABLE();
	__HAL_RCC_PWR_CLK_ENABLE();

    HAL_PWR_EnableBkUpAccess();

    RTC_HandleTypeDef RTC_Handler = {0};
    RTC_Handler.Instance = RTC;
    uint32_t bkpData = HAL_RTCEx_BKUPRead(&RTC_Handler, BKP_UPGRADE_ADDR);
    //HAL_RTCEx_BKUPWrite(&RTC_Handler, OTA_BKP_ADDR, bkpPowerOn);
	

    if (bkpData != bkpJumpToApp) return;
	
	
    boot_app_func app_func = NULL;
    uint32_t app_addr = APP_START_ADDR;
    if (((*(__IO uint32_t *)(app_addr + 4)) & 0xff000000) != 0x08000000) 
	{
		HAL_RTCEx_BKUPWrite(&RTC_Handler, BKP_UPGRADE_ADDR, bkpStayBoot);
		return;
	}

    /* 栈顶地址在 128K RAM 间 */
    if (((*(__IO uint32_t *)app_addr) - 0x20000000) >= (STM32_SRAM_SIZE * 1024)) 
	{
		HAL_RTCEx_BKUPWrite(&RTC_Handler, BKP_UPGRADE_ADDR, bkpStayBoot);
		return;
	}

    app_func = (boot_app_func) * (__IO uint32_t *)(app_addr + 4);
    /* Configure main stack */
    __set_MSP(*(__IO uint32_t *)app_addr);
    /* jump to application */
    app_func();
}

然后在void SystemInit(void)函数中调用此函数:

void SystemInit(void)
{
	extern void ota_start_application(void);
	ota_start_application();
#if defined(USER_VECT_TAB_ADDRESS)
  /* Configure the Vector Table location -------------------------------------*/
  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;
#endif

  /* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
  SCB->CPACR |= ((3UL << 20U)|(3UL << 22U));  /* set CP10 and CP11 Full Access */
#endif
}

这样做的好处是系统上电如果不需要更新程序可以直接跳转到APP,避免在bootloader中对一些寄存器的初始化。
防止跳转到APP重复对寄存器赋值造成的问题。
SystemInit函数执行时机:
SystemInit函数通常在STM32启动过程中由启动文件(startup_stm32fxxx.s)调用,具体执行时机如下:

  1. 启动阶段执行
    SystemInit函数在处理器复位后,由启动代码(startup_stm32xxxx.s)自动调用,在进入main函数之前完成基本的时钟系统配置。

  2. 调用位置
    该函数定义在system_stm32fxxx.c文件中,由汇编启动文件中的Reset_Handler直接调用。以下是典型调用流程:
    在这里插入图片描述

  3. 执行内容
    SystemInit函数主要完成以下初始化工作:

  • 设置中断向量表位置
  • 配置FPU(如果启用)
  • 初始化时钟系统(HSE/MSI/HSI等时钟源选择)
  • 配置Flash等待周期
  • 设置系统时钟频率

3、bootloader更新完成后怎么做

bootloader更新完程序以后我们需要清除后备寄存器中的更新标记值,直接执行复位就可以,如下:

static void ota_jump_app(void) 
{
    __disable_irq();
    RTC_HandleTypeDef RTC_Handler = {0};
    RTC_Handler.Instance = RTC;
    HAL_RTCEx_BKUPWrite(&RTC_Handler, BKP_UPGRADE_ADDR, bkpJumpToApp);
    HAL_NVIC_SystemReset();
}

程序复位以后其他寄存器的值就会被初始化,然后重新进入bootloader执行ota_start_application函数直接跳转到APP

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小灰灰搞电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值