Configuration et Exploitation du Convertisseur Analogique-Numérique sur STM32

Mécanismes de Démarrage et Bootloader

En l'absence de débogueur matériel dédié (tel qu'un ST-Link), il est possible de flasher le microcontrôleur via une liaison série (USART1). Cette méthode nécessite de configurer la broche BOOT0 à un niveau logique haut, forçant ainsi le MCU à démarrer depuis la mémoire système. Le processeur ne lit l'état des broches de boot qu'immédiatement après un reset pour exécuter le Bootloader. Ce programme intégré reçoit les données via l'USART et les écrit dans la mémoire Flash principale, dont l'adresse de base est 0x0800 0000. Une fois le transfert terminé, BOOT0 doit être remis à l'état bas, suivi d'un reset pour exécuter le nouveau firmware.

Les options de configuration (Option Bytes) permettent de gérer des paramètres persistants indépendants du code applicatif, tels que la protection en lecture (dont la désactivation efface la Flash), la protection en écriture et divers paramètres matériels. Ces octets peuvent être modifiés via des outils logiciels dédiés.

Architecture et Principes du Convertisseur Analogique-Numérique

Le Convertisseur Analogique-Numérique (CAN ou ADC) traduit les tensions analogiques continues en valeurs numériques discrètes. Le processus repose sur quatre étapes fondamentales : l'échantillonnage, le maintien, la quantification et le codage. Le STM32 intègre une architecture à Registre à Approximations Successives (SAR). Pour une résolution de 12 bits, le convertisseur effectue 12 comparaisons successives.

Le temps de conversion total ($T_{CONV}$) est la somme du temps d'échantillonnage et de 12,5 cycles d'horloge ADC. Avec une fréquence d'horloge ADC maximale de 14 MHz et un temps d'échantillonnage minimal de 1,5 cycle, le temps de conversion le plus court atteint 1 µs (soit une fréquence de 1 MHz). Il est important de noter qu'un temps d'échantillonnage plus long améliore la stabilité et la précision de la mesure, en particulier pour les sources à haute impédance.

Les entrées multiplexées comprennent jusqu'à 16 canaux externes (broches GPIO), un capteur de température interne, une tension de référence interne ($V_{REFINT}$) et la tension de la batterie de sauvegarde ($V_{BAT}$). La plage de conversion est strictement définie par les tensions de référence $V_{REF+}$ et $V_{REF-}$.

Canaux et Modes de Conversion

Le périphérique divise les entrées en deux groupes distincts :

  • Canaux Réguliers (Regular) : Utilisés pour les conversions standards. Le groupe peut contenir jusqu'à 16 canaux, mais ne possède qu'un seul registre de données. L'utilisation du DMA est fortement recommandée en mode scan pour éviter l'écrasement des données.
  • Canaux Injectés (Injected) : Conçus pour les interruptions de haute priorité. Ils peuvent interrompre une conversion régulière en cours. Ce groupe dispose de 4 registres de données dédiés, permettant de stocker simultanément les résultats de 4 canaux sans nécessiter de DMA.

Le groupe régulier offre quatre modes de foncitonnement combinant les options de déclenchement et de séquençage :

  • Single / Non-Scan : Conversion unique d'un seul canal. Nécessite un nouveau déclenchement pour chaque mesure.
  • Continuous / Non-Scan : Conversion ininterrompue d'un seul canal après un déclenchement initial.
  • Single / Scan : Conversion séquentielle de plusieurs canaux. S'arrête après avoir parcouru toute la séquence.
  • Continuous / Scan : Conversion séquentielle et ininterrompue de tous les canaux configurés.

Le résultat de la conversion sur 12 bits peut être aligné à gauche ou à droite dans le registre de 16 bits. Un décalage vers la gauche équivaut mathématiquement à une multiplication par deux. De plus, une procédure d'auto-calibration interne est disponible pour compenser les variations des capacités internes. Cette calibration doit être lancée alors que l'ADC est désactivé depuis au moins deux cycles d'horloge.

