cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_ADC_ConvCpltCallback only gets called once

cbcooper
Associate III

I'm setting up the ADC in "manual continuous" mode where hadc1.Init.ContinuousConvMode = DISABLE and then I call HAL_ADC_Start_IT() inside of HAL_ADC_ConvCpltCallback().  I get the first call to HAL_ADC_ConvCpltCallback and calling HAL_ADC_Start_IT() returns HAL_OK but the callback never gets called again.

What am I missing?

Thanks,

Chris

  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_SYNC_PCLK_DIV2;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.GainCompensation = 0;
  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.DMAContinuousRequests = DISABLE;
  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_1;
  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;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
1 ACCEPTED SOLUTION

Accepted Solutions
Saket_Om
ST Employee

Hello @cbcooper 

It's better to handle the ADC conversion restart in the main loop, as shown in the example below: 

// Global variable to indicate ADC conversion completion
volatile uint8_t adcConversionComplete = 0;
// ADC handle declaration
ADC_HandleTypeDef hadc1;

// Callback function for ADC conversion complete
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    // Set the flag to indicate conversion is complete
    adcConversionComplete = 1;
}

int main(void) {
    // HAL initialization
    HAL_Init();

    // ADC configuration (assuming hadc1 is properly configured elsewhere)
    // ...

    // Start ADC conversion in interrupt mode
    HAL_ADC_Start_IT(&hadc1);

    // Main loop
    while (1) {
        // Check if ADC conversion is complete
        if (adcConversionComplete) {
            // Reset the flag
            adcConversionComplete = 0;

            // Process the ADC data
            uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
            // Use adcValue as needed

            // Restart ADC conversion in interrupt mode
            HAL_ADC_Start_IT(&hadc1);
        }

        // Other tasks can be performed here
    }
}

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

View solution in original post

3 REPLIES 3
Saket_Om
ST Employee

Hello @cbcooper 

It's better to handle the ADC conversion restart in the main loop, as shown in the example below: 

// Global variable to indicate ADC conversion completion
volatile uint8_t adcConversionComplete = 0;
// ADC handle declaration
ADC_HandleTypeDef hadc1;

// Callback function for ADC conversion complete
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    // Set the flag to indicate conversion is complete
    adcConversionComplete = 1;
}

int main(void) {
    // HAL initialization
    HAL_Init();

    // ADC configuration (assuming hadc1 is properly configured elsewhere)
    // ...

    // Start ADC conversion in interrupt mode
    HAL_ADC_Start_IT(&hadc1);

    // Main loop
    while (1) {
        // Check if ADC conversion is complete
        if (adcConversionComplete) {
            // Reset the flag
            adcConversionComplete = 0;

            // Process the ADC data
            uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
            // Use adcValue as needed

            // Restart ADC conversion in interrupt mode
            HAL_ADC_Start_IT(&hadc1);
        }

        // Other tasks can be performed here
    }
}

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om
cbcooper
Associate III

That works but why?  I would much rather not have the ISR wait for the main code to get around to looking at the value before it starts acquiring the next. 

 

Karl Yamashita
Principal

You don't want to keep calling HAL_ADC_Start_IT directly from the callback as this would cause a lot of overhead and your other interrupts with lower priority will not be able to interrupt. And also your main while loop will not be able to run reliably as well.

So, do as @Saket_Om mentions or use a timer interrupt to start the ADC conversion.

 

I was told that if a devices starts to smoke, put the smoke back in. I guess I never got all the smoke because the device never worked afterwards.
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.