引言

在工业控制、物联网设备等嵌入式应用中,STM32F4 凭借高性能和丰富外设被广泛使用。RTC(实时时钟)通常依赖 LSE 晶振提供精准时基,但 LSE 可能因外部干扰、焊接不良或老化而停振。一旦 LSE 停振,RTC 时间会停止,系统可能因检测到时钟故障而触发复位。若复位后系统无法恢复之前的运行状态(如通信协议状态、传感器校准值、任务进度),将导致严重后果。

本文提出一种基于 RTC 备份寄存器的无痕复位恢复方案:在 LSE 停振中断中,将关键状态写入备份寄存器;复位后,系统启动时读取这些寄存器,判断是否因 LSE 故障复位,并恢复现场。该方案无需外部存储,利用 STM32F4 内部资源,实现快速、可靠的恢复。

原理剖析

1. LSE 停振检测机制

STM32F4 的 RTC 模块包含 LSE 时钟安全系统(LSE CSS)。当使能 LSE CSS 后,若 LSE 振荡停止,硬件会自动产生一个中断(RTC_LSECSS_IRQn)。该中断触发时,LSE 已被强制关闭,RTC 时钟切换到 LSI(内部低速时钟)或直接停止,同时系统可配置为复位(通过 RTC_CR 寄存器的 LSECSSR 位)。

关键点:

  • 中断标志:RTC_ISR 中的 LSECSSF 位(LSE CSS 中断标志)。
  • 复位行为:若在 RTC_CR 中设置 LSECSSR=1,则 LSE 停振会触发系统复位;若为 0,则仅产生中断,系统继续运行(但 RTC 时间可能不准)。
  • 备份寄存器:RTC 的 20 个 32 位备份寄存器(BKPxR)在 VDD 供电时保持内容,系统复位(包括软件复位和 LSE 故障复位)不会清除,但掉电会丢失。

2. 无痕复位恢复设计

设计目标:当 LSE 停振导致复位时,系统重启后能恢复到复位前的运行状态。

实现思路:

  • 在正常运行中,周期性或事件驱动地将关键状态(如运行模式、计数值、标志位)写入备份寄存器。
  • 使能 LSE CSS 并配置为复位模式,同时开启中断(用于在复位前执行保存操作)。
  • 在 LSE CSS 中断服务函数中,将当前状态写入备份寄存器(作为最后保障)。
  • 系统启动时,检查备份寄存器中的特定魔数(Magic Number),若匹配,则表明发生了 LSE 故障复位,恢复保存的状态;否则为正常上电复位,执行初始化。

配置步骤

1. 使能 LSE 和 RTC 时钟

使用 STM32CubeMX 或手动配置:

  • 使能 LSE(外部低速晶振,通常 32.768kHz)。
  • 使能 RTC,选择 LSE 作为时钟源。
  • 使能 RTC 备份寄存器访问(PWR 和 RTC 时钟)。

2. 配置 LSE CSS

在 RTC_CR 寄存器中:

  • 设置 LSECSSE=1(使能 LSE CSS)。
  • 设置 LSECSSR=1(使能复位模式)。
  • 在 NVIC 中使能 RTC_LSECSS_IRQn 中断。

3. 编写中断服务函数

在中断中保存状态到备份寄存器,并清除标志。

4. 启动恢复逻辑

在 main 函数初始化阶段,读取备份寄存器判断复位原因。

完整代码示例

以下代码基于 STM32F407,使用 HAL 库。

#include "stm32f4xx_hal.h"

// 魔数,用于标记备份寄存器有效
#define MAGIC_NUMBER 0xA5A5A5A5

// 备份寄存器索引
#define BKP_MAGIC_IDX 0
#define BKP_STATE_IDX  1
#define BKP_COUNTER_IDX 2

// 全局变量,模拟运行状态
typedef enum {
    STATE_IDLE,
    STATE_RUNNING,
    STATE_PAUSED
} SystemState;

SystemState currentState = STATE_IDLE;
uint32_t runCounter = 0;

