You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32L476从STOP模式唤醒后ADC DMA无法工作问题求助

STM32L476 STOP模式RTC唤醒后ADC DMA失效问题解决

问题概述

STM32L476进入STOP模式经RTC唤醒后,ADC DMA无法工作,多次重新初始化无效。相关细节:

  • 芯片型号:STM32L476
  • 休眠模式:STOP模式,RTC唤醒
  • 唤醒后USB可重新初始化,终端通信正常
  • 仅STOP模式存在该问题,SLEEP模式下ADC DMA触发正常
  • 芯片可正常进入STOP模式并唤醒
  • 唤醒后寄存器状态:
    • ADC ISR=0x00000003, CR=0x10000005, CFGR=0x80001903
    • TIM3 CR1=0x0001, CNT=6606, SR=0x001f
  • ADC转换由TIM3事件触发,已启用DMA连续请求
  • 唤醒后读取ADCbuffer无更新,无ADC及DMA中断

相关代码

uint32_t ADCbuffer[14];  // DMA/ADC result buffer
static uint32_t tick = 0;
int main(void)
{
    /* USER CODE BEGIN 1 */

    /* USER CODE END 1 */

    /* MCU Configuration--------------------------------------------------------*/

    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();

    /* USER CODE BEGIN Init */

    /* USER CODE END Init */

    /* Configure the system clock */
    SystemClock_Config();

    /* Configure the peripherals common clocks */
    PeriphCommonClock_Config();

    /* USER CODE BEGIN SysInit */

    /* USER CODE END SysInit */

    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_DMA_Init();
    MX_ADC1_Init();
    MX_USART1_UART_Init();
    MX_TIM3_Init();
    MX_USB_DEVICE_Init();
    MX_RTC_Init();
    MX_TIM2_Init();
    MX_ADC2_Init();
    /* USER CODE BEGIN 2 */

    //BEEEEPPP
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
    htim2.Instance->CCR2 = htim2.Instance->ARR/2;
    HAL_Delay(200);
    htim2.Instance->CCR2 = 0;


    //Start the ADC and triggers
    //ADC1 regular conversions are triggered by timer3 which also gates the dividers
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
    htim3.Instance->CCR1 = htim3.Instance->ARR;
    htim3.Instance->CCR4 = 2000;

    GPIOB->ASCR |=0x01;

    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
    HAL_Delay(200);


    HAL_ADC_Start_DMA(&hadc1, ADCbuffer,14);
    __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_EOS);
    HAL_ADCEx_InjectedStart(&hadc2);

    uint8_t HiMsg[] = "hello\r\n";
    CDC_Transmit_FS(HiMsg, strlen(HiMsg));
    //Now we have a short delay to allow some initial readings to come in from the ADC
    HAL_Delay(500);

    /* USER CODE END 2 */

    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        if (HAL_GetTick() - tick > 30000)
        {
            tick = HAL_GetTick();
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, 0); //LED OFF
            HAL_SuspendTick();
            HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 20480, RTC_WAKEUPCLOCK_RTCCLK_DIV16); //32768/16 = 2048
            __disable_irq();
            HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
            __enable_irq();
            HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
            SystemClock_Config();
            HAL_ResumeTick();
            HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, 1); //LED ON
            // init ADC hereeee
            // ...
            MX_USB_DEVICE_Init();
            //Bip
            HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
            htim2.Instance->CCR2 = htim2.Instance->ARR/2;
            HAL_Delay(2);
            htim2.Instance->CCR2 = 0;
            HAL_Delay(2000);
            uint8_t HiMsg[] = "hello\r\n";
            CDC_Transmit_FS(HiMsg, strlen(HiMsg));
            HAL_Delay(50);
            HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2);
        }
        /* USER CODE END WHILE */

        /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
}

问题分析与解决方案

核心原因

STOP模式下,ADC和DMA的外设时钟会被关闭,唤醒后仅重新初始化系统时钟不足以恢复外设的正确状态,尤其是DMA的请求通道和ADC的触发配置可能处于异常状态。结合寄存器状态:

  • ADC ISR=0x00000003 表示ADRDY和EOS位置位,但后续无新转换,说明ADC未正确响应触发信号
  • TIM3 SR=0x001f 表示多个标志位(如UIF、CC1IF等)置位,残留标志阻塞了触发逻辑

修复步骤

  1. 唤醒后强制重置ADC和DMA外设
    先通过RCC寄存器重置外设,再执行初始化,确保外设回到初始状态:

    // 重置ADC1
    __HAL_RCC_ADC1_FORCE_RESET();
    HAL_Delay(1);
    __HAL_RCC_ADC1_RELEASE_RESET();
    // 重置DMA通道(根据实际使用的DMA通道修改,示例为DMA1)
    __HAL_RCC_DMA1_FORCE_RESET();
    HAL_Delay(1);
    __HAL_RCC_DMA1_RELEASE_RESET();
    // 重新初始化外设
    MX_DMA_Init();
    MX_ADC1_Init();
    
  2. 清除TIM3和ADC的所有挂起标志
    唤醒后先清除定时器和ADC的残留标志,避免触发逻辑被阻塞:

    __HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_ALL);
    __HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_ALL);
    
  3. 重新启动ADC DMA和定时器触发
    重置初始化后,重新执行校准、启动DMA转换和定时器PWM输出:

    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
    HAL_Delay(200);
    HAL_ADC_Start_DMA(&hadc1, ADCbuffer,14);
    __HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_EOS);
    // 重启TIM3所有PWM通道
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_3);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_4);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
    htim3.Instance->CCR1 = htim3.Instance->ARR;
    htim3.Instance->CCR4 = 2000;
    
  4. 优化STOP模式进入前的外设关闭流程
    进入STOP前主动关闭ADC DMA和定时器,避免外设处于半工作状态:

    // 进入STOP前关闭相关外设
    HAL_ADC_Stop_DMA(&hadc1);
    __HAL_ADC_DISABLE_IT(&hadc1, ADC_IT_EOS);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_2);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_3);
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_4);
    

修改后的唤醒后代码片段

__enable_irq();
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
SystemClock_Config();
HAL_ResumeTick();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, 1); //LED ON

// 重置并重新初始化ADC和DMA
__HAL_RCC_ADC1_FORCE_RESET();
HAL_Delay(1);
__HAL_RCC_ADC1_RELEASE_RESET();
__HAL_RCC_DMA1_FORCE_RESET();
HAL_Delay(1);
__HAL_RCC_DMA1_RELEASE_RESET();
MX_DMA_Init();
MX_ADC1_Init();

// 清除残留标志
__HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_ALL);
__HAL_ADC_CLEAR_FLAG(&hadc1, ADC_FLAG_ALL);

// 重新启动定时器PWM
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
htim3.Instance->CCR1 = htim3.Instance->ARR;
htim3.Instance->CCR4 = 2000;

// 重新校准并启动ADC DMA
HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
HAL_Delay(200);
HAL_ADC_Start_DMA(&hadc1, ADCbuffer,14);
__HAL_ADC_ENABLE_IT(&hadc1, ADC_IT_EOS);

MX_USB_DEVICE_Init();
//Bip
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
htim2.Instance->CCR2 = htim2.Instance->ARR/2;
HAL_Delay(2);
htim2.Instance->CCR2 = 0;
HAL_Delay(2000);
uint8_t HiMsg[] = "hello\r\n";
CDC_Transmit_FS(HiMsg, strlen(HiMsg));
HAL_Delay(50);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2);

额外注意事项

  • 确认DMA通道的优先级配置,避免唤醒后被其他高优先级外设抢占
  • 检查ADC时钟源在唤醒后的配置是否正确,确保ADC时钟稳定
  • 若使用连续转换模式,需确认ADC的CONT位在唤醒后是否正确置位

内容的提问来源于stack exchange,提问作者Nguyễn Phụng Thái Cường

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 02:54:54