Unité 3 / 9

Systèmes embarqués et génération de code de microcontrôleur

Gains :

  • Possibilité de générer du code intégré en fonction du registre et du contexte matériel pour Arduino/STM32/ESP32 avec IA
  • Capacité à reconnaître et à corriger les modèles intégrés tels que les interruptions, les minuteries et les boucles non bloquantes dans la sortie AI
  • Possibilité de revoir le code généré en termes de mémoire, de temps réel et de sécurité avant de le télécharger sur le matériel

En mécatronique, le microcontrôleur est le point de rencontre des idées avec le monde physique. Cartes telles que Arduino, STM32, ESP32 ; il lit les capteurs, pilote les actionneurs, communique et fait tout cela avec une mémoire limitée, une puissance de traitement limitée et des exigences de synchronisation strictes. L'intelligence artificielle est très utile dans ce domaine : elle peut extraire les paramètres d'un registre à partir de la fiche technique d'un capteur, coder un protocole de communication, définir une interruption de minuterie. Mais les systèmes embarqués sont l’un des domaines dans lesquels l’IA produit les « mensonges les plus convaincants » ; car les adresses de registre, les masques de bits et le comportement de synchronisation sont spécifiques à la carte et une erreur de bit perturbe l'ensemble du comportement. Dans cette unité, nous expliquons comment générer du code intégré avec l'IA et comment le réviser avant de le charger dans le matériel.

Différence entre le code embarqué et Pure Software

Un programme de bureau dispose de beaucoup de mémoire, de système d’exploitation et d’une facilité de débogage. Le code embarqué manque de la plupart de ces éléments :

Taille

ordinateur de bureau

système embarqué

mémoire

Niveau Go

Niveau de Ko (par exemple 2 Ko de RAM)

timing

Généralement flexible

Serré, en temps réel

débogage

Facile (débogueur, journal)

Dur (JTAG, série, LED)

Résultat d'erreur

Le programme plante

L'actionneur/le matériel peut être endommagé

accès aux ressources

Résumés du système d'exploitation

Accès direct au Registre

Ces différences déterminent vos critères d'évaluation de la sortie de l'IA : l'utilisation de la mémoire, le temps réel (non bloquant) et la précision du registre matériel sont toujours en tête de votre liste de contrôle.

Code bloqueur ou code non bloquant

L’erreur la plus courante commise par les débutants (et fréquemment commise par l’IA) est l’utilisation de delay(). delay(1000) verrouille le processeur pendant 1 seconde ; Pendant cette période, aucun autre capteur ne peut être lu, aucun bouton ne peut être contrôlé. C’est inacceptable en mécatronique. Au lieu de cela, un modèle non bloquant basé sur millis() est utilisé.

// MAUVAIS : bloqueur -- le processeur ne peut effectuer aucun autre travail pendant 1 seconde void loop() { digitalWrite(LED, HIGH); retard (1000); // tout s'arrête digitalWrite(LED, LOW); retard (1000); // Un bouton d'urgence ne peut pas être lu pour le moment !}// BON : non bloquant -- la boucle n'est pas bloquée, d'autres tâches s'exécutent if (nowMs - previousMs >= interval) { previousMs = nowMs; ledStatus = !ledStatus; digitalWrite (LED, ledStatus); } boutonCheck(); // peut s'exécuter à chaque cycle sensorRead(); //peut s'exécuter dans n'importe quelle boucle}

Le modèle non bloquant est à la base de la mécatronique embarquée : la boucle de contrôle circule en continu, aucune tâche n'en verrouille une autre. Dire à l'IA de "ne pas utiliser de délai, écrire en millisecondes de manière non bloquante" lors de l'écriture du code améliore directement la qualité de la sortie.

