-
Dynamic USB Descriptors
05/15/2021 at 13:04 • 2 commentsA new feature landed in CircuitPython recently, that allows us to do a neat little trick: we can show the CIRCUITPY disk and Python REPL console, or not, depending on whether a certain key is pressed when the keyboard is powered up or reset.
Why is this important?
I find it rather distracting when my keyboard shows up as a disk and serial device, especially when I'm working with other CircuitPython devices — it's sometimes hard to tell which is which. On the other hand, the way you could disable the disk and console previously involved compiling and flashing a special CircuitPython image, as this was a compile-time option. Having to re-flash your firmware to see the disk again every time you want to make some small change or tweak is not very convenient.
So now we can make it so that it's just a keypress away.
All I needed to do is to create the following boot.py file:
import board import digitalio import storage import usb_cdc import usb_hid row = digitalio.DigitalInOut(board.D4) col = digitalio.DigitalInOut(board.A2) col.switch_to_output(value=0) row.switch_to_input(pull=digitalio.Pull.UP) if row.value: storage.disable_usb_drive() usb_cdc.disable() usb_hid.enable(devices=(usb_hid.KEYBOARD,)) row.deinit() col.deinit()
The board.D4 and board.A2 are the row and column of the key that I want to use for the check. The rest is pretty self-explanatory.
-
The Code
05/02/2021 at 10:31 • 0 commentsI'm using my uKeeb library as usual, but some small modifications were needed to make the split keyboard work. On the left hand side I removed all the key handling logic, leaving just the matrix scanning and debouncing, and two methods:
def press(self, x, y): self.buf[0] = x | (y << 4) | 128 self.uart.write(self.buf) def release(self, x, y): self.buf[0] = x | (y << 4) self.uart.write(self.buf)
(Of course I also create the UART object earlier.)
Then on the left hand side I added a method to be always called right after scanning:
def read_uart(self): while self.uart.in_waiting: self.uart.readinto(self.buf) x = self.buf[0] & 0x0f y = (self.buf[0] & 0x70) >> 4 if self.buf[0] & 0x80: self.press(9 - x, y) else: self.release(9 - x, y)
And that's it.
-
The TRRS Cable
05/01/2021 at 22:19 • 0 commentsI already had my code for the keyboard, but I had to modify it slightly, so that it would communicate over the TRRS cable with the other half, to receive the keypresses from it. Initially I assumed that the TRRS cable just connects the TX and RX pins, crossed — since there are 4 wires, two used for power. Only after some head scratching and probing the connections I noticed that something is wrong. I asked the author for a schematic, and turns out that only the RX pins are connected, and one wire is just left unused.
This turned out to be a bit of a problem, because the SAMD21 can't use the RX pin for sending data using the hardware UART, and CircuitPython doesn't have a software UART in the bitbangio module. Eventually I just ended up cutting the trace on the right hand side of the keyboard, and bodging it to TX.
-
The Keyboard
05/01/2021 at 22:13 • 0 commentsOnce the switches arrived, I was ready to assemble the keyboard. It took a little bit of detective work to figure out which way to solder the diodes (I soldered them the wrong way, but fixed it in software, thankfully SAMD21 supports both pull-ups and pull-downs on its pins), and which set of holes to use on the left and right side for the microcontroller board.
-
Fluff M0 Micro
05/01/2021 at 22:10 • 0 commentsSince I wanted to program this keyboard in CircuitPython, I needed a development board that would be compatible pin-wise with the Pro Micro, but use a bit more powerful microcontroller. So I designed this version of #Fluff M0: