2020-10-15 11:17 AM
Hi
When calling HAL_ADC_Start, ADC_Enable returns with error due to timeout.
The timeout set by the HAL is 2ms (ADC_ENABLE_TIMEOUT)
I'm using the STM32L496 with MSI @1Mhz.
I'm using the HAL with FreeRTOS, and there are several tasks running.
There is more than 1 task using the ADC but on different ports (ADC1/ADC2/ADC3) and different channels.
Once in a while during one of the measurements the timeout occurs.
Increasing the timeout solved the issue.
Any idea why this is happening.
Obviously a task context switch happens, prolonging the time this function is out of context thus making it reach the timeout.
These are the relevant lines of code:
/* Enable the ADC peripheral */
LL_ADC_Enable(hadc->Instance);
/* Wait for ADC effectively enabled */
tickstart = HAL_GetTick();
while (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == 0UL)
{
/* If ADEN bit is set less than 4 ADC clock cycles after the ADCAL bit
has been cleared (after a calibration), ADEN bit is reset by the
calibration logic.
The workaround is to continue setting ADEN until ADRDY is becomes 1.
Additionally, ADC_ENABLE_TIMEOUT is defined to encompass this
4 ADC clock cycle duration */
/* Note: Test of ADC enabled required due to hardware constraint to */
/* not enable ADC if already enabled. */
if (LL_ADC_IsEnabled(hadc->Instance) == 0UL)
{
LL_ADC_Enable(hadc->Instance);
}
if ((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* Set ADC error code to ADC peripheral internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
return HAL_ERROR;
}
}
}
2020-10-15 11:25 AM
If a context switch happens, takes >2ms, and returns just prior to the timeout check, it is going to timeout. It will do so before __HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) is checked again.
If you need to delay 4 ADC clock cycles, seems like there is a better solution for how to handle this. Just a 1ms hard delay should solve it.
2020-10-15 11:33 AM
Your suggestion is to add HAL_Delay(1) before calling HAL_ADC_Start?
Or to change the HAL code and placing it before
__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) is checked ?
Thanks!
2020-10-15 12:03 PM
> Your suggestion is to add HAL_Delay(1) before calling HAL_ADC_Start?
Place the delay after calibration but before enabling the ADC. I assume that's right before the code you posted. Since this will take more than 4 ADC ticks, the workaround you're using is no longer needed and the timeout problem is avoided.
2020-10-15 12:46 PM
Where exactly ?
The calibration is done in HAL_ADC_Init right?
The problem is that I allways call HAL_ADC_Start with every sampling I do, thus calling ADC_Enable each time.
Adding a 1 ms delay will increase the sampling time..
2020-10-15 08:38 PM
Hmm, calibration is a separate step, by HAL_ADCEx_Calibration_Start. It's not done in HAL_ADC_Init. If you're not calibrating, I'm not sure what the issue is. Perhaps separate threads are trying to use the same ADC, although I know you said that isn't the case.
2020-10-16 01:03 AM
Yea sure I call HAL_ADCEx_Calibration_Start right before HAL_ADC_Start.
So I should place the delay in between?
As I said, It will increase the sampling time...isn't there a better solution in your opinion?
I understand that just increasing the timeout is not good enough because eventually a higher priority thread can always starve the ADC sampling thread causing it to timeout.
2020-10-17 10:04 PM
The delay will increase sampling time.
Is there a better solution?
2020-10-18 08:09 AM
The code you posted is within HAL, so I understand why it can't be changed. It's unfortunate they've put that workaround in there. You can ignore my advice about adding a delay.
I also see that the ADC_ENABLE_TIMEOUT value is hard-coded to 2ms within HAL.
One solution would be to prevent task switching during the call to HAL_ADC_Start. Not ideal, but it seems like it would prevent the issue. Could be wrong.
2020-10-18 10:27 AM
Looks like increasing ADC_ENABLE_TIMEOUT is the better solution isn’t it?
I don’t like changing Hal code but what about deleting that timeout workaround they’ve put there?
What could be the implications of doing that?
thanks again.