cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_ADC_PollForConversion gets stuck

dfshea
Associate III

I'm writing software that involves reading a single ADC value from my STM32H7R3V8H6, however it is getting stuck in HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);.

If i switch the delay to a smaller value it runs through but it still returns a timeout.

while (1) { HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 100); adc1Data = HAL_ADC_GetValue(&hadc1); HAL_ADC_Stop(&hadc1); //readT(&engine, 0); //readP(&engine, 0); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_MultiModeTypeDef multimode = {0}; ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.LowPowerAutoWait = DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL; hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc1.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure the ADC multi-mode */ multimode.Mode = ADC_MODE_INDEPENDENT; if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; sConfig.OffsetSign = ADC_OFFSET_SIGN_NEGATIVE; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ }
View more
17 REPLIES 17
Karl Yamashita
Principal

HAL_MAX_DELAY = 49.7 Days! 

So if you wait for almost 50 days, the function will eventually return.

Typically 100ms is more than enough for a timeout.

 

How do you know if it return a timeout? You're not checking the return value.

HAL_StatusTypeDef hal_status = HAL_ADC_PollForConversion(&hadc1, 100); if(hal_status == HAL_ERROR) { // error handler } else if(hal_status == HAL_TIMEOUT) { // timeout handler } // get adc value

 

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.

Hm, 50 days is a bit much to see if it times out, so I reduced the delay to 100ms and added a return variable and confirmed that it is indeed returning HAL_TIMEOUT. 

 

I also did some digging and found where in the function it's getting stuck:

tickstart = HAL_GetTick(); /* Wait until End of unitary conversion or sequence conversions flag is raised */ while ((hadc->Instance->ISR & tmp_Flag_End) == 0UL) { /* Check if timeout is disabled (set to infinite wait) */ if (Timeout != HAL_MAX_DELAY) { if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0UL)) { /* New check to avoid false timeout detection in case of preemption */ if ((hadc->Instance->ISR & tmp_Flag_End) == 0UL) { /* Update ADC state machine to timeout */ SET_BIT(hadc->State, HAL_ADC_STATE_TIMEOUT); /* Process unlocked */ __HAL_UNLOCK(hadc); return HAL_TIMEOUT; } } } }

dfshea_0-1740800326794.png

 

Saket_Om
ST Employee

Hello @dfshea 

Did you confirm an ADC calibration before starting the conversion please? 

Did you check to compare your implementation with the example below?

 Projects/NUCLEO-H7S3L8/Examples/ADC/ADC_SingleConversion_TriggerSW

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar
dfshea
Associate III

@Saket_Om, I forgot to do the calibration, I wasn't sure if it was necessary or not. However I just tried doing the calibration and it gets stuck there as well. It gets stuck in this loop:

while (LL_ADC_IsCalibrationOnGoing(hadc->Instance) != 0UL) { wait_loop_index++; if (wait_loop_index >= ADC_CALIBRATION_TIMEOUT) { /* Update ADC state machine to error */ ADC_STATE_CLR_SET(hadc->State, HAL_ADC_STATE_BUSY_INTERNAL, HAL_ADC_STATE_ERROR_INTERNAL); /* Process unlocked */ __HAL_UNLOCK(hadc); return HAL_ERROR; } }
Chris21
Senior II

Where is the code that enables the ADC peripheral clock?

Are your ADC configuration registers all zeroes? 

dfshea
Associate III

@Chris21 It's this code here right? (I could be wrong, this was autogenerated)

static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_MultiModeTypeDef multimode = {0}; ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.LowPowerAutoWait = DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL; hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED; hadc1.Init.OversamplingMode = DISABLE; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure the ADC multi-mode */ multimode.Mode = ADC_MODE_INDEPENDENT; if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; sConfig.SingleDiff = ADC_SINGLE_ENDED; sConfig.OffsetNumber = ADC_OFFSET_NONE; sConfig.Offset = 0; sConfig.OffsetSign = ADC_OFFSET_SIGN_NEGATIVE; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ }
View more
Chris21
Senior II

Somewhere you need something like:

 


/* Peripheral clock enable */
__HAL_RCC_ADC_CLK_ENABLE();

 

Also GPIO pins configured for analog mode.

I confirmed the pins are in analog mode. And this may be a foolish question but when I try to call __HAL_RCC_ADC_CLK_ENABLE() it says there is an undefined reference to it. Is there another HAL library I need to include in the main.c file? Thank you again for your help!

What's your definition of stuck? Because if you return a timeout, then how can it be stuck?

Don't worry, I won't byte.
TimerCallback tutorial! | UART and DMA Idle tutorial!

If you find my solution useful, please click the Accept as Solution so others see the solution.