2025-03-19 2:54 AM - edited 2025-03-19 4:12 AM
I want to initialise ADC in my FreeRTOS task. If I remove/comment out HAL_ADCEx_Calibration_Start function, put a delay (osDelay(1)) between it and HAL_ADC_Start_DMA or place a breakpoint at HAL_ADC_Start_DMA and pause code execution at it during debugging, everything is fine and dmaBuffer gets filled with data from ADC.
However, if I do not do any of those things, then __HAL_ADC_ENABLE(hadc) macro inside of ADC_Enable function called by HAL_ADC_Start_DMA won't set ADEN flag in CR register to enable ADC and ADC_Enable will return HAL_ERROR.
Is it because calibration requires some time to finish and until then ADC can't be enabled? If so, how can I make sure calibration ended? Thank You for help in advance!
My FreeRTOS task initialising ADC:
volatile HAL_StatusTypeDef adcCalibrationReturn;
volatile HAL_StatusTypeDef adcStartReturn;
uint32_t adcTaskTick=0;
void startAdcTask(void *argument) {
adcCalibrationReturn=HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
osDelay(1); //if this is uncommented or if program stops at instruction breakpoint placed right below, then ADC
//sets HAL function ADC_Enable properly sets ISR to 1 and 0x10000001
adcStartReturn=HAL_ADC_Start_DMA(&hadc1, (uint32_t *)dmaBuffer, sizeof(dmaBuffer));
for (;;) {
adcTaskTick++;
osDelay(1000);
}
}
ADC_Enable function called by HAL_ADC_Start_DMA. There __HAL_ADC_ENABLE(hadc) macro either succeeds or not, depending on whether delay has been used or not:
static HAL_StatusTypeDef ADC_Enable(ADC_HandleTypeDef* hadc)
{
uint32_t tickstart = 0U;
/* ADC enable and wait for ADC ready (in case of ADC is disabled or */
/* enabling phase not yet completed: flag ADC ready not yet set). */
/* Timeout implemented to not be stuck if ADC cannot be enabled (possible */
/* causes: ADC clock not running, ...). */
if (ADC_IS_ENABLE(hadc) == RESET)
{
/* Check if conditions to enable the ADC are fulfilled */
if (ADC_ENABLING_CONDITIONS(hadc) == RESET)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* Set ADC error code to ADC IP internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
return HAL_ERROR;
}
/* Enable the ADC peripheral */
__HAL_ADC_ENABLE(hadc); //XXX this is where enabling ADC fails
//if code executes too soon (i.e. without delay
/* Wait for ADC effectively enabled */
tickstart = HAL_GetTick();
while(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == RESET)
{
if((HAL_GetTick() - tickstart) > ADC_ENABLE_TIMEOUT)
{
/* New check to avoid false timeout detection in case of preemption */
if(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_RDY) == RESET)
{
/* Update ADC state machine to error */
SET_BIT(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL);
/* Set ADC error code to ADC IP internal error */
SET_BIT(hadc->ErrorCode, HAL_ADC_ERROR_INTERNAL);
return HAL_ERROR;
}
}
}
}
/* Return HAL status */
return HAL_OK;
}
EDIT 1
I tried to wait for calibration to complete and voltage regulator to be enabled. It didn't work:
volatile HAL_StatusTypeDef adcCalibrationReturn;
volatile HAL_StatusTypeDef adcStartReturn;
uint32_t adcTaskTick=0;
void startAdcTask(void *argument) {
adcCalibrationReturn=HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
// osDelay(1); //if this is uncommented or if program stops at instruction breakpoint placed right below, then ADC
//sets HAL function ADC_Enable properly sets ISR to 1 and 0x10000001
while ( ( ((hadc1.Instance->CR) & (ADC_CR_ADCAL)) !=0 ) //while calibration is not complete...
&& ( ((hadc1.Instance->CR) & (ADC_CR_ADVREGEN)) != (ADC_CR_ADVREGEN_0) ) //while voltage regulator is not enabled...
) {
//wait
}
adcStartReturn=HAL_ADC_Start_DMA(&hadc1, (uint32_t *)dmaBuffer, sizeof(dmaBuffer));
for (;;) {
adcTaskTick++;
osDelay(1000);
}
}
EDIT 2
I forgot to mention I use STM32F302K6U6.