// 保存状态到备份寄存器
void SaveStateToBackup(void) {
    HAL_RTC_BackupStorageWrite(&hrtc, BKP_MAGIC_IDX, MAGIC_NUMBER);
    HAL_RTC_BackupStorageWrite(&hrtc, BKP_STATE_IDX, (uint32_t)currentState);
    HAL_RTC_BackupStorageWrite(&hrtc, BKP_COUNTER_IDX, runCounter);
}

// 从备份寄存器恢复状态
void RestoreStateFromBackup(void) {
    if (HAL_RTC_BackupStorageRead(&hrtc, BKP_MAGIC_IDX) == MAGIC_NUMBER) {
        currentState = (SystemState)HAL_RTC_BackupStorageRead(&hrtc, BKP_STATE_IDX);
        runCounter = HAL_RTC_BackupStorageRead(&hrtc, BKP_COUNTER_IDX);
        // 清除魔数,避免重复恢复
        HAL_RTC_BackupStorageWrite(&hrtc, BKP_MAGIC_IDX, 0);
    } else {
        // 正常上电复位,初始化默认值
        currentState = STATE_IDLE;
        runCounter = 0;
    }
}

// LSE CSS 中断服务函数
void RTC_LSECSS_IRQHandler(void) {
    // 保存当前状态(最后保障)
    SaveStateToBackup();
    // 清除中断标志
    __HAL_RTC_LSECSS_CLEAR_FLAG(&hrtc, RTC_FLAG_LSECSSF);
    // 注意:由于配置了复位模式,此中断后系统将复位,但保存操作已完成
}

// RTC 初始化(简化)
void RTC_Init(void) {
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_RCC_RTC_ENABLE();
    HAL_PWR_EnableBkUpAccess();

    RTC_HandleTypeDef hrtc = {0};
    hrtc.Instance = RTC;
    hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
    hrtc.Init.AsynchPrediv = 127;
    hrtc.Init.SynchPrediv = 255;
    hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
    hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
    HAL_RTC_Init(&hrtc);

    // 使能 LSE CSS 并配置复位模式
    __HAL_RTC_LSECSS_ENABLE(&hrtc);
    __HAL_RTC_LSECSS_ENABLE_RESET(&hrtc);
    HAL_NVIC_SetPriority(RTC_LSECSS_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(RTC_LSECSS_IRQn);
}

int main(void) {
    HAL_Init();
    SystemClock_Config();
    RTC_Init();

    // 恢复状态
    RestoreStateFromBackup();

    // 主循环
    while (1) {
        // 模拟运行状态变化
        runCounter++;
        if (runCounter % 100 == 0) {
            currentState = (currentState == STATE_RUNNING) ? STATE_PAUSED : STATE_RUNNING;
        }
        // 周期性保存状态(例如每 10ms)
        if (runCounter % 10 == 0) {
            SaveStateToBackup();
        }
        HAL_Delay(10);
    }
}

注意事项

  • 备份寄存器掉电丢失:备份寄存器在 VDD 供电时保持,但若系统完全断电,内容会丢失。因此该方案适用于复位(非掉电)场景,若需掉电保持,需使用 VBAT 供电的备份域。
  • 中断优先级:LSE CSS 中断应设为高优先级,确保在复位前能及时执行保存操作。
  • 清除魔数:恢复后清除魔数,避免重复恢复导致状态错误。
  • LSE 恢复:若 LSE 停振后系统复位,但硬件故障未排除,可能再次触发复位。建议在恢复后检查 LSE 状态,若仍异常,可切换到 LSI 并报警。
  • HAL 库版本:不同 HAL 库版本对 LSE CSS 的支持略有差异,请参考对应手册。
  • 测试验证:实际测试时,可人为断开 LSE 晶振或短路,观察系统是否按预期复位并恢复状态。

总结

通过利用 RTC 备份寄存器和 LSE 时钟安全系统,STM32F4 在 LSE 停振导致复位后,能够无痕恢复运行状态,极大提升了系统的鲁棒性。本文提供的方案代码简洁,易于集成,适用于对可靠性要求高的嵌入式应用。开发者可根据实际需求扩展保存更多状态,实现更复杂的恢复逻辑。