Conversion ADC STM32 à l'aide de HAL

10

J'essaie d'apprendre à utiliser la "nouvelle" bibliothèque HAL de stm32.
Lorsque j'essaie de faire une conversion ADC simple, cela ne fonctionne qu'une seule fois, mais il arrête la conversion. Je suppose que l'indicateur de fin de conversion n'est pas défini. J'utilise la carte Discovery STM32f429I, qui a à bord STM32f429ZI.
Notez que je sais que sprintf est une mauvaise pratique et que faire adc avec interruption est meilleur, je sais que, veuillez ne pas le signaler, ce n'est pas pertinent pour la question, je teste juste HAL ici.
La question est donc de savoir pourquoi le drapeau EOC n'est pas défini ou que puis-je faire pour le faire fonctionner? La recherche sur Google n'aide pas beaucoup, car il existe très peu de bons documents sur HAL.

Voici le code:

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

J'ai également créé le projet avec CubeMX, la configuration adc est la suivante: entrez la description de l'image ici

EDIT 1
J'ai essayé de tout déboguer et il semble que le programme reste bloqué dans la vérification du drapeau EOC - il voit qu'il n'est pas affiché et émet donc un temporisateur en attendant que EOC apparaisse (mais il n'est jamais défini) Voici le code où il se coince dans le débogueur:

/* 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
la source

Réponses:

6

Dans votre code d'origine, définissez la sélection de fin de conversion sur désactivé.

 hadc1.Init.EOCSelection = DISABLE;

Il s'est avéré que la #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)valeur est égale à DISABLE. Donc, en réalité, EOCSelection doit être configuré comme: pour pouvoir interroger l'ADC plusieurs fois.entrez la description de l'image ici

Ensuite, vous pouvez lire l'ADC en continu sans arrêter et démarrer 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);
        }
    }
}

De cette façon, cela a bien fonctionné pour moi.

Puisque HAL est une toute nouvelle bibliothèque, il n'y a pas beaucoup de ressources à trouver mais pas impossible. J'ai beaucoup appris de ce tutoriel , il montre pas à pas toutes les utilisations possibles d'ADC; de la simple interrogation à l'utilisation des interruptions et du DMA.

Bence Kaulics
la source
hm ... la désactivation d'EOCSelection le fait fonctionner, mais d'après sa définition, il dit - Spécifie si l'indicateur EOC est défini à la fin de la conversion de canal unique ou à la fin de toutes les conversions. La désactivation de cela ne devrait pas aider par définition .. mais cela aide .... confus. Savez-vous pourquoi la désactivation exacte de cela fait que cela fonctionne? merci pour la réponse quand même
ScienceSamovar
J'apprends juste HAL aussi, donc je ne connais pas encore la raison. Ce n'est qu'une expérience. J'ai trouvé que HAL pouvait être si fatigant tant de fois.
Bence Kaulics,
J'ai vérifié les valeurs #define ADC_EOC_SEQ_CONV ((uint32_t)0x00000000)définies et qui est identique à désactivé, donc désactivé est en fait ADC_EOC_SEQ_CONV.
Bence Kaulics
1
oh, ok, donc ce n'est pas littéralement désactivé. Cela a du sens, auparavant c'était ADC_EOC_SINGLE_CONV, ce qui signifie probablement juste cela - il ne convertit qu'une seule fois, et ADC_EOC_SEQ_CONV est une conversion continue. Encore un mystère résolu :) Merci!
ScienceSamovar
Oui, ça devrait être le cas. :)
Bence Kaulics
2

Hm ... J'ai trouvé quelques tutoriels qui ont utilisé HAL_ADC_Stop (& hadc1) pour terminer la conversion ... Je regardais ces tutoriels avant et je pensais que c'était plutôt barbare, il semble qu'il désactive complètement ADC, donc je pensais qu'il devrait y avoir méthode différente. Mais il semble que cela fonctionne bien.
Soyez les bienvenus pour poster une réponse s'il existe une manière plus élégante de le faire, car je pense que l'utilisation de HAL_ADC_Stop () est assez horrible, mais peut être utilisée à des fins d'apprentissage.

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
la source
Salut, j'ai trouvé un problème avec cette méthode, elle limite la fréquence d'échantillonnage maximale que vous pouvez atteindre par beaucoup, il n'est pas recommandé d'utiliser cette méthode si vous avez besoin de conversions ADC rapides.
Richard Bamford
2

Je voudrais ajouter que pour ma configuration (nucleo-h743) il ne suffisait pas de régler:

hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;

J'ai également dû activer le paramètre de dépassement:

hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;

Sans cela, HAL_ADC_PollForConversion bloquait toujours. Je ne comprends pas très bien pourquoi cela était nécessaire mais cela me permet d'interroger en mode continu.

biglotusturtle
la source
0

Cela fonctionne pour moi, j'espère que cela vous aidera:

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
la source