Conversione ADC STM32 utilizzando HAL


10

Sto cercando di imparare come utilizzare la "nuova" libreria HAL da stm32.
Quando provo a fare una semplice conversione ADC funziona solo una volta, ma poi smette di convertire. Suppongo che il flag di fine conversione non venga impostato. Sto usando la scheda Discovery STM32f429I, che ha STM32f429ZI a bordo.
Nota che so che lo sprint è una cattiva pratica e che è meglio fare adc con interrupt, lo so, per favore non sottolinearlo, questo non è rilevante per la domanda, sto solo testando HAL qui.
Quindi la domanda è: perché il flag EOC non è impostato o cosa posso fare per farlo funzionare? Googling non aiuta molto dal momento che pochissimi buoni materiali su HAL là fuori.

Ecco il codice:

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

Ho anche creato il progetto con CubeMX, la configurazione adc è la seguente: inserisci qui la descrizione dell'immagine

EDIT 1
Ho provato a eseguire il debug di tutto e sembra che il programma sia bloccato nel controllo del flag EOC - vede che non viene mostrato e quindi genera un timer in attesa che venga visualizzato EOC (ma non viene mai impostato) Ecco il codice in cui si trova rimane bloccato nel debugger:

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

Risposte:


6

Nel codice originale, imposta la selezione di Fine conversione su disabilitata.

 hadc1.Init.EOCSelection = DISABLE;

Si è scoperto che il #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)valore è uguale a DISABLE. Quindi effettivamente EOCSelection dovrebbe essere configurato come: per poter eseguire il polling dell'ADC più volte.inserisci qui la descrizione dell'immagine

Quindi è possibile leggere continuamente l'ADC senza arrestare e avviare l'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);
        }
    }
}

In questo modo ha funzionato bene per me.

Poiché HAL è una libreria abbastanza nuova, non ci sono molte risorse da trovare ma non impossibili. Ho imparato molto da questo tutorial , che dimostra passo dopo passo tutti i possibili utilizzi dell'ADC; dal semplice polling, all'utilizzo di interrupt e DMA.


hm ... la disabilitazione di EOCSelection lo fa funzionare, ma dalla sua definizione dice - Specifica se il flag EOC è impostato alla fine della conversione a canale singolo o alla fine di tutte le conversioni. Disabilitare questo non dovrebbe aiutare per definizione ... ma aiuta .... confuso. Sai perché disabilitare esattamente questo fa funzionare? grazie comunque per la risposta
ScienceSamovar,

Sto solo imparando anche HAL, quindi non ne conosco ancora il motivo. È solo un'esperienza. Ho scoperto che l'HAL può essere trasformato così tante volte.
Bence Kaulics il

Ho verificato i valori di definizione e #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)che è uguale a disabilitato, quindi disabilitato è in realtà ADC_EOC_SEQ_CONV.
Bence Kaulics il

1
oh, ok, quindi non è letteralmente disabilitato. Ha senso, in precedenza era ADC_EOC_SINGLE_CONV che probabilmente significa proprio questo: converte solo una volta e ADC_EOC_SEQ_CONV è una conversione continua. Un altro mistero risolto :) Grazie!
ScienceSamovar,

Sì, dovrebbe essere così. :)
Bence Kaulics il

2

Hm ... ho trovato un paio di tutorial che hanno usato HAL_ADC_Stop (& hadc1) per terminare la conversione ... Stavo guardando questi tutorial prima e ho pensato che questo è un modo piuttosto barbaro, sembra che disabiliti completamente ADC, quindi penso che ci dovrebbe essere metodo diverso. Ma sembra che questo funzioni davvero bene.
Ti invitiamo a postare una risposta se esiste un modo più elegante di farlo, poiché penso che usare HAL_ADC_Stop () sia piuttosto terribile, ma può essere utilizzato per scopi di apprendimento.

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

  }

Ciao, ho riscontrato un problema con questo metodo, limita la frequenza di campionamento massima che puoi ottenere MOLTO, non è consigliabile utilizzare questo metodo se hai bisogno di conversioni ADC rapide.
Richard Bamford,

2

Vorrei aggiungere che per la mia configurazione (nucleo-h743) non è stato sufficiente impostare:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

Ho anche dovuto abilitare l'impostazione di superamento:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Senza questo, HAL_ADC_PollForConversion stava ancora bloccando. Non capisco perfettamente perché ciò fosse necessario, ma mi consente di eseguire il polling in modalità continua.


0

Questo funziona per me, spero che possa aiutare:

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);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.