GPIO lines

This document explains how to manage the GPIO lines on the FOX Board G20 using the Sysfs interface

Written by Sergio Tanzilli

How to make a blinking led

First of all let's try to blink a led using a GPIO line. We need a led and a 1K resistor wired on pin J7.3 as shown below. Please note that the led has a polarity so you have to wire it properly.

Blinking led in Python

If Python is not installed in your FOX read this tutorial.

This a basic example on how to blink an external led wired on J7 connector in Python:

File: http://acme-dev.svn.sourceforge.net/viewvc/acme-dev/python/led.py -

#!/usr/bin/python
#
# $Id$
 
import time
import fox
 
print "Blinking led"
print "Type ctrl-C to exit"
 
led = fox.pin('J7.3','low')
 
while True:
	time.sleep(1)
	led.on()
	time.sleep(1)
	led.off()

This example use the standard module time installed by default with Python and the module fox wrote by me to simplify the access to the FOX Board G20 lines.

To install this example and the last version of fox.py module type:

debarm:/# wget http://acme-dev.svn.sourceforge.net/viewvc/acme-dev/python/fox.py
debarm:/# wget http://acme-dev.svn.sourceforge.net/viewvc/acme-dev/python/led.py

The run the example typing:

debarm:/# python led.py

or run directly the code typing:

debarm:/# chmod +x led.py
debarm:/# ./led.py

Read a button

This a basic example on how read an external button J7.5 pin in Python:

File: http://acme-dev.svn.sourceforge.net/viewvc/acme-dev/python/button.py -

#!/usr/bin/python
#
# $Id$
 
import time
import fox
 
print "Pressing button"
print "Type ctrl-C to exit"
 
led = fox.pin('J7.3','low')
button = fox.pin('J7.5','in')
 
while True:
	if button.get()==0:
		led.on()
	else:
		led.off()
 

How to wire a buzzer ?

You will find below a design to simply add a buzzer and pilot it from the netus. This will normally work with 3.3 or 1.8 V output. An optional 1K resistor could be add between the G20 output and the BC 547 base.

In this example the design allow to drive a buzzer with a 35 mA under 5 V.

In construction… The author is not responsible in case of electrical destruction while trying thi design :-)

A resistor between transistor base and foxg20 should be added IMHO. — Claudio 2010/02/11 12:41
You're right claudio i will modify the design
erlo on IRC channel suggest that you cannot have 35mA with 1.5K resistor under 5V; he suggest to don't use the 1.5KΩ

How Linux manages the GPIO lines (sysfs method)

The J7.3 pin is identified by the Kernel id 82. Before use any GPIO line needs to be exported writing the id in the /sys/class/gpio/export file. To do that manually type:

debarm:/# echo 82 > /sys/class/gpio/export

A new directory called /sys/class/gpio/gpio82 will be created with some files inside:

debarm:/# ls /sys/class/gpio/gpio82
direction  edge  power  subsystem  uevent  value

To set the line as output type “out” in the file direction:

debarm:/# echo out > /sys/class/gpio/gpio82/direction

Now to turn on and off the led type:

debarm:/# echo 1 > /sys/class/gpio/gpio82/value
debarm:/# echo 0 > /sys/class/gpio/gpio82/value

This methos is not so fast but is compatible with any programming languages.

GPIO lines (device base method)

Written by Claudio Mignanti
On some distribution (OpenWrt and debian (Debian appear to lack in this feature atm)) there is another way to access GPIO driver, according to Douglas Gilbert test the ioctl access runs at just over 300 kHz1) while the sysfs version runs at around 130 kHz2).

Here a little example on how to use it3):

int main(){ int fd;
    //open the device file
    fd = open("/dev/gpio", O_RDWR);
    
    //request gpio pin
    res = ioctl(fd, GPIO_REQUEST, 82);

    //set gpio as output
    ioctl(fd, GPIO_DIR_OUT, 82);

    for (k = 0; k < 10000000; ++k) {
        ioctl(fd, GPIO_SET, 82);    //cycle on/off
        ioctl(fd, GPIO_CLEAR, 82);
    } 
    //remeber to release gpio!
    res = ioctl(fd, GPIO_FREE, 82);
    close(fd);
}

