CI20 GPIO LED Blink Tutorial

Blinking an LED using a GPIO pin is the "Hello World" of embedded systems, let's do it on a CI20 Creator board!

Small disclaimer: I ran this sequence of commands on my CI20 with no problems or damage, but always be careful of possible short circuits and similar electrical issues. If you manage to damage your board, you're on your own...

Blink a LED on a GPIO pin from CI20's command shell
Goals of this tutorial are:
 * explain the basics of GPIO control in Linux
 * blink a LED connected to a GPIO pin on the expansion header

All of this can be done using the sysfs interface from the command line, no programming is involved.

You will need a CI20 board, a working LED and a current limiting resistor for it.

If you just want to try it without explanation, see the section below

What is a General-Purpose Input/Output (GPIO) pin?
A GPIO is a software controlled digital signal, a GPIO pin is a pin on an integrated circuit whose function and behaviour can be controlled by the user (see the other wiki here).

The two main operation mode of a GPIO are input and output:
 * in "input" mode, you can read "low" and "high" values
 * in "output" mode, you can write "low" and "high" values

You can think of it as a binary sensor (input) or controlled switch (output). Other uses (e.g. as IRQ lines) are outside the scope of this tutorial.

Controlling GPIOs from the shell (Linux' sysfs interface for GPIOs)
The GPIOs on the CI20 board can be accessed using the special sysfs filesystem at the "/sysfs/" mount point, specifically in the "/sys/class/gpio/" directory. The main concept is that reading from and writing to special files in this directory will enable you to control the CI20's GPIOs operation mode. A full documentation on GPIO control implementation in the Linux kernel can be found in the Linux kernel source documentation, specifically in "Documentation/gpio/".

Some links to the online git repository at kernel.org:

GPIOs sysfs support

general GPIO description

What's in "/sys/class/gpio/"
There are three kinds of things in "/sys/class/gpio/":
 * 1) control interface "export" and "unexport"
 * 2) exported GPIOs directories (nodes)
 * 3) GPIO controllers (gpiochip*) directories

Writing a GPIO number to the "export" file will enable access to the GPIO and create the corresponding directory. You can do it simply using the "echo" shell command, so the following command: echo 123 > export will result in a "/sys/class/gpio/gpio123" directory.

Writing a GPIO number to the "unexport" file will disable access to the GPIO and remove the corresponding directory. The following command: echo 123 > unexport will remove "/sys/class/gpio/gpio123".

Usually a large number of GPIOs is available in embedded platforms, the control of these is split between multiple GPIO controllers. Each controller presents a separate directory in "/sys/class/gpio", with the form "/sys/class/gpio/gpiochip*", e.g. "/sys/class/gpio/gpiochip0". Among the content of gpiochip* directories, we are interested in three files:
 * base: the first GPIO number managed by this particual GPIO controller
 * label: controller label
 * ngpio: how many GPIOs are managed by this controller

You can check these stats for every GPIO controller on the CI20 with the following shell command: for f in `ls -d /sys/class/gpio/gpiochip*`; do echo $f `cat $f/label $f/base $f/ngpio` ; done It shows the list of controllers and for each controller its label, base and ngpio.

How to know what GPIO number to use
In the CI20_Hardware page there is a description of the expansion headers that shows both "schematic" names and "sysfs" numbers for GPIOs, just hover the mouse on the desired pin to see what is the associated GPIO's number in sysfs.

See for example the schematics of the Primary expansion header

The following is an explanation of how the mechanism works for who is interested.

The GPIO names on the CI20's schematics (e.g. PD26, PE14, ...) are not the same as shown in the sysfs interface: how can we work out what GPIO number to use? Let's have a look at the gpiochip* stats, running again the command: root@ci20:/home/ci20/src# for f in `ls -d /sys/class/gpio/gpiochip*`; do echo $f `cat $f/label $f/base $f/ngpio` ; done /sys/class/gpio/gpiochip0 GPIO A 0 32 /sys/class/gpio/gpiochip128 GPIO E 128 32 /sys/class/gpio/gpiochip160 GPIO F 160 32 /sys/class/gpio/gpiochip32 GPIO B 32 32 /sys/class/gpio/gpiochip64 GPIO C 64 32 /sys/class/gpio/gpiochip96 GPIO D 96 32

