Go embarcado: Escrevendo firmware em uma linguagem que não explode a pilha

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Go e hardware: por que isso não é brincadeira?

\n

Quando se ouve a expressão "desenvolvimento embarcado", geralmente se imagina C, assembly e uma depuração dolorosa através de um LED. Mas o mundo não para. Hoje, Go (ou Golang) está batendo cada vez mais forte na porta do mundo dos microcontroladores. E não está batendo à toa, mas com goroutines, coletor de lixo e interfaces integradas.

\n

Neste artigo, vamos entender como é o desenvolvimento embarcado em Go, escrever código real para um microcontrolador hipotético e descobrir se vale a pena. Spoiler: sim, se você está cansado de vazamentos de memória e adora código legível.

\n\n

Por que Go e não C? Três pilares

\n

O embarcado clássico é C. Mas Go tem três killer-features que fazem os engenheiros repensarem seus hábitos:

\n
    \n
  • Segurança de memória: sem ponteiros selvagens que podem voar para o espaço. O compilador Go é mais rigoroso que o compilador C.
  • \n
  • Goroutines: threads leves que se encaixam perfeitamente na arquitetura orientada a eventos dos microcontroladores.
  • \n
  • Multiplataforma: você escreve código no Mac e compila para ARM Cortex-M. Sem complicações.
  • \n
\n

Claro, há uma ressalva: o Go nativo (gc) não sabe compilar para MCUs pequenos. Mas existe o projeto TinyGo — um compilador que adapta o Go para hardware com kilobytes de memória. É nele que vamos focar.

\n\n

Configuração do ambiente: TinyGo e sua placa

\n

Antes de escrever código, vamos preparar o ambiente de trabalho. Para desenvolvimento embarcado em Go, você precisará de:

\n
    \n
  1. Instalar o TinyGo: brew install tinygo (ou baixar do site oficial).
  2. \n
  3. Instalar a toolchain para sua placa (ex: ARM GCC para STM32).
  4. \n
  5. Conectar a placa via USB.
  6. \n
\n

Vamos verificar se tudo funciona:

\n
tinygo version\ntinygo: 0.31.0 (linux/amd64)\n
\n

Agora podemos compilar código para qualquer placa suportada: tinygo build -target=arduino-nano -o firmware.hex main.go.

\n\n

Primeiro blink: LED em Go

\n

O clássico do gênero. Conectamos ao pino, alternamos o sinal. Veja como é a programação de microcontroladores em Go:

\n
package main\n\nimport (\n    "machine"\n    "time"\n)\n\nfunc main() {\n    // O LED embutido geralmente está no pino 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
\n

Compilamos e gravamos na placa:

\n
tinygo flash -target=arduino-nano -port=/dev/ttyUSB0 main.go\n
\n

Voilà! O LED pisca. Observe: usamos o pacote machine — uma abstração de hardware do TinyGo. Ele esconde o trabalho com registradores, mas fornece uma interface Go limpa.

\n\n

Trabalhando com GPIO e interrupções

\n

Em projetos reais, não basta apenas piscar. É preciso ler botões, sensores, reagir a eventos. Em Go para sistemas embarcados, as interrupções são implementadas através de canais e goroutines. Exemplo: vamos criar um handler para o pressionamento de um botão.

\n
package 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    // Aguarda o pressionamento (pin == LOW, pois há pull-up para VCC)\n    for {\n        if !button.Get() {\n            fmt.Println("Botão pressionado!")\n        }\n    }\n}\n
\n

Mas isso é um busy loop. Quer algo mais eficiente? Use interrupção através de canal:

\n
func main() {\n    button := machine.D2\n    button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})\n\n    // Canal para eventos\n    ch := make(chan bool, 1)\n    button.SetInterrupt(machine.PinFalling,                

Blogs

Book Recommendations