Conversión de STM32 ADC usando HAL

10

Estoy tratando de aprender cómo usar la "nueva" biblioteca HAL de stm32.
Cuando trato de hacer una conversión ADC simple, funciona solo una vez, pero luego deja de convertir. Supongo que el indicador de Fin de conversión no se establece. Estoy usando la placa de descubrimiento STM32f429I, que tiene STM32f429ZI a bordo.
Tenga en cuenta que sé que sprintf es una mala práctica y que hacer adc con interrupción es mejor, sé que, por favor, no lo señale, esto no es relevante para la pregunta, solo estoy probando HAL aquí.
Entonces, la pregunta es por qué el indicador EOC no está configurado o qué puedo hacer para que funcione. Buscar en Google no ayuda mucho, ya que hay muy pocos buenos materiales sobre HAL.

Aquí está el código:

__IO uint16_t ADCValue=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);

int main(void)
{
  char str[15];

  /* Various initializations */

  HAL_ADC_Start(&hadc1);
  while (1)
  {

        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
            sprintf(str, "%d", ADCValue);
            BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }

  }

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    ADCValue = HAL_ADC_GetValue(&hadc1);
}

También creé el proyecto con CubeMX, la configuración adc es la siguiente: ingrese la descripción de la imagen aquí

EDITAR 1
Intenté depurar todo y parece que el programa se queda atascado en la comprobación de la marca EOC: ve que no se muestra y, por lo tanto, emite un temporizador esperando que aparezca EOC (pero nunca se configura) Aquí está el código donde está se atasca en el depurador:

/* Check End of conversion flag */
  while(!(__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)))
  {
    /* Check for the Timeout */
    if(Timeout != HAL_MAX_DELAY)
    {
      if((Timeout == 0)||((HAL_GetTick() - tickstart ) > Timeout))
      {
        hadc->State= HAL_ADC_STATE_TIMEOUT;
        /* Process unlocked */
        __HAL_UNLOCK(hadc);
        return HAL_TIMEOUT;
      }
    }
ScienceSamovar
fuente

Respuestas:

6

En su código original, configure la Selección de fin de conversión en deshabilitada.

 hadc1.Init.EOCSelection = DISABLE;

Resultó que el #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)valor es igual a DISABLE. Entonces, en realidad, la EOCSelection debe configurarse como: para poder sondear el ADC varias veces.ingrese la descripción de la imagen aquí

Luego puede leer el ADC continuamente sin detener e iniciar el ADC:

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    ConfigureADC();

    HAL_ADC_Start(&hadc1);
    while(1)
    {
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
        }
    }
}

De esta manera funcionó bien para mí.

Dado que HAL es una biblioteca bastante nueva, no hay muchos recursos para encontrar pero no imposible. Aprendí mucho de este tutorial , demuestra todo el uso posible de ADC paso a paso; desde encuestas simples, hasta el uso de interrupciones y DMA.

Bence Kaulics
fuente
hm ... deshabilitar EOCSelection hace que funcione, pero según su definición dice: especifica si el indicador EOC se establece al final de la conversión de un solo canal o al final de todas las conversiones. Desactivar esto no debería ayudar por definición ... pero ayuda ... confuso. ¿Sabes por qué exactamente deshabilitar esto hace que funcione? gracias por la respuesta de todos modos
ScienceSamovar
También estoy aprendiendo HAL, así que todavía no sé la razón. Es solo una experiencia. Descubrí que HAL puede estar conspirando muchas veces.
Bence Kaulics
He comprobado los valores definidos y #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)que es lo mismo que deshabilitado, por lo que deshabilitado es en realidad ADC_EOC_SEQ_CONV.
Bence Kaulics
1
oh, ok, entonces no está literalmente deshabilitado. Tiene sentido, anteriormente era ADC_EOC_SINGLE_CONV, lo que probablemente significa exactamente eso: convierte solo una vez, y ADC_EOC_SEQ_CONV es una conversión continua. Un misterio más resuelto :) ¡Gracias!
ScienceSamovar
Sí, ese debería ser el caso. :)
Bence Kaulics
2

Hm ... Encontré un par de tutoriales que usaban HAL_ADC_Stop (& hadc1) para finalizar la conversión ... Estaba mirando estos tutoriales antes y pensé que era una forma bastante bárbara, parece que deshabilita ADC por completo, así que pensé que debería haber método diferente Pero parece que esto realmente funciona bien.
Sea bienvenido a publicar la respuesta si hay una forma más elegante de hacerlo, ya que creo que usar HAL_ADC_Stop () es bastante horrible, pero se puede usar con fines de aprendizaje.

while (1)
  {
        HAL_ADC_Start(&hadc1);
        if (HAL_ADC_PollForConversion(&hadc1, 1000000) == HAL_OK)
        {
            ADCValue = HAL_ADC_GetValue(&hadc1);
                        sprintf(str, "%d", ADCValue);
                        BSP_LCD_DisplayStringAt(130,30, (uint8_t*)str, LEFT_MODE);
        }
        HAL_ADC_Stop(&hadc1);

  }
ScienceSamovar
fuente
Hola, encontré un problema con este método, restringe la frecuencia de muestreo máxima que puede lograr MUCHO, no se recomienda usar este método si necesita conversiones rápidas de ADC.
Richard Bamford
2

Me gustaría agregar que para mi configuración (nucleo-h743) no fue suficiente para configurar:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

También tuve que habilitar la configuración de desbordamiento también:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Sin esto, HAL_ADC_PollForConversion seguía bloqueándose. No entiendo completamente por qué esto era necesario, pero me permite sondear en modo continuo.

biglotusturtle
fuente
0

Esto funciona para mí, espero que ayude:

if (HAL_ADC_Start(&hadc) != HAL_OK)
{
    /* Start Conversation Error */
    // Error_Handler();
}
if (HAL_ADC_PollForConversion(&hadc, 500) != HAL_OK)
{
    /* End Of Conversion flag not set on time */
    // Error_Handler();
    ADCValue=-1;
}
else
{
    /* ADC conversion completed */
    /*##-5- Get the converted value of regular channel ########################*/
    ADCValue = HAL_ADC_GetValue(&hadc);
}
HAL_ADC_Stop(&hadc);
Yaniv Maor
fuente