Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/boisgera/tinygo-arduino
TinyGo for Arduino
https://github.com/boisgera/tinygo-arduino
arduino golang iot tinygo
Last synced: 25 days ago
JSON representation
TinyGo for Arduino
- Host: GitHub
- URL: https://github.com/boisgera/tinygo-arduino
- Owner: boisgera
- Created: 2022-10-18T20:12:15.000Z (about 2 years ago)
- Default Branch: master
- Last Pushed: 2022-12-25T09:58:12.000Z (almost 2 years ago)
- Last Synced: 2023-03-22T17:07:26.458Z (over 1 year ago)
- Topics: arduino, golang, iot, tinygo
- Language: HTML
- Homepage:
- Size: 10.5 MB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# TinyGo for Arduino
![](slides/images/sahand-babali-owjrvbyXYyc-unsplash.jpg)
## π§ Introduction
- π [Slide deck](https://boisgera.github.io/tinygo-arduino/slides/index.html)
## π Documentation
- π [TinyGo `machine` package for Arduino Uno](https://tinygo.org/docs/reference/microcontrollers/machine/arduino/).
- π [Arduino Projects Book](https://github.com/boisgera/tinygo-arduino/raw/master/doc/arduino-projects-book.pdf), license [CC-BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/3.0/) by Arduino LLC.
## π§° Do It Yourself (DIY)
### π» Hello world! (PC/Go version)
![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainfunc main() {
println("Hello! π")
}
```Run from source:
```
$ go run app.go
Hello! π
```Compile:
```
$ go build app.go
$ ls
app app.go
```Execute:
```
$ ./app
Hello! π
```File size:
```
$ du -h app
1,2M app
```Cross-compile (Windows):
```
$ GOOS=windows go build app.go
ls
app app.exe app.go
$ du -h app.exe
1,2M app.exe
```Cross-compile (Apple Silicon):
```
$ rm app app.exe
$ ls
app.go
$ GOOS=darwin GOARCH=arm64 go build app.go
$ ls
app app.go
$ du -h app
1,1M app
```βΉοΈ If you use [Visual Studio Code](https://code.visualstudio.com/),
you may install the [Go extension](https://marketplace.visualstudio.com/items?itemName=golang.go)
to get code completion, signature help, etc.### π» Hello world! (PC/TinyGo version)
![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainfunc main() {
println("Hello! π")
}
```Run from source:
```
$ tinygo run app.go
Hello! π
```Build:
```
$ tinygo build app.go
(base) boisgera@oddball:~/tmp/sandbox$ ls
app app.go
(base) boisgera@oddball:~/tmp/sandbox$ du -h app
68K app
```Execute:
```
$ ./app
Hello! π
```### π Hello world! (Arduino/TinyGo version)
![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainfunc main() {
println("Hello from Arduino! π")
}
``````bash
tinygo flash -target=arduino app.go
``````
avrdude: AVR device initialized and ready to accept instructionsReading | ################################################## | 100% 0.00s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "/tmp/tinygo287452646/main.hex"
avrdude: writing flash (1174 bytes):Writing | ################################################## | 100% 0.20s
avrdude: 1174 bytes of flash written
avrdude: verifying flash memory against /tmp/tinygo287452646/main.hex:
avrdude: load data flash data from input file /tmp/tinygo287452646/main.hex:
avrdude: input file /tmp/tinygo287452646/main.hex contains 1174 bytes
avrdude: reading on-chip flash data:Reading | ################################################## | 100% 0.16s
avrdude: verifying ...
avrdude: 1174 bytes of flash verifiedavrdude done. Thank you.
```
If you are familiar with Python, you can read this message with:
```bash
pip install pyserial
```![](https://img.shields.io/static/v1?label=&message=read.py&logo=python&color=white)
```python
import serial# βοΈ Configuration
BAUD_RATE = 9600
SERIAL_PORT = "/dev/ttyACM0"# β³ Loop
with serial.Serial(SERIAL_PORT, BAUD_RATE) as file:
while True:
bytes = file.readline().strip()
print(bytes.decode("utf-8"))
`````` bash
$ python read.py
Hello from Arduino! π
β³
```But there is a simpler alternative with TinyGo:
```bash
$ tinygo flash -monitor -baudrate=9600 -target arduino app.go
...
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
Hello from Arduino! π
β³
```### β±οΈ Time
![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport "time"
func main() {
for i := 0; i < 3; i++ {
println("Hello from Arduino! π")
time.Sleep(500 * time.Millisecond)
}
}
``````bash
$ tinygo flash -monitor -baudrate=9600 -target arduino app.go
...
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
Hello from Arduino! π
Hello from Arduino! π
Hello from Arduino! π
β³
```![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport "time"
func main() {
for {
println("Hello from Arduino! π")
time.Sleep(500 * time.Millisecond)
}
}
``````bash
$ tinygo flash -monitor -baudrate=9600 -target arduino app.go
...
Connected to /dev/ttyACM0. Press Ctrl-C to exit.
Hello from Arduino! π
Hello from Arduino! π
Hello from Arduino! π
β³
```β οΈ The standard [`Timer` & `Ticker` standard API](https://pkg.go.dev/time) would be super
nice to have, but [they are buggy at the moment](https://github.com/tinygo-org/tinygo/issues/2169#issuecomment-985644057).### π₯ Blinky
![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport (
"machine"
"time"
)var Output = machine.PinConfig{Mode: machine.PinOutput}
func main() {
led := machine.LED // i.e. machine.D13 (a Pin)
led.Configure(Output)
for {
led.Low()
time.Sleep(1000 * time.Millisecond)
led.High()
time.Sleep(3000 * time.Millisecond)
}
}
``````bash
tinygo flash -target=arduino app.go
```βΉοΈ If you use [Visual Studio Code](https://code.visualstudio.com/),
you may install the [TinyGo extension](https://marketplace.visualstudio.com/items?itemName=tinygo.vscode-tinygo) and select the `arduino` target to get code completion and signature
help for the `machine` package.
For more details, refer to the [TinyGo documentation](https://tinygo.org/docs/guides/ide-integration/vscode/).### π Intel HEX
> **Intel hexadecimal object file format**, Intel hex format or Intellec Hex is a file format that conveys binary information in ASCII text form. It is commonly used for programming microcontrollers, EPROMs, and other types of programmable logic devices and hardware emulators. In a typical application, a compiler or assembler converts a program's source code (such as in C or assembly language) to machine code and outputs it into a HEX file. [...] The HEX file is then read by a programmer to write the machine code into a PROM or is transferred to the target system for loading and execution.
([Wikipedia](https://en.wikipedia.org/wiki/Intel_HEX))
```bash
tinygo build -o app.hex -target=arduino app.go
``````
$ cat app.hex
:100000000C9434000C9472020C9472020C947202E0
:100010000C9472020C9472020C9464020C9472029E
:100020000C9472020C9472020C9472020C94720280
...
:10007000BEBF0F92A0E0B3E0C4E6D3E0EEE1F5E04E
:1005700066726F6D2041726475696E6F2120F09F05
:02058000918B5D
:00000001FF
``````bash
pip install intelhex
``````bash
$ hexinfo.py app.hex
- file: 'app.hex'
data:
- { first: 0x00000000, last: 0x00000581, length: 0x00000582 }
``````pycon
>>> 0x00000582
1410
```(1410 bytes, well below the 32 kb limit for Arduino Uno).
Then instead of `tinygo flash`, do:
```bash
avrdude -C /etc/avrdude.conf -p atmega328p -c arduino -P /dev/ttyACM0 -D -U flash:w:app.hex:i
``````
$ man avrdude
AVRDUDE(1) BSD General Commands Manual AVRDUDE(1)NAME
avrdude β driver program for ``simple'' Atmel AVR MCU programmerSYNOPSIS
avrdude -p partno [-b baudrate] [-B bitclock] [-c programmer-id]
[-C config-file] [-D] [-e] [-E exitspec[,exitspec]] [-F]
[-i delay] [-n -logfile] [-n] [-O] [-P port] [-q] [-s] [-t] [-u]
[-U memtype:op:filename:filefmt] [-v] [-x extended_param] [-V]
...
```### π» WokWi Simulator
![WokWi β Online Arduino Simulator](media/wokwi.png)
1. Sign into .
2. Start from Scratch with Arduino Uno. You may rename the project "Blinky"
instead of "sketch.ino" and delete the `sketch.ino` file ; we won't need it.3. In the editor, right-click and open the command palette (or press F1).
4. Select "Load HEX File and Start Simulation ..." and upload your `app.hex` file.
5. Profit! π
### π₯ LED
To replicate the Blinky project, but with an external LED instead of the
onboard one, we need little change in the `app.go` program; if we intend
to connect the LED D4, we have:![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport (
"machine"
"time"
)var Output = machine.PinConfig{Mode: machine.PinOutput}
func main() {
led := machine.D4
led.Configure(Output)
for {
led.Low()
time.Sleep(1000 * time.Millisecond)
led.High()
time.Sleep(3000 * time.Millisecond)
}
}
```![WokWi β External LED](media/wokwi-LED.png)
### π² Toggle Button + LED
To switch the LED state, press the button during at least 0.1 seconds,
then release it.![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport (
"machine"
"time"
)var Input = machine.PinConfig{Mode: machine.PinInput}
var Output = machine.PinConfig{Mode: machine.PinOutput}var ButtonPin = machine.D2
var ButtonWasPressed = falsevar LightPin = machine.D4
var LightOn = falsefunc setup() {
LightPin.Configure(Output)
ButtonPin.Configure(Input)
}func ButtonHandler() {
ButtonPressed := !ButtonPin.Get()
ButtonRelease := !ButtonPressed && ButtonWasPressed
if ButtonRelease {
LightOn = !LightOn
}
ButtonWasPressed = ButtonPressed
}func LightHandler() {
if LightOn {
LightPin.High()
} else {
LightPin.Low()
}
}func main() {
setup()
for {
ButtonHandler()
LightHandler()
time.Sleep(100 * time.Millisecond)
}
}
```![WokWi β External LED](media/wokwi-button-LED.png)
### π ADC
![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport (
"machine"
"time"
)var adc = machine.ADC{Pin: machine.ADC0}
func setup() {
machine.InitADC()
}func main() {
setup()
for {
println(adc.Get() >> 6)
time.Sleep(1 * time.Second)
}
}
```![WokWi β ADC](media/wokwi-ADC.png)
`diagram.json`:
```json
{
"version": 1,
"author": "SΓ©bastien BoisgΓ©rault",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} },
{
"type": "wokwi-slide-potentiometer",
"id": "pot1",
"top": 223.8,
"left": 38.76,
"attrs": { "travelLength": "30" }
}
],
"connections": [
[ "uno:GND.2", "pot1:GND", "black", [ "v36.18", "h-178.04" ] ],
[ "uno:5V", "pot1:VCC", "red", [ "v38.57", "h-120.71" ] ],
[ "uno:A0", "pot1:SIG", "green", [ "v21.83", "h56.09", "v118.38", "h-229.59" ] ]
]
}
```### π PWM
See [Using PWM](https://tinygo.org/docs/tutorials/pwm/).
β οΈ Floating-point computations are not used here. They are not supported by
the hardware and thus have to be emulated in software and this is costly.![](https://img.shields.io/static/v1?label=&message=app.go&logo=go&color=white)
```go
package mainimport (
"machine"
"time"
)var pwm machine.PWM
var pwmPin = machine.D5
var period uint64
var ch uint8func setup() {
pwm.Configure(machine.PWMConfig{})
period = pwm.Period() // 16_000 ns
var err error
ch, err = pwm.Channel(pwmPin)
if err != nil {
panic(err)
}
}func main() {
setup()
top := pwm.Top()
x := top
for {
println(x)
pwm.Set(ch, x)
x = x - top/100
if x == 0 {
x = top
}
time.Sleep(10 * time.Duration(period))
}
}
```![WokWi β ADC](media/wokwi-PWM.png)
`diagram.json`:
```json
{
"version": 1,
"author": "SΓ©bastien BoisgΓ©rault",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 159.41, "left": 11.03, "attrs": {} },
{
"type": "wokwi-led",
"id": "led1",
"top": 80.49,
"left": 149.12,
"attrs": { "color": "green" }
}
],
"connections": [ [ "uno:GND.1", "led1:C", "black", [ "v0" ] ], [ "uno:5", "led1:A", "green", [ "v0" ] ] ]
}
```