Here part of gpio_dev.h:

/********************************************************************* 
 * 
 * This Linux kernel header is expanded from the original driver 
 * (gpio_dev) by John Crispin. It provides an ioctl based interface to 
 * GPIO pins via the /dev/gpio char device and gpiolib within the kernel. 
 * The third argument to each ioctl is the GPIO pin number. 
 * 
 * This driver has been tested with lk 2.6.31 and works. The original 
 * driver fails quietly with this version. The protocol is now a bit 
 * different: the ioctl(fd, GPIO_REQUEST, <pin>) should be called 
 * after the open("/dev/gpio", O_RDWR) to determine if the <pin> is 
 * already in use. If the ioctl is successful (i.e. returns 0 for not 
 * in use) then the <pin> is claimed by this driver and 
 * ioctl(fd, GPIO_FREE, <pin>) should be called prior to close(fd) . 
 *  
 * See <kernel_source>/Documentation/gpio.txt 
 * Note that kernel designers prefer the use of the sysfs gpio interface. 
 * This char driver is easier to use from code and faster. 
 ********************************************************************/ 

#define GPIO_GET        _IO(IOC_GPIODEV_MAGIC, 10) 
#define GPIO_SET        _IO(IOC_GPIODEV_MAGIC, 11) 
#define GPIO_CLEAR      _IO(IOC_GPIODEV_MAGIC, 12) 
#define GPIO_DIR_IN     _IO(IOC_GPIODEV_MAGIC, 13) 
#define GPIO_DIR_OUT    _IO(IOC_GPIODEV_MAGIC, 14) 
        /* Sets the direction out and clears the <pin> (low) */ 

#define GPIO_DIR_HIGH   _IO(IOC_GPIODEV_MAGIC, 15) 
        /* Sets the direction out and sets the <pin> (high) */ 
#define GPIO_REQUEST    _IO(IOC_GPIODEV_MAGIC, 16) 
#define GPIO_FREE       _IO(IOC_GPIODEV_MAGIC, 17) 
#define GPIO_CAN_SLEEP  _IO(IOC_GPIODEV_MAGIC, 18) 

GPIO lines available

The AT91SM9G20 CPU used on the FOX Board G20 has 3 ports called A,B and C with 32 bit each. Any bit is wired out to the CPU pins as I/O line. Unfortunately not all the I/O lines are wired out to the FOX Board connector and not all the I/O line available on the FOX Board G20 connector are available also to the user as general purpose I/O (GPIO). That's way I/O lines are multiplexed with other peripherals like serial ports, SPI, I2C, A/D converter etc, microSD, data flash, USB etc. On the factory default configuration FOX Board G20 has 28 I/O lines available for general purpose.

On the software side Linux provides a standard way to manage the GPIO lines base on Sysfs. This is a virtual file system that exports information about devices and drivers from the kernel device model to the userspace. The Sysfs related to the GPIO is available starting from this path /sys/class/gpio/.

Each I/O lines is identified by a kernel ID. The table below shows the Kernel ID of each GPIO line available on the J6 and J7 connectors (see the complete pin-out):

Pin number Kernel ID Note
J7.3 82
J7.4 83
J7.5 80
J7.6 81
J7.7 66
J7.8 67
J7.9 64
J7.10 65
J7.11 110 1.8V
J7.12 111 1.8V
J7.13 108 1.8V
J7.14 109 1.8V
J7.15 105 1.8V
J7.19 101 1.8V
J7.35 60
J7.36 59
J7.37 58
J7.38 57
Pin number Kernel ID Note
J6.17 85
J6.18 84
J6.19 95
J6.20 94
J6.24 38
J6.25 39
J6.26 41
J6.36 42
J6.37 54
J6.38 43

fox.py

On acme-dev project is available a python library that can be used also to control gpio pin.
See the class pin definition.

