Table of Contents

Intro

The ClockworkPi GameShell comes with a GPIO expansion header. It provides access to 14 pins, that you can access with dupont cables.

Note: I wrote this post while I was figuring things out, so please be patient if it is not written linearly or not detailed enough.

Hopefully this provides you enough information to understand the GPIOs, and how to use them.

Getting the GPIOs to work

To get the GPIOs to work, we need to consider the avaiable information, i.e. find out which pin is which. This means we need to know how it is labeled on the outside of the GameShell, and to which pin this resolves on the CPU/SoC.

With the first information, we can check with a multimeter which pin is Pin 1, and verfiy the schematics, to get an orientation. Then, we can check if we can change the output state of the pin (using the info from the SoC’s Datasheet) and verify with a multimeter if our assumptions are correct.

Only then we can proceed to try the next steps, for example I2C. I like to aproach these things with the smallest possible steps to find mistakes (on my side) as soon as possible. If you start with an unverified assumption, it will be harder to find, for example if it is a wiring error.

Research

There is a discussion thread in the clockworkpi forum, which already provides a lot of information. Part of the inormation you find in this post will match this thread. My usual aproach is to follow this from the bottom up to make sure I full understand how things work, and avoid breaking things ;).

The mainboard schematics in their GitHub repository:

https://github.com/clockworkpi/GameShellDocs/blob/master/clockwork_Mainboard_Schematic.pdf

The Schematics show that we have 8 GPIOS and 6 pins for power.
We can find the pin numbers PH4-PH9 and PB0,PB1
We can see the chip with the label "R16-J" on the mainboard. This is a System-on-Chip (SoC), i.e. it is a tiny computer on its own.

The GPIO expansion cable is connected at the bottom of this module.

This SoC is an Allwinner Technology R16-J, with the following datasheet:

https://linux-sunxi.org/images/b/b3/R16Datasheet_V1.4(1).pdf

Expansion Pins

We can combine the information of the schematics and the datasheet to get to the following table (I also added information from the sections below):

Type Pin # (ext.) Pin # (Package) Function 1 Function 2 Pin # (sysfs) Color
3V0 1         blue
GPIO 2 PB0 UART0/2_TX PB-EINT0 32 green
GPIO 3 PB1 UART0/2_RX PB-EINT1 33 yellow
GND 4         white
GPIO 5 PH5 I2C1-SDA   229 red
GPIO 6 PH4 I2C1-SCL   228 brown
GND 7         black
GPIO 8 PH6 UART3-TX SPI0-CS 230 blue
GPIO 9 PH7 UART3-RX SPI0-CLK 231 green
GPIO 10 PH9 UART3-CTS SPI0-MISO 233 yellow
GPIO 11 PH8 UART3-RTS SPI0-MOSI 232 white
GND 12         red
5V0 13         brown
5V0 14         black

We see, we have Serial pins, I2C pins and SPI pins. According to the datasheet we can also use these ports as GPIOs.

Pin Order

With the multimeter you can verify the white (GND) and blue (3V0) cables on the right read 3.0V.
.. the same goes for red (GND) and black (5V0) reading 5.2V.

Important: The colors have nothing to do with +,-, or GND, and so on. Please make sure _NOT_ to make any assumptions by the colors. Always check your cables have the same color ordering.Then, refer to the table above for pin details.

Using GPIOS directly via CLI

First, become root:

sudo su

Next, I want to access the GPIO pins using the sysfs interface.

cd /sys/class/gpio
ls

Which returns

export	gpiochip0  gpiochip352	unexport

To access the pins as GPIO we can now map them into this interface. You can find more details on this on this page:

https://linux-sunxi.org/GPIO

From this page, you will find that the a package pin, for example PB0 or PB1 are assigned a sysfs number for this interface.

The rule to calculate this number is

(position of letter in alphabet - 1) * 32 + pin number

So for PB0 this results in (2 - 1) * 32 + 0 = 32 and for PB1 it’s (2 - 1) * 32 + 1 = 33.

I updated the table above acordingly.

Note: I am running Kernel 5.2.0-rc4-clockworkpi-cpi3 (compiled, as described below)

Then, create the pin’s interface:

echo 32 > /sys/class/gpio/export

which creates the interface’s pin directory:

cd /sys/class/gpio/gpio32/ # PB0, green cable

