Go et le matériel : pourquoi ce n'est pas une blague ?
\nQuand on entend l'expression « développement embarqué », on imagine généralement du C, de l'assembleur et un débogage pénible via une LED. Mais le monde ne s'arrête pas là. Aujourd'hui, Go (ou Golang) frappe de plus en plus sûrement à la porte du monde des microcontrôleurs. Et il ne frappe pas pour rien, mais avec des goroutines, un ramasse-miettes et des interfaces intégrées.
\nDans cet article, nous allons voir à quoi ressemble le développement embarqué en Go, écrire du code réel pour un microcontrôleur hypothétique et comprendre si le jeu en vaut la chandelle. Spoiler : oui, si vous en avez assez des fuites mémoire et que vous aimez le code lisible.
\n\nPourquoi Go plutôt que C ? Les trois piliers
\nL'embarqué classique, c'est du C. Mais Go a trois fonctionnalités killer qui poussent les ingénieurs à revoir leurs habitudes :
\n- \n
- Sécurité mémoire : plus de pointeurs sauvages qui peuvent partir dans l'espace. Le compilateur Go est plus strict que le compilateur C. \n
- Goroutines : des threads légers qui s'adaptent parfaitement à l'architecture événementielle des microcontrôleurs. \n
- Multiplateforme : vous écrivez le code sur Mac, et vous compilez pour ARM Cortex-M. Sans prise de tête. \n
Bien sûr, il y a un hic : le Go natif (gc) ne sait pas compiler pour les petits MCU. Mais il y a le projet TinyGo — un compilateur qui adapte Go aux puces avec des kilo-octets de mémoire. C'est sur lui que nous allons nous concentrer.
\n\nConfiguration de l'environnement : TinyGo et votre carte
\nAvant d'écrire du code, préparons notre poste de travail. Pour le développement embarqué en Go, vous aurez besoin de :
\n- \n
- Installer TinyGo :
brew install tinygo(ou le télécharger depuis le site officiel). \n - Installer la chaîne d'outils pour votre carte (par exemple, ARM GCC pour STM32). \n
- Connecter la carte via USB. \n
Vérifions que tout fonctionne :
\ntinygo version\ntinygo: 0.31.0 (linux/amd64)\n\nMaintenant, vous pouvez compiler du code pour n'importe quelle carte supportée : tinygo build -target=arduino-nano -o firmware.hex main.go.
Premier blink : une LED en Go
\nUn grand classique. On se connecte à une broche, on fait clignoter. Voici à quoi ressemble la programmation de microcontrôleurs en Go :
\npackage main\n\nimport (\n "machine"\n "time"\n)\n\nfunc main() {\n // La LED intégrée est généralement sur la broche 13 (ou LED_BUILTIN)\n led := machine.LED\n led.Configure(machine.PinConfig{Mode: machine.PinOutput})\n\n for {\n led.High()\n time.Sleep(500 * time.Millisecond)\n led.Low()\n time.Sleep(500 * time.Millisecond)\n }\n}\n\nOn compile et on flashe sur la carte :
\ntinygo flash -target=arduino-nano -port=/dev/ttyUSB0 main.go\n\nEt voilà ! La LED clignote. Notez que nous utilisons le paquet machine — c'est l'abstraction matérielle de TinyGo. Elle cache le travail avec les registres, mais offre une interface Go propre.
Travail avec GPIO et interruptions
\nDans les projets réels, il ne suffit pas de faire clignoter. Il faut lire des boutons, des capteurs, réagir aux événements. En Go pour les systèmes embarqués, les interruptions sont implémentées via des canaux et des goroutines. Exemple : attachons un gestionnaire d'appui sur un bouton.
\npackage main\n\nimport (\n "machine"\n "fmt"\n)\n\nfunc main() {\n button := machine.D2\n button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})\n\n // On attend l'appui (pin == LOW, car pull-up vers l'alimentation)\n for {\n if !button.Get() {\n fmt.Println("Bouton pressé !")\n }\n }\n}\n\nMais c'est une boucle active. On veut plus efficace ? Utilisons une interruption via un canal :
\nfunc main() {\n button := machine.D2\n button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})\n\n // Canal pour les événements\n ch := make(chan bool, 1)\n button.SetInterrupt(machine.PinFalling,