At the after-party of Go Conference mini 2023 Winter IN KYOTO1, sago35 gave me an sgkey micropad assembly kit. I had already been interested in custom keyboards, and sago35’s talk “Continued: The World of Custom Keyboards Made with TinyGo2” along with the live coding was so interesting that I decided to buy the necessary parts and have some fun with sgkey and TinyGo3.

The Japanese version of this article is available here.

Assembling the sgkey

Follow the guide. I prepared a Seeeduino XIAO (not RP2040) along with the optional LCD display.

Solder the diodes, resistors, pin sockets, and key switches in order. I hadn’t soldered since middle school, so my technique was a bit rough.

After that, attach the keycaps, XIAO, and LCD module, then add the rubber feet to complete the build.

Running sgkey with TinyGo

Sample Program

First, flash the sample program. Select xiao as the target, not xiao-rp2040.

$ tinygo flash -target=xiao -size=short .
   code    data     bss |   flash     ram
  81744    2284    7332 |   84028    9616

At this point, macOS recognized it as a keyboard. This is handled nicely by sago35/tinygo-keyboard.

You can type “tinygo” with the 6 keys, and it’s also displayed on the LCD. Pretty impressive.

LED Blinking

Next, let’s try blinking an LED. The Seeeduino XIAO has 4 LEDs, 3 of which can be controlled. Let’s blink one of the blue LEDs (LED2).

package main

import (
	"machine"
	"time"
)

func main() {
	led := machine.LED2
	led.Configure(machine.PinConfig{Mode: machine.PinOutput})
	for {
		led.High()
		time.Sleep(500 * time.Millisecond)
		led.Low()
		time.Sleep(500 * time.Millisecond)
	}
}

You can see the blue LED blinking. The green LED is always on. Maybe I should have made it flash more aggressively.

Running sgkey with Vial

sago35/tinygo-keyboard supports Vial, which lets you change key mappings via a GUI and easily configure layers.

Changes made in the browser are reflected on the sgkey in real time. I wonder how it writes to the sgkey. Since it prompts you to select a device from the browser, I assume there’s some API that allows communication between the browser and the device.

This time, I set keys 1-5 on layer 1 and keys 6-0 on layer 2, with a toggle to switch between layers.

And just like that, I can input all 10 digits with only 6 keys.

It might be fun to display the current layer on the LCD as well.

By the way, the ProductID and VendorID in the sample vial.json are 0x000a and 0x2e8a, but for the xiao they are 0x802f and 0x2886. So I rewrote vial.json and ran go run cmd/gen-def/main.go to update def.go, but the behavior was the same whether I changed them or not. I’m not very familiar with this area, so I’m not sure why.

Closing Thoughts

TinyGo is amazing — you can write embedded programs with the same feel as regular Go. Since I’ve already bought all the electronics tools, I’d like to try a few more things4.

Thank you, sago35!


  1. I also gave a talk — please check out my slides here ↩︎

  2. https://sago35.hatenablog.com/entry/2023/12/05/095108 ↩︎

  3. mazrean, who also received an sgkey, assembled it at lightning speed ↩︎

  4. I’ve been eyeing the keyball61 for a while ↩︎