evan j brunner

Raspberry-pi and the Silicon Labs C2 Programming Interface

what? why would anyone do this?

cause I’m cheap and it seemed marginally possible

I recently started a project, and decided that it necessitated connecting a collection of C8051F30x devices to a raspberry-pi. I don’t own a device capable of programming the 8-bit micros. Ultimately what I (::cough::cough:: google) discovered was that the kernel has had support for the C2 interface since 2008 for various reasons.

Silicon labs has a wide array of micro controllers that support a programming interface simply refered to as C2:

..a two wire serial communication protocol designed to enable in-system programming and debugging on low pin-count [devices].1

The C8051F30 QFN has a 4×4mm footprint combined with a seemingly impossible number of peripherals. The combination of small size, low pin count, a fast multiplexed ADC, and at least 3 PWM outputs couldn’t be matched (as far as I found) from the likes of Microchip, Amtel, or Fairchild.

how I did it

summary

It took some further probing around to figure out that the c2port-core.ko (as it used to be called) needed an associated client. The included c2port-durmar2150.c is one such example, but is not useful for the Broadcom BCM2835 (raspberry pi).

Coincidentally I’d found a gpio-bit-banging implementation in a random openwrt github repo. I’m not really sure why it’s there (and it’s not very well documented) but I was able to splice all this into the official raspberry-pi linux repo – and create a functional set of modules.

I’ve setup a fork of the r-pi linux repo that contains my changes. This patch created from commit c588a3851 is the quickest way of adding the necessary changes to an arbitrary repo or branch of your own preference.

exercise

NOTE: if you’re serious about going down this road, do yourself a favor and proceed in a Linux environment (specifically I used Ubuntu 12.04.5). I’ve got a mac, and I’ve tried the do-everything-in-OSX (you can find help all over the web), but OSX is not Linux. Every step you take, OSX will remind you of that – and you’ll need help. Run a VM.

Start with a vanilla Raspbian (Debian Wheezy) image from raspberrypi.org.

Boot it up, setup SSH with some keys (or not).. etc.

Clone a linux repo (for the demo I’ll use the original the raspberrypi/linux repo):

user@host:~/prj$ git clone https://github.com/raspberrypi/linux.git

Apply the patch:

user@host:~/prj/linux$ git clone https://gist.github.com/f7c56965e6b21f7a9877.git
user@host:~/prj/linux$ git am --signoff < c2port-gpio.patch

Get a cross-compile toolchain2:

user@host:~/prj$ git clone https://github.com/raspberrypi/tools.git
user@host:~/prj$ export CCPREFIX=~/prj/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-
user@host:~/prj$ ${CCPREFIX}gcc --version
arm-linux-gnueabihf-gcc (crosstool-NG linaro-1.13.1-4.8-2014.01 - Linaro GCC 2013.11) 4.8.3 20140106 (prerelease)
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

build a configuration that inherits from the rpi:

user@host:~/prj/linux$ #fetch the config from the raspbian build
user@host:~/prj/linux$ scp pi@raspberrypi:/proc/config.gz .
user@host:~/prj/linux$ gunzip -c config.gz > .config
user@host:~/prj/linux$ #update it 
user@host:~/prj/linux$ ARCH=arm CROSS_COMPILE=${CCPREFIX} make oldconfig
scripts/kconfig/conf --oldconfig Kconfig
*
* Restart config...
*
*
* C2PORT
*
Silicon Labs C2 port support (C2PORT_CORE) [N/m/y/?] (NEW) m
C2 port support generic GPIO (C2PORT_GPIO) [N/m/y/?] (NEW) m
#
# configuration written to .config
#

Build the kernel

user@host:~/prj/linux$ #build the kernel with n threads where n=[number of cores]+1
user@host:~/prj/linux$ ARCH=arm CROSS_COMPILE=${CCPREFIX} make -jn

Mount the pi filesystem at root, with root permissions3

user@host:~/prj/linux$ sudo mkdir /mnt/pi
user@host:~/prj/linux$ sshfs root@raspberrypi:/ /mnt/pi
root@raspberrypi's password:

Build and install the new modules

