clockworkpi

Using CardKB from M5Stack without reprogramming it!

What is the CardKB ?


The CardKB is a simple and cute keyboard made by M5Stack, owner of modular stackable product development toolkits based on ESP32.
It uses I²C to communicate, wich means it has a clock line and a data line (you can check documentation here). It nearly exactly fits the size of our GameShell, and costs nearly nothing, wich makes it a great choice.

Enabling I²C on the GameShell :

I took many informations to make I²C enabled here. If not precised, execute tasks on any computer. I assume you’re using a Linux distribution (I use Pop!_OS but it should work on any distros, you’ll just need to adapt it to yours ! If you don’t have one installed, consider using WSL).
First of all :

  • Download and extract the toolchain which we will use to compile and build our Kernel:
wget https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/arm-linux-gnueabihf/gcc-linaro- 
7.2.1-2017.11-x86_64_arm-linux-gnueabihf.tar.xz
tar xf gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf.tar.xz
  • Add it to the PATH :
cd gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/
export PATH=$PATH:$(pwd)
  • Download dependencies if required :
apt-get install flex bison libssl-dev u-boot-tools
  • Download Kernel sources (choose depending on your environment). I’ll choose the 5.3.6 as it’s the one I use on my GS.

  • From sources’ root, go to ./arch/arm/boot/dts and add the following to the end of sun8i-r16-clockworkpi-cpi3.dts :

&i2c1 {
    status = "okay";
};
  • Build the Kernel using this command :
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
  • Copy the newly generated .dtb file to your GS :
scp arch/arm/boot/dts/sun8i-r16-clockworkpi-cpi3.dtb cpi@clockworkpi:/home/cpi/
  • As a super-user, mount your boot partition on the GS (you can use ssh cpi@clockworkpi to access a CLI) :
sudo su
cd /mnt
mkdir boot
mount /dev/mmcblk0p1 /mnt/boot/
  • Make a backup as it may break your OS if something goes wrong on the GS :
cp /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb.bak
  • Install the new .dtb file by copying it into the boot partition on the GS :
cp /home/cpi/sun8i-r16-clockworkpi-cpi3.dtb /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb
  • Reboot and test your installation simply using on the GS :
i2cdetect -y 0

If everything worked as intended it should probe every I²C adresses, showing an array like this :

    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- 

Enabling uinput Kernel module :

The keyboard library, wich is the library we will be using in our script , uses uinput to emulate a keyboard. It has not been included in the GS Kernel modules, we will then need to build our own modified Kernel and add it to the GS.

  • Fist of all we will need to fix something. In the file ./scripts/dtc/dtc-lexer.l find :
YYLTYPE yylloc;
  • And add extern keyword before it :
extern YYLTYPE yylloc;
  • Using previously downloaded Kernel sources include User level driver support using menuconfig :
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
  • You can find it under :
Device Drivers --->
    Input Device Support --->
        Miscellaneous devices --->

To include it you’ll need to press Y (a * will appear).
Press exit or Escape until you’re prompted to save. Save.

  • Build the Kernel image :
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
mkimage -A arm -O linux -T kernel -C none -a 0x40008000 -e 0x40008000 -n "Linux Kernel" -d arch/arm/boot/zImage uImage
  • On your GS, make a backup file of your uImage (as root):
cd /mnt/boot/
cp uImage uImage.bak
  • Replace the uImage file and reboot:
cp /home/cpi/uImage ./uImage
reboot

You’re nearly done !

Python script :

To ensure the script will work, you’ll need to download smbus and keyboard Python libraries :



We will use the keyboard library to simulate a keyboard via Python as mentionned earlier. The smbus one will be used to interact with the I²C interface.
  • To install those, simply type on the GS :
pip install smbus
pip install keyboard
  • Make a file named <filename>.py and paste the following code in it :
#importing smbus for i2c, and keyboard for injecting keystrokes.
import smbus,keyboard

#Selecting i2c channel (0 by default for GameShell, may be different for RPi
channel = 0

#CardKB i2c adress to listen on 
address = 0x5f

bus = smbus.SMBus(channel)


while True:
#    test = ""
#    try :
#        test = bus.read_byte_data(address, 0)
#    except:
#        pass
#    if test != "":
#        print(test)
    try :
        #reads value passed by the keyboard
        msg = bus.read_byte(address)
        #ensures no empty messages are passed
        if msg != 0 :
            #180,181,182,183 prints weird chars instead of  what they're meant to : key_up/down/left/right
            if msg == 180 :
                keyboard.press_and_release("left")
                #print(msg)
            elif msg == 181:
                keyboard.press_and_release("up")
                #print(msg)
            elif msg == 182:
                keyboard.press_and_release("down")
                #print(msg)
            elif msg == 183:
                keyboard.press_and_release("right")
                #print(msg)
            else:
                #print(chr(msg))
                #print(msg)
                keyboard.press_and_release(chr(msg))
    except :
        pass

Here’s what it looks like :

As you can see it’s absolutely not practical, it still needs a case, and I use some illegal lego techniques. I should also shorten the cables. Feel free to ask questions, share what you did etc… See ya ! :smiley:

7 Likes

Solid tutorial! Thanks for sharing!

3 Likes

Thanks ! I’m planning to buy a 3D printer to make it more practical. :stuck_out_tongue:

3 Likes