ac6-formation, un département d'Ac6 SAS
FR
FrançaisEnglish
 
go-up

ac6 ac6-formation

Faire écrire du code embarqué par un LLM : ce qui marche et ce qui casse

Un modèle de langage produit du code qui ressemble à du code correct. Sur un serveur, l'écart entre les deux se voit vite : le test échoue, l'exception remonte. Sur un microcontrôleur, un registre inventé ne provoque pas d'erreur, il configure autre chose, et le défaut apparaît trois semaines plus tard sur une carte sur dix.

C'est cette asymétrie qui rend l'assistance par IA différente en embarqué, et non une prétendue incapacité des modèles.

Ce qui marche vraiment

La transformation de code. Convertir une machine à états d'un format à un autre, passer d'un jeu d'API HAL à un autre, ajouter systématiquement une vérification de retour sur trois cents appels. Le modèle excelle quand la source de vérité est dans le contexte et que la tâche est mécanique.

L'écriture de bancs de test. Générer des cas limites pour une fonction de parsing de trame, produire un banc de test qui couvre les débordements, les longueurs nulles, les CRC invalides. C'est fastidieux, sans piège matériel, et le modèle est bon à ce jeu.

Les squelettes de pilote. Une structure de pilote Zephyr ou Linux avec ses tables d'initialisation, ses macros et son enregistrement est très codifiée. Le modèle en produit une base saine, qu'il reste à remplir.

L'explication de code existant. Comprendre pourquoi une fonction héritée manipule un registre d'une certaine façon, à condition de lui fournir la documentation du composant.

Ce qui casse, et pourquoi

Les registres et les champs de bits inventés. C'est le mode d'échec dominant. Le modèle a vu des milliers de pilotes STM32 pendant son entraînement ; il produit un nom de registre cohérent avec ce corpus, mais qui n'existe pas sur votre référence exacte. Le compilateur ne peut pas le savoir si le nom vient d'un en-tête générique, et l'écriture part dans un registre réservé.

Les hypothèses de timing. Un délai calculé « à peu près », une boucle d'attente sans borne, une temporisation en nombre d'itérations plutôt qu'en microsecondes. Le code fonctionne sur le bureau et échoue à froid, ou après un changement de fréquence d'horloge.

Les problèmes de concurrence. Un modèle produit rarement les barrières mémoire nécessaires, oublie volatile sur une variable partagée avec une interruption, et propose des sections critiques trop larges ou trop étroites. C'est un domaine où l'erreur est invisible à la relecture rapide.

La gestion mémoire en contexte contraint. Des allocations dynamiques là où il ne doit pas y en avoir, des tampons sur la pile dimensionnés sans considération pour une pile de 2 kilooctets, de la récursion.

Les règles de codage. MISRA C, l'interdiction de malloc après l'initialisation, les conventions maison : un modèle ne les respecte que si on les lui rappelle explicitement, à chaque fois.

Le contexte change tout

La différence entre un assistant inutile et un assistant productif ne tient pas au modèle, mais à ce qu'on lui donne.

Fournissez le fichier d'en-tête du composant, pas la référence du composant. Coller les définitions de registres pertinentes, ou le fragment du manuel de référence, supprime la classe entière des registres inventés. Le modèle cesse de deviner puisqu'il lit.

Fournissez un exemple de votre code existant. Un pilote déjà écrit dans le projet vaut mieux qu'une page de consignes de style : le modèle imite ce qu'il voit.

Nommez les contraintes explicitement. « Pas d'allocation dynamique, pile de 2 Ko maximum, appelable depuis un contexte d'interruption, conforme MISRA C 2012 règle 21.3 » produit un résultat très différent de « écris-moi un pilote ».

C'est exactement ce que formalisent les mécanismes de contexte structuré, du type Model Context Protocol, qui donnent au modèle un accès contrôlé aux fiches techniques et aux sources du projet plutôt qu'à sa seule mémoire d'entraînement.

La boucle de validation, non négociable

Le code produit par un modèle doit franchir les mêmes filtres que le code d'un stagiaire compétent mais sans expérience matérielle.

  1. Compilation avec tous les avertissements, en -Wall -Wextra -Werror. Une bonne part des inventions tombe ici.
  2. Analyse statique, cppcheck ou un outil MISRA. Elle attrape les débordements de tampon et les conversions douteuses que la relecture laisse passer.
  3. Relecture ciblée sur trois points : chaque accès registre est-il vérifié contre le manuel, chaque variable partagée avec une interruption est-elle volatile, chaque boucle d'attente a-t-elle une borne.
  4. Test sur cible, pas seulement en simulation.

Le point 3 est celui qui demande un ingénieur. Les trois autres s'automatisent.

Une règle simple pour décider

Confiez au modèle ce que vous pouvez vérifier plus vite que vous ne l'écririez. Un banc de test, une conversion mécanique, un squelette : la vérification est rapide, le gain est réel.

Ne lui confiez pas ce dont la vérification coûte plus cher que l'écriture. Une séquence d'initialisation d'horloge, une gestion d'interruption critique, un protocole de synchronisation entre cœurs : relire ligne à ligne contre le manuel de référence prend plus de temps que d'écrire soi-même, et donne une confiance moindre.

Références

Pour aller plus loin

Ces réflexes se construisent en pratiquant sur du code réel, avec les fiches techniques dans le contexte et une boucle de validation en place. C'est l'objet de notre formation au développement embarqué assisté par IA.