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 III

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; }
View more

 

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.

2 REPLIES 2
_AdamNtrx
Associate III

I think I found a bug inside of my code that caused many other problems:

adcStartReturn=HAL_ADC_Start_DMA(&hadc1, (uint32_t *)dmaBuffer, sizeof(dmaBuffer));

 

The last argument above should be:

sizeof(dmaBuffer)/sizeof(dmaBuffer[0])

 

So the whole instruction should look like:

adcStartReturn=HAL_ADC_Start_DMA( &hadc1, (uint32_t *)dmaBuffer, sizeof(dmaBuffer)/sizeof(dmaBuffer[0]) );

 

 

I wondered why other structures and variables get corrupted during execution of my program and the cause was incorrect memory range specified by last argument of HAL_ADC_Start_DMA. Still, a delay is required when I use ADC Asynchronous Clock Mode.

 

EDIT 1

Weird, ADC seems to be starting just fine, even without delay between calibration and start.

 

EDIT 2

If ADC is using Asynchronous Clock Mode and prescaler is set to 64, then starting ADC right after calibration without delay fails. Other prescaler values work fine:

Prescaler.png

 

_AdamNtrx
Associate III

Does anyone have any idea why this program works like that?