- commit
- a7eed5f
- parent
- a5cef60
- author
- Neale Pickett
- date
- 2026-02-11 20:16:53 -0700 MST
Move to tinygo!
8 files changed,
+148,
-1
+2,
-0
1@@ -1,3 +1,5 @@
2+build/
3+
4 pcb/*
5
6 3d/*.stl
A
Makefile
+16,
-0
1@@ -0,0 +1,16 @@
2+flash: flash-qtpy
3+flash-qtpy: build/qtpy/concertina.bin
4+ stty -F /dev/ttyACM0 1200 && sleep 1 # Reset into bootloader
5+ bossac --offset=0x2000 -w -v $< -R
6+
7+build: build/qtpy/concertina.bin
8+
9+clean:
10+ rm -rf build/*
11+
12+build/%/concertina.bin: cmd/concertina
13+ tinygo build -o $@ -target=$* ./$</...
14+
15+layouts.h: layouts.txt mklayouts.py
16+ ./mklayouts.py $< > $@
17+
+87,
-0
1@@ -0,0 +1,87 @@
2+package main
3+
4+import (
5+ "image/color"
6+ "machine"
7+ "time"
8+ "tinygo.org/x/drivers"
9+ "tinygo.org/x/drivers/ssd1306"
10+ "tinygo.org/x/drivers/ws2812"
11+)
12+
13+// For crying out loud.
14+// https://github.com/tinygo-org/drivers/issues/837`
15+var White = color.RGBAModel.Convert(color.White).(color.RGBA)
16+var Black = color.RGBAModel.Convert(color.Black).(color.RGBA)
17+
18+type Concertina struct {
19+ display *ssd1306.Device
20+ tonegen MidiWriter
21+ i2c drivers.I2C
22+}
23+
24+func NewConcertina(vs1053Reset machine.Pin) (c *Concertina) {
25+ // Make the LED red during setup
26+ machine.NEOPIXELS_POWER.Configure(machine.PinConfig{machine.PinOutput})
27+ machine.NEOPIXELS_POWER.High()
28+ machine.NEOPIXELS.Configure(machine.PinConfig{machine.PinOutput})
29+ pixel := ws2812.New(machine.NEOPIXELS)
30+ pixel.WriteColors([]color.RGBA{color.RGBA{0x10, 0, 0, 0}})
31+
32+ vs1053Reset.Configure(machine.PinConfig{machine.PinOutput})
33+ vs1053Reset.Low()
34+ machine.DefaultUART.Configure(machine.UARTConfig{
35+ BaudRate: 31250,
36+ TX: machine.UART_TX_PIN,
37+ RX: machine.UART_RX_PIN,
38+ })
39+
40+ if err := machine.I2C0.Configure(machine.I2CConfig{}); err != nil {
41+ println(err)
42+ return
43+ }
44+
45+ c = &Concertina {
46+ tonegen: MidiWriter{Writer: machine.DefaultUART},
47+ i2c: machine.I2C0,
48+ }
49+
50+
51+ // ssd1306 setup already has a delay, so we use that to reset the vs1053
52+ vs1053Reset.High()
53+
54+ c.display = ssd1306.NewI2C(c.i2c)
55+ c.display.Configure(
56+ ssd1306.Config{
57+ Width: 128,
58+ Height: 32,
59+ Address: 0x3C,
60+ },
61+ )
62+
63+
64+ c.tonegen.SetPatch(22) // General MIDI harmonica
65+
66+ // init is done, turn off the LED
67+ machine.NEOPIXELS_POWER.Low()
68+
69+ return
70+}
71+
72+func main() {
73+ c := NewConcertina(machine.D3)
74+
75+ var x int
76+ for {
77+ c.display.ClearBuffer()
78+ c.display.FillRectangle(int16(x), 28 - int16(x % 28), 4, 4, White)
79+ c.display.Display()
80+ x = (x + 1) % 120
81+
82+ c.tonegen.NoteOn(byte(x))
83+
84+ time.Sleep(200 * time.Millisecond)
85+
86+ c.tonegen.NoteOff(byte(x))
87+ }
88+}
+28,
-0
1@@ -0,0 +1,28 @@
2+package main
3+
4+import "io"
5+
6+type MidiWriter struct {
7+ io.Writer
8+ Channel byte
9+}
10+
11+func (w MidiWriter) NoteOnVelocity(note byte, velocity byte) {
12+ w.Write([]byte{0x90 + w.Channel, note, velocity})
13+}
14+
15+func (w MidiWriter) NoteOn(note byte) {
16+ w.NoteOnVelocity(note, 127)
17+}
18+
19+func (w MidiWriter) NoteOffVelocity(note byte, velocity byte) {
20+ w.Write([]byte{0x80 + w.Channel, note, velocity})
21+}
22+
23+func (w MidiWriter) NoteOff(note byte) {
24+ w.NoteOffVelocity(note, 127)
25+}
26+
27+func (w MidiWriter) SetPatch(patch byte) {
28+ w.Write([]byte{0xC0 + w.Channel, patch})
29+}
A
go.mod
+7,
-0
1@@ -0,0 +1,7 @@
2+module woozle.org/neale/concertina
3+
4+go 1.24.4
5+
6+require tinygo.org/x/drivers v0.34.0
7+
8+require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
A
go.sum
+4,
-0
1@@ -0,0 +1,4 @@
2+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
3+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
4+tinygo.org/x/drivers v0.34.0 h1:lw8ePJeUSn9oICKBvQXHC9TIE+J00OfXfkGTrpXM9Iw=
5+tinygo.org/x/drivers v0.34.0/go.mod h1:ZdErNrApSABdVXjA1RejD67R8SNRI6RKVfYgQDZtKtk=
+1,
-1
1@@ -17,7 +17,7 @@ blink.elf: blink.o
2 avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature $< $@
3
4 clean:
5- rm -f *.elf *.o *.hex .upload
6+ rm -f *.elf *.o *.hex
7
8
9
+3,
-0
1@@ -3,6 +3,9 @@
2 #include <avr/io.h>
3 #include <avr/interrupt.h>
4
5+// CPU frequency in Hertz
6+#define F_CPU (1 * 1000000UL)
7+
8 void init(void) {
9 DDRB = 0xff; // All port B pins are outputs
10 }