cancel
Showing results for 
Search instead for 
Did you mean: 

Delay between HAL_ADCEx_Calibration_Start and HAL_ADC_Start_DMA required for unknown reason

_AdamNtrx
Associate II

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.

0 REPLIES 0