Don't rely on this api atm this is instable!

File: http://acme-dev.svn.sourceforge.net/viewvc/acme-dev/python/fox.py -

# This file is released under public domain.
#
# 2010 - Claudio Mignanti, Sergio Tanzilli
#
# $Id$
 
import os.path
import serial
import fcntl, struct, termios, os
import time
 
GPIO_GET      = 16906
GPIO_SET      = 16907
GPIO_CLEAR    = 16908
GPIO_DIR_IN   = 16909
GPIO_DIR_OUT  = 16910
GPIO_DIR_HIGH = 16911
GPIO_REQUEST  = 16912
GPIO_FREE     = 16913
GPIO_CAN_SLEEP= 16914
 
 
class pin:
	"""This call can be used to access GPIO pins using device base method\n 
	It implements: pin(fox_pin_name, direction), .get(), .set(1|0)"""
	kernelid_table = {
		'J7.3'  :  82,
		'J7.4'  :  83,
		'J7.5'  :  80,
		'J7.6'  :  81,
		'J7.7'  :  66,
		'J7.8'  :  67,
		'J7.9'  :  64,
		'J7.10' :  65,
		'J7.11' : 110,
		'J7.12' : 111,
		'J7.13' : 108,
		'J7.14' : 109,
		'J7.15' : 105,
		'J7.16' : 106,
		'J7.17' : 103,
		'J7.18' : 104,
		'J7.19' : 101,
		'J7.20' : 102,
		'J7.21' :  73,
		'J7.22' :  72,
		'J7.31' :  87,
		'J7.32' :  86,
		'J7.33' :  89,
		'J7.34' :  88,
		'J7.35' :  60,
		'J7.36' :  59,
		'J7.37' :  58,
		'J7.38' :  57,
		'J6.3'  :  92,
		'J6.4'  :  71,
		'J6.5'  :  70,
		'J6.6'  :  93,
		'J6.7'  :  90,
		'J6.8'  :  69,
		'J6.9'  :  68,
		'J6.10' :  91,
		'J6.13' :  75,
		'J6.14' :  74,
		'J6.15' :  77,
		'J6.16' :  76,
		'J6.17' :  85,
		'J6.18' :  84,
		'J6.19' :  95,
		'J6.20' :  94,
		'J6.21' :  63,
		'J6.22' :  62,
		'J6.24' :  38,
		'J6.25' :  39,
		'J6.26' :  41,
		'J6.27' :  99,
		'J6.28' :  98,
		'J6.29' :  97,
		'J6.30' :  96,
		'J6.31' :  56,
		'J6.32' :  55,
		'J6.36' :  42,
		'J6.37' :  54,
		'J6.38' :  43,
	}
 
	fd_pin = -1
 
	def is_low(self, string):
		if (string == "out" or string == "low" or string == "0"):
			return True
		if (string == "in" or string == "high" or string == "1"):
			return False
		return int(string)
 
	def getid(self,pin_name):
		if (pin_name.isdigit() == False ):
			return self.kernelid_table[pin_name]
		else:
			return int(pin_name)
 
	def __init__(self,pin_name,direction):
		self.kernelid=self.getid(pin_name)
 
		self.fd_pin = open ("/dev/gpio")
		fcntl.ioctl(self.fd_pin, GPIO_REQUEST, self.kernelid)
 
		if self.is_low(direction):
			fcntl.ioctl(self.fd_pin, GPIO_DIR_OUT, self.kernelid)
		else:
			fcntl.ioctl(self.fd_pin, GPIO_DIR_IN, self.kernelid)
 
	def set(self,value):
		if self.is_low(value):
			return fcntl.ioctl(self.fd_pin, GPIO_CLEAR, self.kernelid)
		else:
			return fcntl.ioctl(self.fd_pin, GPIO_SET, self.kernelid)
 
	def get(self):
		return fcntl.ioctl(self.fd_pin, GPIO_GET, self.kernelid)
 
	def on(self):
		return self.set(1)
 
	def off(self):
		return self.set(0)
 
	def free(self):
		fcntl.ioctl(self.fd_pin, GPIO_FREE, self.kernelid)
 
class display:
	""" This class can be used to controll 4D System oled display
attacched to serial port. If no arg is supply if will use ttyS3 as default.
	"""
	def __init__(self, port="/dev/ttyS3"):
		ser = serial.Serial(port, 115200, 1,
			serial.PARITY_NONE,
			serial.STOPBITS_ONE,
			serial.EIGHTBITS
		)
		ser.write("U")	# Autobaud char
		ser.read(1)
 
	def clear(self):
		"""Clear screen"""
		ser.write("E")
		ser.read(1)
 
	def write(self, string, x=0, y=0):
		"""Write string to x,y position"""
		ser.write("s%c%c%c%c%c%s%c" % (int(x),int(y),1,0xFF,0xFF,string,0x00))		
		ser.read(1)
 
class adc:
	"""This class allow you to access the four ADC channel using the appropriate device file"""
	def __init__ (self, chan):
		if chan < 0 or chan > 3:
			return -2
		self.chan = chan
		self.fd = open ('/dev/at91-adc')
		if fd == -1:
			return -1
		return fcntl.ioctl (self.fd, 0x1, chan)
 
	def read (self):
		return fcntl.ioctl (self.fd, 0x2, chan)
 
class motor:
	"""This class can be used to control a standard DC motor using two GPIO pins.
Class define three methods: forward(), backward() and stop()"""
	def __init__ (self, pin1, pin2):
		self.pt1 = pin( pin1, "out")
		self.pt2 = pin( pin2, "out")
		self.off()
 
	def forward(self):
		self.pt1.on()
		self.pt2.off()
 
	def backward(self):
		self.pt1.off()
		self.pt2.on()
 
	def stop(self):
		self.pt1.off()
		self.pt2.off()
 
 
class stepper:
	""" This class allow you to drive a stepper motor using gpio pins.\n
The stepper class use the follow paramethers for costructor:\n
     (enable, direction, step, [limit], [low_pwr])\n
	"""
	have_limit = 0
	have_lowpwr = 0
	is_at_end = 0
	direction = 0
 
	def __init__ (self, en, dir, step, limit=0, low_pwr=0):
		self.en_pin 	= pin(en, "out")
		self.dir_pin 	= pin(dir, "out")
		self.step_pin 	= pin(step, "out")
		if (low_pwr != 0):
			self.lwpwr_pin 	= pin(low_pwr, "out")
			self.have_lowpwr= 1
		if (limit != 0):
			self.limit_pin 	= pin(limit, "in")
			self.have_limit = 1
		#reset the hw
		self.dir(0)
		self.disable()
 
	def enable (self):
		self.en_pin.off()
 
	def disable (self):
		self.en_pin.on()
 
	def dir (self, value):
		self.dir_pin.set(value)
		self.direction = value
 
	def recover_end (self, step=300):
		print "direction: %d" % self.direction
		self.dir_pin.set(not self.direction)
		for i in range(0, step):
			self.step_pin.set(0)
			self.step_pin.set(1)
		self.dir_pin.set(self.direction)
 
	def step (self, number=1, delay=0, recover_step=300):
		self.enable()
		time.sleep(0.001)
		for i in range(0, number):
			#check if at limit
			if (self.have_limit and self.limit_pin.get() == 0):
					self.recover_end(recover_step)
					self.disable()
					return number - i + recover_step	#missing steps
			self.step_pin.set(0)
			self.step_pin.set(1)
		time.sleep(0.001)
		self.disable()
		return 0
 
	def free(self):
		self.en_pin.free()
		self.dir_pin.free()
		self.step_pin.free()
		if (self.have_limit):
			self.limit_pin.free()
		if (self.have_lowpwr):
			self.low_pwr.free()

Links

1) inside C code
2) ON/OFF cycle on single gpio
3) this example is not intend to be used as is
 
hw/gpio.txt · Last modified: 2010/02/19 23:16 by claudyus
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki