Tinygo mit Neovim auf Nixos
In freudiger Erwartung der GopherConEU 2023 wollte ich ein Board mit RP2040 Chipsatz bestellen. Da tinygo
von Haus aus den Raspberry Pi Pico unterstützt, war das auch gleich das Gerät der Wahl.
Während der Holder nett und insgesamt irrelevant ist, hat mich am Ende das Wifi fast wahnsinnig werden lassen, doch dazu später mehr.
Das Setup
Der Code
Ein simples “Hallo, Welt” des Embedded Computing: Blinking LED
Zur Vollständigkeit hier einmal eingefügt gibt es den genauen Ablauf und weiterführende Details dazu in obiger Dokumentation.
package main
import (
"machine"
"time"
)
func main() {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.Low()
time.Sleep(time.Millisecond * 500)
led.High()
time.Sleep(time.Millisecond * 500)
}
}
Mit Definition des TinyGo Target wird das machine
Package mit Leben gefüllt und wir können wie gehabt entwickeln.
Auch dazu gibt es eine IDE Integration Documentation, die aber natürlich wieder nicht auf meine esoterischen Eigenarten zugeschnitten ist.
Immerhin gibt es neben einer sehr guten vim-go Integration auch ein tinygo.vim Package, dass es auszuprobieren gilt: Selbst ist der Gopher!
Die Herausforderungen
Spoiler: Am Ende habe ich das Sample dann doch tatsächlich lauffähig bekommen.
Der Weg dort hin ist hier aufgelistet.
vim Integration
Obwohl ich mich vim-go echt gute Erfahrungen gemacht hat, blieben diese bei tinygo.vim bislang aus.
Der Umfang ist zwar gering, doch führt ein beherztes :TinygoTarget pico
unerwarteterweise zu einem Fehler:
Zeile 61:
E492: Kein Editorbefehl: LspStop
Diesen Punkt habe ich übersprungen, das war nicht mein Kaninchenbau.
NixOS Integration
Der Pico unterstützt den uf2 Bootloader, das heißt, sobald eine .uf2
kompatible Binärdatei in den USB Mountpoint übertragen wird, rennt dass Gerät mit eben dieser Software los.
Leider generiert tinygo
für den Pico aber eine .elf
Datei.
$ tinygo build --target=pico
$ ls
go.mod hello.elf main.go
Das bewegt den Pico zu rein überhaupt gar nichts.
Nun kann tinygo
angeblich direkt auf das Gerät flashen, aber auch das ist nur angeblich:
$ tinygo flash --target=pico
error: failed to flash /tmp/tinygo2877794396/main.uf2: unable to locate device: RPI-RP2
Aber: Wir haben eine ordentliche main.uf2
Datei! Warum auch immer die nicht beim build
gebaut wird…
Dennoch können wir damit arbeiten, indem wir mittels -work
mitteilen, dass das Arbeitsverzeichnis erhalten bleiben soll.
$ tinygo flash -work -target=pico
WORK=/tmp/tinygo2877794396
error: failed to flash /tmp/tinygo2877794396/main.uf2: unable to locate device: RPI-RP2
$ sudo cp /tmp/tinygo2877794396/main.uf2 ~/usb
Daraufhin teilt uns dmesg
mit, dass der Pico erfolgreich neu gestartet ist.
Aber es blinkt keine LED.
PicoW != Pico
Beim Pico W handelt es sich um die Wifi Variante.
Akuell wird Wifi von TinyGo noch nicht unterstützt, aber das ist nicht das Problem.
Das Problem ist, dass der Wifi Chip irgendwo angeschlossen sein muss.
Dieses Irgendwo scheint zufällig GP25
zu sein, der im handelsüblichen Pico auf die LED fällt.
Entsprechend mappt TinyGo auch machine.LED
für --target=pico
auf GP25
.
Leider heißt die LED auf dem Pico W aber WL_GPIO0
und ist entsprechend I/O Pin 0 des Infineon Wireless Chipsatzes.
Zusätzlich findet sich im gesamten Pin Plan kein ``GP25`, an den sich einfach eine externe LED anschließen ließe.
Die Raspberry Pico Dokumentation hält besagte Pin Pläne für beide Varianten bereit.
Also hilft nur ein beherzter Griff in die Elektronikkiste, eine kleine Codeanpassung und die Erfahrung im Upload der fertigen .uf2
Datei, und schon läuft es:
package main
import (
"machine"
"time"
)
func main() {
led := machine.GP22
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.Low()
time.Sleep(500 * time.Millisecond)
led.High()
time.Sleep(500 * time.Millisecond)
}
}
Am Ende blinkt eine LED. Geschafft!