Conversión continua ADC STM32F103

Me enfrento a un problema relacionado con la adquisición continua del canal ADC en STM32F103.

Uso la interrupción al final de la conversión para llamar a una función de devolución de llamada para almacenar el valor adquirido.

El problema se refiere a la devolución de llamada que se llama solo la primera vez.

Configuré mi proyecto usando STM32CubeMx para adquisición continua y generación de interrupciones.

Esta es la configuración del ADC:

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();
}

Esta es mi función de adquisición:

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

Y finalmente mi devolución de llamada:

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);
    }
}

¿Olvidé algo en la devolución de llamada?

¿Estás limpiando la interrupción en alguna parte?
@EugeneSh.: No. Creo que en modo continuo no se necesita la limpieza de interrupciones. ¿Lo limpio? Gracias
No tengo ganas de cavar en la hoja de datos. Pero deberías. O simplemente pruébalo.
Oye, ahora veo. No está configurando la devolución de llamada correctamente en absoluto. Pero solo está llamando manualmente HAL_ADC_ConvCpltCallbackpara que vea que se llama.
Una interrupción es la información para que usted haga algo, cuando lo haya hecho, necesita volver a habilitarlo.
@EugeneSh.: ¿En serio? ¿Dónde cometí errores?
Ver actualización del comentario
@EugeneSh. HAL_ADC_ConvCpltCallback(&adc_handler);
Espera. Veo. El código STM tiene una declaración débil de una función del mismo nombre, por lo que se configura como una devolución de llamada automáticamente.
@EugeneSh. Sí, creo la devolución de llamada "HAL_ADC_ConvCpltCallback" en mi biblioteca ADC.
Pero en cualquier caso, no debe llamarlo manualmente como lo hace
No llamo a la devolución de llamada. Solo lo redefino en mi código. como st sugerir
HAL_ADC_ConvCpltCallback(&adc_handler);esta línea está llamando a la función.
Pero deberías mostrártelo main, ya que el flujo no está claro.
@EugeneSh.: ¡Op! ¡tienes razón! Creo que el problema está relacionado con la interrupción. ¿Necesito configurar TI para ADC1 y NVIC?
Nuevamente, no tengo tiempo para profundizar en una investigación aquí, pero es posible que desee echar un vistazo aquí .

Respuestas (1)

Se olvidó de habilitar las interrupciones ADC, que se puede hacer algo como esto:

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

Lo siguiente con el manejo de interrupciones de HAL es que hay dos declaraciones de funciones débiles.

  1. paravoid ADC_IRQHandler()
  2. paravoid HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)

Debe implementar el ADC_IRQHandler()primero, se llamará cuando el ADC genere una interrupción. Dentro de esta función, debe llamar al HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc)parámetro , es el controlador de su ADC ( ADC_HandleTypeDef).

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

Ahora, HAL_ADC_IRQHandler()verificará cada tipo de error por usted (puede verificarlo en su implementación) y si todo está bien, llamará al void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc). Como también tiene una declaración débil, debe implementar la función.

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
    //{
    //
    //}
}

En STM32CubeMX, en la ventana Configuración de ADC1, hay una pestaña llamada Configuración de NVIC . Aquí puede habilitar las interrupciones globales para ADC1 y ADC2, y si lo hace, STM32Cube las implementará void ADC_IRQHandler(void)en el archivo stm32f1xx_it.c .

/******************************************************************************/
/* 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 */
}

También es solo un breve resumen, por lo que sugiero leer el tutorial que @Eugene Sh le mostró.

¡Gracias! ¡Configuré correctamente el ADC IT con STM32Cube y ahora el adc funciona bien!