This document explains how to manage the GPIO lines on the FOX Board G20 using the Sysfs interface
Written by Sergio Tanzilli
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.
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
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()
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.
A resistor between transistor base and foxg20 should be added IMHO. — Claudio 2010/02/11 12:41You'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Ω
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.
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)
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 |
On acme-dev project is available a python library that can be used also to control gpio pin.
See the class pin definition.
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()