As you can see, there are 6 controllers, labeled from "GPIO A" to "GPIO F", each controlling 32 GPIOs (ngpio == 32). Assuming we want to control GPIO PD28, what GPIO number do I need to use? PD28 means 28th GPIO of block "D", controller "/sys/class/gpio/gpiochip96" is labeled as "GPIO D", its base is 96, thus: 96 (first GPIO in block D) + 28 (our GPIO of interest in block D) = 124 (GPIO number to be used in sysfs)

Hardware setup
Connect LED's cathode to a ground pin on CI20's primary expansion header (e.g. pin 25) Connect LED's anode to a resistor (used to limit current thus preventing LED to burn up, for a quick test everything from 100 Ohm to 1k Ohm should work) Connect resistor's other end to chosen GPIO pin, in this case GPIO PD28 means pin 7 on primary expansion header

Software setup
Open a shell / command prompt on the board Acquire admin privileges running "su" and inserting root password (default is "ci20")

The blinking
Just run the following commands (text after "#" are comments and can be omitted):

cd /sys/class/gpio/ echo 124 > export #enable access to the GPIO cd gpio124/ #enter new directory cat direction #check urrent direction echo out > direction #Set GPIO as output cat direction #Check new GPIO direction cat value #Check current value echo 1 > value #Set value as high as a test, LED should lit-up cat value #Check that value changed while ( true ); do echo 1 > value; cat value; sleep 1; echo 0 > value; cat value; sleep 1; done;
 * 1) Endless loop, 1 sec on plus 1 sec off, press CTRL+C to end

At this point, the LED should blink on/off with a period of 2 seconds. Congratulation, you completed the first tutorial on GPIO control on the CI20 :-)

After you finish experimenting, you can press "Ctrl+C" to stop the blinking, write "0" to disable the output and "unexport" the GPIO (or simply power down the board).

A simple script
This is a simple script you can use to do the same things, with the addition that you can change the value of the "GPIO" variable to change the affected GPIO:
 * 1) !/bin/bash

GPIO=124 GPIODIR=/sys/class/gpio/gpio$GPIO

echo "Configuring GPIO $GPIO"

if [ ! -e "$GPIODIR" ] then echo "Exporting GPIO" echo $GPIO > /sys/class/gpio/export else echo "GPIO already exported" fi
 * 1) check if the gpio is already exported

echo "Current direction: `cat $GPIODIR/direction`" echo "Set GPIO as output" echo out > $GPIODIR/direction echo "New GPIO direction: `cat $GPIODIR/direction`" echo "Current value: `cat $GPIODIR/value`" echo "Set value as high" echo 1 > $GPIODIR/value echo "New value: `cat $GPIODIR/value`"

echo "Start blinking, 1 sec on plus 1 sec off, press CTRL+C to end" while ( true ); do echo 1 > $GPIODIR/value; cat $GPIODIR/value; sleep 1; echo 0 > $GPIODIR/value; cat $GPIODIR/value; sleep 1; done;
 * 1) Endless loop

Example: Using the onboard LED and button
On revision B boards, the onboard LED (PF15) is GPIO 175 and the onboard button (PD17) is GPIO 113. The following script will use the button's value to update the the LED's value.

Once the script is running, the onboard LED should turn blue when the button is not pressed and red when the button is pressed.


 * 1) !/bin/sh

LED=175 BTN=113 GPIODIR=/sys/class/gpio

if [ ! -e $GPIODIR/gpio$LED ] then echo $LED > $GPIODIR/export fi

if [ ! -e $GPIODIR/gpio$BTN ] then echo $BTN > $GPIODIR/export fi

echo in > $GPIODIR/gpio$BTN/direction echo out > $GPIODIR/gpio$LED/direction

while ( true ); do cat $GPIODIR/gpio$BTN/value > $GPIODIR/gpio$LED/value; done;

Example 2: Using the onboard LEDs of Ci20 V2 boards
Revision v2 of the Ci20 adds 4 general purpose LEDs to the design. These are made available via the LED class driver, with default triggers as follows To control these LEDs yourself, you must first replace the default trigger with "None" to disconnect the LED from the kernels activity: echo none > /sys/class/leds/ledX/trigger Then the LED may be turned on by writing a non-zero value into the brightness file: echo 1 > /sys/class/leds/ledX/brightness And to turn it off again: echo 0 > /sys/class/leds/ledX/brightness
 * LED0 - None
 * LED1 - NAND Flash access
 * LED2 - CPU1 activity
 * LED3 - CPU0 activity