引言
在嵌入式系统设计中,低功耗与数据完整性往往相互制约。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 时钟配置
-
使能 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); - 配置系统时钟:正常运行时使用 HSE+PLL,进入 STOP 前无需切换,因为 STOP 会关闭它们。
3.2 RTC 配置
-
使能 PWR 时钟:访问电源控制寄存器。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); -
配置 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); - 使能 RTC 中断:在 NVIC 中配置。
3.3 DMA 配置(以 ADC 为例)
- 初始化 ADC:配置为连续转换或外部触发。
-
配置 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 唤醒中断中:
- 清除中断标志。
- 重新配置系统时钟(如果使用 HSE/PLL,需重新初始化)。
- 重新使能 DMA 并启动传输。
- 处理数据(如存储到 Flash 或发送)。
- 再次进入 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 模式下实现低功耗与数据采集的平衡。本文提供的方案适用于周期性数据记录场景,如环境监测、可穿戴设备等。开发者可根据实际需求调整唤醒周期和采样率,进一步优化功耗。记住,低功耗设计是一个系统工程,需从硬件到软件全面考虑。