concertina

Elecronic concertina
git clone https://git.woozle.org/neale/concertina.git

commit
a7eed5f
parent
a5cef60
author
Neale Pickett
date
2026-02-11 20:16:53 -0700 MST
Move to tinygo!
8 files changed,  +148, -1
A go.mod
A go.sum
M .gitignore
+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+
A cmd/concertina/concertina.go
+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+}
A cmd/concertina/midi.go
+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=
M src/Makefile
+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 
M src/blink.c
+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 }