0
\$\begingroup\$

I'm facing with a problem regarding continuous acquisition of ADC channel in STM32F103.

I use the interrupt at the end of conversion to call a callback function to store the acquired value.

The problem regards the callback that is called only the first time.

I configured my project using STM32CubeMx for continuous acquisition and interrupt generation.

This is the ADC configuration:

hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
    Error_Handler();
}

/**Configure Regular Channel 
*/
sConfig.Channel = ADC_CHANNEL_11;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
    Error_Handler();
}

This is my acquisition function:

ea_ADC_Err_Code_t ea_ADC_n_data_read(Adc_Channel_t channel, adc_eoc_callback adc_cb) 
{
    ea_ADC_Err_Code_t err_code = ADC_ERR;     
    ADC_ChannelConfTypeDef sConfig;

    adc_read_value    = 0;
    adc_eoc_cb        = adc_cb;
    n_adc_acquisition = ADC_MAX_CONS_ACQ;

    /* Deinit ADC */       
    //while(HAL_ADC_DeInit(&adc_handler) != HAL_OK);

    /* Initialize ADC */ 
    //HAL_ADC_Init(&adc_handler);

    /* Configure ADC Channel */
    sConfig.Channel = channel;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
    HAL_ADC_ConfigChannel(&adc_handler, &sConfig);

    /* Set ADC callback */
    HAL_ADC_ConvCpltCallback(&adc_handler);

    /* ADC Calibration */
    //HAL_ADCEx_Calibration_Start(&adc_handler);

    /* Start conversion with interrupt*/
    if (HAL_ADC_Start_IT(&adc_handler) == HAL_OK)
    {
      err_code = ADC_OK;
    }

    return err_code;
}

And finally my callback:

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if (n_adc_acquisition)
    {
        adc_read_value += HAL_ADC_GetValue(&adc_handler);
        n_adc_acquisition--;
        edi_Print_L1("ADC Callback %d\n", n_adc_acquisition);
    }
    else
    {
        HAL_ADC_Stop_IT(&adc_handler);
        adc_read_value = adc_read_value >> ADC_DIVIDE_BY_EIGTH;
        adc_eoc_cb(adc_read_value);
    }
}

Did I forget something in the callback?

\$\endgroup\$
  • \$\begingroup\$ Are you clearing the interrupt anywhere? \$\endgroup\$ – Eugene Sh. Jun 16 '16 at 14:01
  • \$\begingroup\$ @EugeneSh.: No. I think that in continuous mode, the interrupt cleaning is not needed. Do I clean IT? Thanks \$\endgroup\$ – Federico Jun 16 '16 at 14:03
  • 1
    \$\begingroup\$ Hey, now I see. You are not setting the callback properly at all. But you are just manually calling your HAL_ADC_ConvCpltCallback so you see it is called. \$\endgroup\$ – Eugene Sh. Jun 16 '16 at 14:05
  • 1
    \$\begingroup\$ Ah, wait. I see. STM code has a weak declaration of a function of the same name, so it is set as a callback automatically? \$\endgroup\$ – Eugene Sh. Jun 16 '16 at 14:09
  • 1
    \$\begingroup\$ Again, I don't have time to go deeply in a research here, but you might want to take a look here \$\endgroup\$ – Eugene Sh. Jun 16 '16 at 14:23
4
\$\begingroup\$

You forgot to enabled the ADC interrupts, which can be done something like this:

HAL_NVIC_SetPriority(ADC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC_IRQn);

The next thing with HAL's interrupt handling is that there are two weak function declaration.

  1. for void ADC_IRQHandler()
  2. for void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

You have to implement the ADC_IRQHandler() first, this will be called when an interrupt is generated by the ADC. Inside this function you have to call the HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc), parameter is your ADC's handler (ADC_HandleTypeDef).

void ADC_IRQHandler()
{
    HAL_ADC_IRQHandler(&hadc1);
    //HAL_ADC_IRQHandler(&hadc2); <--- In case of a second ADC
}

Now, HAL_ADC_IRQHandler() will check every kind of error for you (you can check it in its implementation) and if everything is fine, it will call the void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc). As it also has a weak declaration, so you have to implement the function.

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc->Instance == ADC1)
    {
        int converted_value = HAL_ADC_GetValue(hadc);
        // Do stuff
    }

    //if(hadc->Instance == ADC2)  // <-- In case of a second ADC
    //{
    //
    //}
}

In STM32CubeMX, in the ADC1 Configuration window, there is tab called NVIC Settings. Here you can enable the global interrupts for ADC1 and ADC2, and if you do so, then STM32Cube will implements the void ADC_IRQHandler(void) in the stm32f1xx_it.c file.

/******************************************************************************/
/* STM32F4xx Peripheral Interrupt Handlers                                    */
/* Add here the Interrupt Handlers for the used peripherals.                  */
/* For the available peripheral interrupt handler names,                      */
/* please refer to the startup file (startup_stm32f4xx.s).                    */
/******************************************************************************/

/**
* @brief This function handles ADC1 and ADC2 global interrupts.
*/
void ADC_IRQHandler(void)
{
  /* USER CODE BEGIN ADC_IRQn 0 */

  /* USER CODE END ADC_IRQn 0 */
  HAL_ADC_IRQHandler(&hadc1);
  /* USER CODE BEGIN ADC_IRQn 1 */

  /* USER CODE END ADC_IRQn 1 */
}

Also it's just a brief summary, so I suggest to read through the tutorial, @Eugene Sh showed you.

\$\endgroup\$
  • \$\begingroup\$ Thanks! I configured correctly the ADC IT with STM32Cube and now the adc works well! \$\endgroup\$ – Federico Jun 16 '16 at 16:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.