Astuce : recherchez le retard (dans le code intégré de l'IA. Si vous constatez un retard dans la boucle de contrôle principale, le plus souvent, ce code n'est pas adapté à un système temps réel et doit être réécrit.

Interruptions et minuteries

Nous capturons les événements critiques (impulsion du codeur, bouton, échantillonnage périodique) avec des interruptions au lieu d'attendre dans la boucle principale. La routine d'interruption (ISR) doit être écrite de manière courte et soignée : pas de retards, d'impression en série ou de calculs longs ; Les variables partagées sont marquées volatiles.

encoderCounter long volatile = 0 ; // ISR et la boucle sont partagés -> condition volatile void enkoderISR() { // Short ISR : comptez simplement, ne faites aucun autre travail if (digitalRead(ENC_B)) enkoderCounter++; else encoderCounter--;}void setup() { pinMode(ENC_A, INPUT_PULLUP); pinMode(ENC_B, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(ENC_A), enkoderISR, RISING);}void loop() { compteur long; noInterrupts(); //interruptions courtes pour la lecture atomique counter = encoderCounter; interruptions(); //effectuer des transactions en toute sécurité avec le comptoir...}

Trois points critiques dans cet exemple sont ceux où l'IA manque souvent : (1) le encoderCounter partagé doit être « volatile » sinon l'optimisation du compilateur manquera les mises à jour ; (2) l'ISR doit être court ; (3) Lors de la lecture d'une variable multi-octets dans la boucle principale, les interruptions pour la lecture atomique doivent être fermées pendant une courte période, sinon ISR peut intervenir pendant la lecture et une valeur à moitié/corrompue peut être lue (condition de concurrence). Assurez-vous de vérifier si ces trois éléments sont présents dans le code AI.

Précision du registre et fiche technique

L'IA peut déformer de manière crédible l'adresse de registre d'un capteur ou le bit de configuration d'un MCU. Par exemple, le registre de gestion de l'alimentation d'une IMU MPU6050 est 0x6B ; Si l'IA donne 0x6A, le code est compilé, il semble fonctionner, mais le capteur ne se réveille pas. De telles erreurs ne sont détectées que par rapport à la fiche technique.

// Réveil MPU6050 : selon la fiche technique PWR_MGMT_1 = 0x6B, valeur 0x00#define MPU_ADDR 0x68#define PWR_MGMT_1 0x6B // <-- VERIFY from datasheetWire.beginTransmission(MPU_ADDR);Wire.write(PWR_MGMT_1);Wire.write(0x00); // se réveille du mode veille modeWire.endTransmission(true);

Attention : vérifiez chaque adresse de registre, masque de bits et adresse I2C/SPI fournies par l'IA à partir de la fiche technique. Ces valeurs sont spécifiques à la carte et à la puce ; La valeur dont l'IA « se souvient » peut provenir d'une autre révision de la puce. Un registre incorrect conduit silencieusement à un comportement incorrect.

Invite faible/Invite forte

FAIBLE : "Lire le capteur de température sur ESP32." (Quel capteur ? Quel protocole ? Quelle broche ? Code générique, probablement erroné.) FORT : "Lire un capteur de température DS18B20 sur ESP32 (framework Arduino) à partir de GPIO4 avec OneWire. Écrivez de manière non bloquante, échantillonnez toutes les 1 seconde (en utilisant un délai, basé sur les millisecondes). Définissez l'indicateur d'erreur en cas d'erreur de lecture (valeur fixe -127 ou 85). Veuillez spécifier chaque bibliothèque et connexion de broche que vous utilisez. dans le premier commentaire, pour des raisons de mémoire, utilisez char buffer au lieu de String."

Invite puissante ; Il donne la puce, le framework, le capteur, le protocole, la broche, le modèle d'échantillonnage, l'état d'erreur et la contrainte de mémoire. De cette façon, le résultat est à la fois vérifiable et réaliste.

Liste de contrôle de révision pour le code intégré

Avant de charger la sortie AI, passez-la par cette liste :

  1. Blocage : y a-t-il un retard ou un blocage prolongé dans la boucle principale ?
  2. volatile : les variables partagées avec ISR sont-elles volatiles ?
  3. Accès atomique : la variable partagée multi-octets est-elle sûre à lire ?
  4. Registre : Les adresses et les masques de bits sont-ils compatibles avec la fiche technique ?
  5. Mémoire : chaîne, grands tableaux, la récursivité crée-t-elle un débordement de niveau Ko ?
  6. Gestion des erreurs : les erreurs de lecture des capteurs et les délais d'attente de communication sont-ils gérés ?
  7. Démarrage sécurisé : les sorties de l'actionneur sont-elles placées dans un état sûr (passif) au démarrage ?

Mini-étui

L'ingénieur en systèmes embarqués Baran demande à l'IA d'écrire le code qui lit l'IMU pour un drone. Le code se compile et semble fonctionner, mais les valeurs d'angle n'ont aucun sens. Baran applique la liste de contrôle : compare les adresses des registres avec la fiche technique et constate que l'IA sort incorrectement le registre de configuration du gyroscope (0x1A au lieu de 0x1B), donc l'échelle de sensibilité est erronée. Une fois corrigées, les valeurs s'installent. Puis delay(10) est remarqué dans la boucle principale ; convertir cela en une structure basée sur les millisis, car bloquer la boucle de contrôle de vol est inacceptable. Enfin, il voit que la variable compteur partagée n'est pas volatile et l'ajoute. L'IA a rapidement donné le squelette ; Mais la liste d'examen a détecté trois erreurs distinctes : d'enregistrement, de blocage et volatile, et le matériel n'était pas du tout menacé.

Erreurs courantes

  • Tuer la réponse en temps réel en utilisant delay() dans la boucle de contrôle principale.
  • Évitez de rendre la variable partagée avec ISR volatile et de subir une corruption silencieuse des données.
  • Lecture d'une variable partagée multi-octets de manière non atomique et génération d'une condition de concurrence critique.
  • Ne pas vérifier les masques de registre/bits donnés par l'IA avec la fiche technique.
  • Création d'un débordement de mémoire en utilisant des chaînes et de grands tableaux dans une RAM limitée.
  • Oublier de sécuriser initialement les sorties des actionneurs.

En résumé

  • Code embarqué ; Il fonctionne avec une mémoire limitée, un timing serré et un accès direct aux registres.
  • Dans la boucle principale, un modèle non bloquant basé sur des millisecondes est utilisé à la place du retard.
  • L'ISR reste court ; les variables partagées doivent être volatiles et accessibles de manière atomique.
  • Les adresses de registre et les masques de bits sont toujours vérifiés par rapport à la fiche technique ; L’IA peut se tromper.
  • La mémoire, la gestion des erreurs et l'état de démarrage sécurisé sont toujours vérifiés.
  • Invite puissante ; Il comprend la puce, le framework, le capteur, le protocole, la broche et les contraintes.

Tâche de candidature

Choisissez un capteur (par exemple DS18B20, MPU6050 ou HC-SR04) et un microcontrôleur (Arduino/ESP32/STM32). Demandez à l'IA de générer un code de lecture non bloquant avec le puissant modèle d'invite de cette unité. Suivez ensuite les sept éléments de la liste de contrôle de révision un par un : comparez au moins une valeur de registre/pin avec la fiche technique, vérifiez les retards de boucle, vérifiez l'état volatile des variables partagées. Combien d'éléments ont été « réussis » du premier coup et combien ont nécessité une correction ? Notez chaque problème que vous rencontrez et sa solution.