CardKB mini keyboard with MicroPython

small computer screen with text
*** APPALLING TYPEWRITER ***
** Type stuff, Esc to end **

then further down: "hello I am smol keeb"
it really is the size of a credit card
(running with a SeeedStudio Wio Terminal)

I got one of these CardKB Mini Keyboards to see if I could use it for small interactives with MicroPython devices. It’s very small, and objectively not great as a mass data entry tool. “Better than a Pocket C.H.I.P. keyboard” is how I’d describe the feel. It’s also pretty reliable.

It’s got an I²C Grove connector, and its brains are an ATMega chip just like an Arduino. It’s strictly an ASCII keyboard: that is, it sends the 8-bit ASCII code of the key combination you pressed. It doesn’t send scan codes like a PC keyboard. The driver source is in the CardKB m5-docs, so if you really felt ambitious you could write a scan code-like firmware for yourself.

The device appears at I²C peripheral address 95, and returns a single byte when polled. That byte’s either 0 if no key was pressed, or the character code of what was pressed. The Esc key returns chr(27), and Enter returns CR. If you poll the keyboard too fast it seems to lose the plot a little, so a tiny delay seems to help

Here’s a small demo for MicroPython that acts as the world’s worst typewriter:

# M5Stack CardKB tiny keyboard - scruss, 2021-06
# MicroPython - Raspberry Pi Pico

from machine import Pin, I2C
from time import sleep_ms

i2c = I2C(1, scl=Pin(7), sda=Pin(6))
cardkb = i2c.scan()[0]  # should return 95
if cardkb != 95:
    print("!!! Check I2C config: " + str(i2c))
    print("!!! CardKB not found. I2C device", cardkb,
          "found instead.")
    exit(1)

ESC = chr(27)
NUL = '\x00'
CR = "\r"
LF = "\n"
c = ''

print("*** APPALLING TYPEWRITER ***")
print("** Type stuff, Esc to end **")

while (c != ESC):
    # returns NUL char if no character read
    c = i2c.readfrom(cardkb, 1).decode()
    if c == CR:
        # convert CR return key to LF
        c = LF
    if c != NUL or c != ESC:
        print(c, end='')
    sleep_ms(5)

And here’s the CircuitPython version. It has annoying tiny differences. It won’t let me use the I²C Grove connector on the Wio Terminal for some reason, but it does work much the same:

# M5Stack CardKB tiny keyboard - scruss, 2021-06
# CircuitPython - SeeedStudio Wio Terminal
# NB: can't use Grove connector under CPY because CPY

import time
import board
import busio

i2c = busio.I2C(board.SCL, board.SDA)

while not i2c.try_lock():
    pass

cardkb = i2c.scan()[0]  # should return 95
if cardkb != 95:
    print("!!! Check I2C config: " + str(i2c))
    print("!!! CardKB not found. I2C device", cardkb,
          "found instead.")
    exit(1)

ESC = chr(27)
NUL = '\x00'
CR = "\r"
LF = "\n"
c = ''
b = bytearray(1)

# can't really clear screen, so this will do
for i in range(12):
    print()
print("*** APPALLING TYPEWRITER ***")
print("** Type stuff, Esc to end **")
for i in range(8):
    print()

while (c != ESC):
    # returns NUL char if no character read
    i2c.readfrom_into(cardkb, b)
    c = b.decode()
    if c == CR:
        # convert CR return key to LF
        c = LF
    if c != NUL or c != ESC:
        print(c, end='')
    time.sleep(0.005)

# be nice, clean up
i2c.unlock()

Leave a comment

Your email address will not be published. Required fields are marked *