CI20 GPIO LED Blink Tutorial

From eLinux.org
Revision as of 03:38, 10 December 2015 by Harveyhunt (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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 an 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)

Using WiringX

The GPIO library wiringX has been ported to the Ci20 and provides a simple C interface to the Ci20's GPIOs.

Multiple C examples can be found here.

WiringX also provides a Python interface, which can be found here.

Python implementations of the C examples can also be found here.

Example: blinking LED

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
#Endless loop, 1 sec on plus 1 sec off, press CTRL+C to end
while ( true ); do echo 1 > value; cat value; sleep 1; echo 0 > value; cat value; sleep 1; done;

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:

#!/bin/bash

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

echo "Configuring GPIO $GPIO"

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

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`"

#Endless loop
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;

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.

#!/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

  • LED0 - None
  • LED1 - NAND Flash access
  • LED2 - CPU1 activity
  • LED3 - CPU0 activity

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