STM32G491CET6 ADC中断与HAL_Delay运行死循环问题咨询
STM32G491CET6 ADC中断、HAL_Delay死循环故障排查
故障现象
- 配置ADC中断触发采样时,程序陷入无限死循环
- 调用
HAL_Delay()函数时,程序同样触发死循环 - 同逻辑代码在STM32F103平台可正常运行,当前工程TIM1 PWM输出功能正常
核心复现代码如下:
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(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ADC1_Init(); MX_TIM1_Init(); /* USER CODE BEGIN 2 */ HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED) != HAL_OK) { /* Configuration Error */ Error_Handler(); } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_ADC_Start_IT (&hadc1); HAL_Delay(100); } /* USER CODE END 3 */ } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4); }
故障根因
两类死循环故障本质是STM32G4系列与F1系列的HAL库、NVIC规则差异导致的,PWM功能不受影响是因为TIM1 PWM输出由硬件自动完成,不需要CPU或中断参与。
1. SysTick中断被阻塞,HAL_Delay()死锁
HAL_Delay()的实现逻辑是轮询全局变量uwTick直到计数值达到目标延时,这个变量只能在SysTick中断服务函数中递增:
- STM32F1默认NVIC优先级分组为2位抢占优先级、2位子优先级,HAL库默认配置的SysTick优先级可正常响应
- STM32G4如果未手动配置优先级分组,或者将ADC等外设中断的抢占优先级设置为高于/等于SysTick优先级,当ADC中断持续触发时,SysTick中断无法抢占执行,
uwTick无法递增,HAL_Delay()会永远卡在轮询逻辑中。
2. ADC中断链路缺失,CPU反复进入中断死循环
从F1移植代码到G4时很容易遗漏中断服务函数对接:
- 如果工程中没有实现
ADC1_2_IRQHandler()中断服务函数,或者函数内没有调用HAL_ADC_IRQHandler(&hadc1),ADC转换完成的中断标志位永远不会被清除 - 中断标志未清除时,CPU退出中断后会立刻再次进入ADC中断服务,永远无法回到主循环执行后续逻辑,表现为死循环。
3. ADC启动逻辑存在隐患
当前代码在while循环中无判断重复调用HAL_ADC_Start_IT(),如果上一次ADC转换未完成就重复调用启动接口,会导致HAL库ADC状态机异常,触发错误处理死循环。
解决方法
配置正确的NVIC优先级分组,保证SysTick中断可响应
在HAL_Init()调用之后、系统时钟配置之前,添加优先级配置代码,对齐F1系列常用的优先级逻辑,确保SysTick不会被外设中断阻塞:HAL_Init(); /* 设置4位抢占优先级、0位子优先级 */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); /* 配置SysTick为1ms中断,抢占优先级设为最高级0 */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);ADC1中断的抢占优先级设置为1及以下即可,不要高于SysTick的0级。
补全ADC中断服务链路
打开工程的stm32g4xx_it.c文件,确认存在ADC1/2中断服务函数,且内部正确调用HAL库中断处理入口:void ADC1_2_IRQHandler(void) { HAL_ADC_IRQHandler(&hadc1); }同时确认ADC初始化函数中已经开启ADC全局中断、配置了对应NVIC通道(CubeMX中勾选ADC全局中断会自动生成该段代码):
HAL_NVIC_SetPriority(ADC1_2_IRQn, 1, 0); HAL_NVIC_EnableIRQ(ADC1_2_IRQn);优化ADC启动逻辑
增加采样完成标志位,避免重复调用ADC启动接口导致状态机异常:/* 主循环前定义标志位 */ uint8_t adc_conv_flag = 0; while (1) { if(adc_conv_flag) { adc_conv_flag = 0; HAL_Delay(100); HAL_ADC_Start_IT(&hadc1); } } /* 回调函数中增加实例判断、置位标志 */ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ if(hadc->Instance == ADC1) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4); adc_conv_flag = 1; } }
内容的提问来源于stack exchange,提问作者vsa
相关产品推荐
相关产品推荐