Which contains the following files

active_low  device  direction  edge  power  subsystem  uevent  value

To use this pin as an output pint you can configure it

echo out > direction

And enable it

echo 1 > value
... and the GPIO turns on ...

or disable it

echo 0 > value
... and the GPIO turns off ...

I will leave it to the reader to test this for the echo in > direction, echo value case ;).

Using I2C (/dev/i2c-0)

There is a command line tool i2cdetect that can scan for devices connecte to the I2C port.

Out of the box this complains

root@clockworkpi:/home/cpi# i2cdetect 1
Error: Could not open file `/dev/i2c-1' or `/dev/i2c/1': No such file or directory

because there is not a single I2C entry listed under /dev/i2c-X out of the box.

Enabling I2C via Device Tree

(See the section below how to get the Kernel Sources)

Go to linux-5.2-rc4/arch/arm/boot/dts.

Here, I added the following section to sun8i-r16-clockworkpi-cpi3.dts

&i2c1 {
    status = "okay";
}

and build with (like the kernel build section below, if you have previously built the kernel, this will be quick)

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-

Copy over the new file to your GameShell

scp arch/arm/boot/dts/sun8i-r16-clockworkpi-cpi3.dtb cpi@clockworkpi:/home/cpi/

Connect to your game shell and mount the boot partition:

ssh cpi@clockworkpi
sudo su
cd /mnt
mkdir boot
mount /dev/mmcblk0p1 /mnt/boot/

Make a backup to be safe(!):

cp /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb.bak

Install the new device tree file:

mv /home/cpi/sun8i-r16-clockworkpi-cpi3.dtb /mnt/boot/sun8i-r16-clockworkpi-cpi3.dtb

I2C Scan

You can scan the I2C bus with (as root):

root@clockworkpi:/home/cpi# i2cdetect 0

If you have nothing attached to the I2C Pins you will get:

WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0.
I will probe address range 0x03-0x77.
Continue? [Y/n] 
    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- 
This is my I2C setup, a sensor and an OLED display.

  • VIN -> blue (1)
  • GND -> white (4)
  • SDA -> red (5)
  • SCL -> brown (6)
Please always double check with the table above.

If you connect a Bosch BME280 sensor and a Oled 32x128 SSD1306 display you get:

WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0.
I will probe address range 0x03-0x77.
Continue? [Y/n] 
    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- 76 --    

\o/.

SPI

// TODO: sorry :)

Building a new Kernel

Sources

This repo provides what you need to build the kernel:

https://github.com/clockworkpi/Kernel

The following assumes you are building for

Prepare the sources (we are going to work in a directory called cpi-0.4-kernel-5.2)

mkdir cpi-0.4-kernel-5.2
cd cpi-0.4-kernel-5.2/
wget https://git.kernel.org/torvalds/t/linux-5.2-rc4.tar.gz
tar xf linux-5.2-rc4.tar.gz
cd linux-5.2-rc4
wget https://raw.githubusercontent.com/clockworkpi/Kernel/master/v0.4/52rc4.patch
git apply 52rc4.patch

Toolchain

Prepare your tool chain (back in cpi-0.4-kernel-5.2)

cd cpi-0.4-kernel-5.2/
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 

I had to install some missing packages (on Debian 10.2):

apt-get install flex bison libssl-dev u-boot-tools

This might be an incomplete list of missing packages, and if you have a different setup, it will likely fail in the make step below. In this case you have to google your error message and check what package is missing on your system.

add the compiler to the path:

cd gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabihf/bin/
export PATH=$PATH:$(pwd)

Compiling

Go to the source (using the session with the updated $PATH variable above)

cd ../../linux-5.2-rc4
cp ./arch/arm/configs/clockworkpi_cpi3_defconfig .config
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

Now, you should have the file uImage, your freshly built kernel.

Installing a new Kernel

First we copy over the uImage from our build machine: scp uImage cpi@clockworkpi:/home/cpi/

On the GameShell, you need to mount the /boot partition:

ssh cpi@clockworkpi
sudo su
cd /mnt
mkdir boot
mount /dev/mmcblk0p1 /mnt/boot/

It makes sense to create a backup first.

cd /mnt/boot/
cp uImage uImage.bak

..and replace the uImage file.

cp /home/cpi/uImage ./uImage
reboot