user@host:~/prj/linux$ ARCH=arm CROSS_COMPILE=${CCPREFIX} \ 
> INSTALL_MOD_PATH=/mnt/pi DEPMOD=/bin/true make -jn modules_install

Slap the new kernel into place

user@host:~/prj/tools/mkimage$ #decompress the image
user@host:~/prj/tools/mkimage$ ./imagetool-uncompressed.py ../../linux/arch/arm/boot/zImage
user@host:~/prj/tools/mkimage$ #move it to the pi
user@host:~/prj/tools/mkimage$ mv kernel.img /mnt/pi/boot/

Restart the pi4

user@host:~/prj/$ ssh pi@raspberrypi
pi@raspberrypi:~/$ sudo reboot

Insert the new modules56

pi@raspberrypi:~/$ #This enables the c2port on brdcm GPIO ports 17 and 18
pi@raspberrypi:~/$ #which are rpi-GPIO ports 11 and 12 respectively.
pi@raspberrypi:~/$ sudo modprobe c2port-gpio c2d=17 c2ck=18 
pi@raspberrypi:~/$ #for a quick debug output, mount the debugfs
pi@raspberrypi:~/$ #enabled in the default .config: CONFIG_DEBUG_FS=y
pi@raspberrypi:~/$ sudo mount -t debugfs none /sys/kernel/debug 
pi@raspberrypi:~/$ sudo cat /sys/kernel/debug/gpio
GPIOs 0-53, bcm2708_gpio:
 gpio-16  (led0                ) out hi
 gpio-17  (c2port data         ) in  lo
 gpio-18  (c2port clock        ) in  lo 
pi@raspberrypi:~/$

Reach out and touch a microcontroller

pi@raspberrypi:~/$ su root
Password:
root@raspberrypi:/home/pi# echo 1 >/sys/class/c2port/c2port0/access
root@raspberrypi:/home/pi# cat /sys/class/c2port/c2port0/dev_id
10
root@raspberrypi:/home/pi# cat /sys/class/c2port/c2port0/rev_id
0

finishing touches

pi@raspberrypi:~/$ #insert udev rule to mod ownership of c2port dev
pi@raspberrypi:~/$ sudo echo "SUBSYSTEM=="c2port", ACTION=="add", PROGRAM="/bin/sh -c 'chown -R pi:pi /sys%p'"" > /etc/udev/rules.d/98-c2port.rules
pi@raspberrypi:~/$ #automatically load module on boot
pi@raspberrypi:~/$ sudo echo "c2port-gpio c2d=17 c2ck=18" >> /etc/modules

that-last-thing-that-should-probably-be-the-first-thing

specify device flash size

It’s important to note that the c2port-gpio has the flash block size, and number of blocks hard-coded into the driver. To make your specific device work correctly, you’ll have to get the flash size from the device specifications and edit the driver before you build. Specifically I did the following for the C8051F30:

--- a/drivers/misc/c2port/c2port-gpio.c
+++ b/drivers/misc/c2port/c2port-gpio.c
@@ -67,7 +67,7 @@ static void gpio_c2port_c2ck_set(struct c2port_device *dev, int status)
 
 static struct c2port_ops gpio_c2port_ops = {
 	block_size	:512,		/* bytes */
-	blocks_num	:30,		/* total flash size: 15360 bytes */
+	blocks_num	:15,		/* total flash size: 7680 bytes */
 	access		:gpio_c2port_access,
 	c2d_dir		:gpio_c2port_c2d_dir,
 	c2d_get		:gpio_c2port_c2d_get,

1 AN127 Flash Programming via the C2 Interface

2 The easiest way to get a toolchain is to clone it from the raspberrypi github account (as I did in the demo). There are more formal instructions on how to use the provided binary or build your own toolchain using crosstool-ng in the Embedded Linux Wiki. Also, there are instructions on how to enable kernel debug.

3 The pi doesn’t have a root password set by default. To create one:

pi@raspberrypi:~/$ sudo passwd root

4 If the pi refuses to boot, your kernel image is bad. Start over.

5 If depmod didn’t run on reboot, modprobe may claim the module was not found. To fix this quick run depmod --all.

6 Actual port mappings can be read from the schematic (found here), or from the world’s most insane table.