Implémentation Pratique avec la Bibliothèque HAL

Voici une implémentation moderne utilisant la bibliothèque HAL (Hardware Abstraction Layer) pour gérer l'acquisition sur un seul canal, puis sur plusieurs canaux via reconfiguration dynamique.

Initialisation et Acquisition Mono-canal

#include "stm32f4xx_hal.h"

ADC_HandleTypeDef hadc_sensor;

void Sensor_ADC_Init(void)
{
    __HAL_RCC_ADC1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // Configuration de la broche analogique
    GPIO_InitTypeDef gpio_config = {0};
    gpio_config.Pin = GPIO_PIN_0;
    gpio_config.Mode = GPIO_MODE_ANALOG;
    gpio_config.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &gpio_config);

    // Configuration globale de l'ADC
    hadc_sensor.Instance = ADC1;
    hadc_sensor.Init.Resolution = ADC_RESOLUTION_12B;
    hadc_sensor.Init.ScanConvMode = DISABLE;
    hadc_sensor.Init.ContinuousConvMode = DISABLE;
    hadc_sensor.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc_sensor.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc_sensor.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc_sensor);

    // Configuration du canal spécifique
    ADC_ChannelConfTypeDef channel_config = {0};
    channel_config.Channel = ADC_CHANNEL_0;
    channel_config.Rank = 1;
    channel_config.SamplingTime = ADC_SAMPLETIME_56CYCLES;
    HAL_ADC_ConfigChannel(&hadc_sensor, &channel_config);
}

uint16_t Fetch_Single_Analog_Value(void)
{
    HAL_ADC_Start(&hadc_sensor);
    HAL_ADC_PollForConversion(&hadc_sensor, 50);
    return (uint16_t)HAL_ADC_GetValue(&hadc_sensor);
}

Acquisition Multi-canaux par Polling

Pour lire plusieurs canaux sans utiliser le DMA ni le mode Scan, il est possible de reconfigurer dynamiquement le canal avant chaque conversion logicielle.

uint16_t Fetch_Multi_Analog_Value(uint32_t target_channel)
{
    ADC_ChannelConfTypeDef dynamic_channel = {0};
    dynamic_channel.Channel = target_channel;
    dynamic_channel.Rank = 1;
    dynamic_channel.SamplingTime = ADC_SAMPLETIME_56CYCLES;
    
    // Reconfiguration à la volée
    HAL_ADC_ConfigChannel(&hadc_sensor, &dynamic_channel);
    
    HAL_ADC_Start(&hadc_sensor);
    HAL_ADC_PollForConversion(&hadc_sensor, 50);
    return (uint16_t)HAL_ADC_GetValue(&hadc_sensor);
}

Intégration dans la Boucle Principale

uint16_t sensor_val_0, sensor_val_1, sensor_val_2, sensor_val_3;

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    
    Display_Init();
    Sensor_ADC_Init();
    
    Display_Print(1, 1, "CH0:");
    Display_Print(2, 1, "CH1:");
    Display_Print(3, 1, "CH2:");
    Display_Print(4, 1, "CH3:");
    
    while (1)
    {
        sensor_val_0 = Fetch_Multi_Analog_Value(ADC_CHANNEL_0);
        sensor_val_1 = Fetch_Multi_Analog_Value(ADC_CHANNEL_1);
        sensor_val_2 = Fetch_Multi_Analog_Value(ADC_CHANNEL_2);
        sensor_val_3 = Fetch_Multi_Analog_Value(ADC_CHANNEL_3);
        
        Display_PrintNum(1, 6, sensor_val_0, 4);
        Display_PrintNum(2, 6, sensor_val_1, 4);
        Display_PrintNum(3, 6, sensor_val_2, 4);
        Display_PrintNum(4, 6, sensor_val_3, 4);
        
        HAL_Delay(100);
    }
}

Étiquettes: STM32 ADC Microcontroller HAL EmbeddedC

Publié le 10 juillet à 00h04