引言

在嵌入式系统设计中,低功耗与数据完整性往往相互制约。STM32F4 系列凭借其丰富的外设和灵活的电源管理,成为许多便携式设备的首选。STOP 模式是 STM32F4 低功耗策略中的关键一环,它关闭大部分时钟,但保留 SRAM 和寄存器内容,功耗可低至 10µA 左右。然而,要在 STOP 模式下保持 RTC 计时并让 DMA 持续采集传感器数据,需要精心的时钟配置和外设协作。本文将带你一步步实现这一方案。

1. 原理剖析:STOP 模式下的外设行为

1.1 STOP 模式概述

STOP 模式基于 Cortex-M4 内核的 SLEEPDEEP 机制。进入 STOP 后,所有时钟(包括 HSE、HSI、PLL)均被关闭,但以下模块保持供电:

  • SRAM 和寄存器:内容不丢失。
  • RTC:若使用 LSI 或 LSE 作为时钟源,可继续运行。
  • 备份域:包括备份寄存器、RTC 等。
  • 部分 GPIO:可配置为唤醒源。

关键点:DMA 在 STOP 模式下默认停止,因为其时钟(AHB/APB)被关闭。但我们可以通过外部事件RTC 唤醒来短暂唤醒系统,执行 DMA 传输,再重新进入 STOP,实现“间歇性采集”。

1.2 RTC 与 DMA 的协作策略

  • RTC 唤醒:配置 RTC 闹钟或唤醒定时器,周期性产生唤醒事件(如每 1 秒)。
  • DMA 采集:唤醒后,系统时钟恢复,DMA 可快速将 ADC 或传感器数据搬运到内存,然后再次进入 STOP。
  • 数据缓存:使用双缓冲或环形缓冲区,避免数据覆盖。

2. 硬件准备

  • 开发板:STM32F407 Discovery 或类似板卡
  • 传感器:如 MPU6050(I2C 接口)或内部 ADC 采样
  • 工具:STM32CubeIDE 或 Keil MDK

3. 配置步骤

3.1 时钟配置

  1. 使能 LSE 或 LSI:RTC 需要独立时钟源。推荐使用 LSE(32.768kHz),精度更高。
    RCC_BackupResetCmd(ENABLE);
    RCC_LSEConfig(RCC_LSE_ON);
    while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
    RCC_RTCCLKCmd(ENABLE);
    
  2. 配置系统时钟:正常运行时使用 HSE+PLL,进入 STOP 前无需切换,因为 STOP 会关闭它们。

3.2 RTC 配置

  1. 使能 PWR 时钟:访问电源控制寄存器。
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
    
  2. 配置 RTC 唤醒定时器
    RTC_WakeUpCmd(DISABLE);
    RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits); // 1Hz 计数
    RTC_SetWakeUpCounter(1); // 1 秒唤醒
    RTC_WakeUpCmd(ENABLE);
    RTC_ITConfig(RTC_IT_WUT, ENABLE);
    
  3. 使能 RTC 中断:在 NVIC 中配置。

3.3 DMA 配置(以 ADC 为例)

  1. 初始化 ADC:配置为连续转换或外部触发。
  2. 配置 DMA:将 ADC 数据寄存器映射到内存缓冲区。
    DMA_InitTypeDef DMA_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    DMA_DeInit(DMA2_Stream0);
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)adc_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_Init(DMA2_Stream0, &DMA_InitStructure);
    DMA_Cmd(DMA2_Stream0, ENABLE);
    

3.4 进入 STOP 模式

在进入 STOP 前,确保 DMA 已停止(或暂停),然后执行:

PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);

注意:进入 STOP 后,DMA 时钟关闭,传输会暂停。唤醒后需重新使能。

3.5 唤醒处理

在 RTC 唤醒中断中:

  1. 清除中断标志。
  2. 重新配置系统时钟(如果使用 HSE/PLL,需重新初始化)。
  3. 重新使能 DMA 并启动传输。
  4. 处理数据(如存储到 Flash 或发送)。
  5. 再次进入 STOP。

4. 完整代码示例

以下代码演示了核心逻辑(基于标准外设库):

// 全局变量
uint16_t adc_buffer[128];
volatile uint8_t wakeup_flag = 0;

void RTC_WKUP_IRQHandler(void) {
    if (RTC_GetITStatus(RTC_IT_WUT) != RESET) {
        RTC_ClearITPendingBit(RTC_IT_WUT);
        wakeup_flag = 1;
    }
}

void SystemClock_Config(void) {
    // 配置 HSE、PLL,使能 FLASH 预取等(略)
}

void ADC_DMA_Config(void) {
    // 初始化 ADC1 和 DMA2_Stream0(见上文)
}

void Enter_StopMode(void) {
    // 停止 DMA 传输
    DMA_Cmd(DMA2_Stream0, DISABLE);
    // 进入 STOP 模式
    PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
    // 唤醒后重新配置系统时钟
    SystemClock_Config();
    // 重新使能 DMA
    DMA_Cmd(DMA2_Stream0, ENABLE);
}

int main(void) {
    // 初始化时钟、RTC、ADC、DMA、NVIC
    SystemClock_Config();
    RTC_Config();
    ADC_DMA_Config();
    NVIC_Config();

    while (1) {
        Enter_StopMode();
        if (wakeup_flag) {
            wakeup_flag = 0;
            // 处理采集到的数据(此时 DMA 已重新使能,但需等待传输完成)
            // 例如:存储到外部 Flash 或通过 UART 发送
        }
    }
}

5. 注意事项

  • 时钟恢复:从 STOP 唤醒后,系统时钟默认使用 HSI,若需高性能,必须重新配置 PLL。
  • DMA 缓冲管理:使用双缓冲时,注意切换时机,避免数据覆盖。
  • RTC 时钟源:LSE 在低功耗下更稳定,但 LSI 无需外部晶振,适合成本敏感设计。
  • 唤醒源:除了 RTC,还可配置 EXTI 外部引脚唤醒,但需注意 GPIO 状态。
  • 调试:在 STOP 模式下,SWD 调试可能失效,建议使用串口打印调试信息。
  • 功耗测量:实际功耗受 GPIO 漏电流影响,未使用的引脚应配置为模拟输入或下拉。

6. 总结

通过合理配置 RTC 唤醒和 DMA 传输,STM32F4 可以在 STOP 模式下实现低功耗与数据采集的平衡。本文提供的方案适用于周期性数据记录场景,如环境监测、可穿戴设备等。开发者可根据实际需求调整唤醒周期和采样率,进一步优化功耗。记住,低功耗设计是一个系统工程,需从硬件到软件全面考虑。