User Tools

Site Tools


doc:hardware:port.gpio

GPIO

Hardware

GPIOs are commonly used in router devices for buttons or leds. They only safely supply or sink (pull to GND) a maximum of 4mA aprox., and the voltage is usually 3.3V when active. Only two states are posible: high or low. Depending on how a device is activated by a GPIO, active low or active high is defined.

  • Active high: the device is activated when the GPIO is HIGH
  • Active low: the device is activated when the GPIO is LOW

In this image you can see how a GPIO is wired to buttons or leds, to work as active low or high



GPIOs can be used for complex tasks:

kernel module description
1-wire kmod-w1-master-gpio 1-wire bus master
PWM kmod-pwm-gpio pulse width modulator
SPI kmod-spi-gpio bitbanging Serial Peripheral Interface
kmod-mmc-over-gpio MMC/SD card over GPIO
I2C kmod-i2c-gpio bitbanging I2C
LIRC
LIRC GPIO blaster
no official module yet
kmod-lirc_gpioblaster
Linux Infrared Remote Control
Rotary encoder kmod-input-gpio-encoder GPIO rotary encoder
Custom Rotary Encoder kmod-rotary-gpio-custom Custom GPIO rotary encoder
rcswitch-kmod rcswitch-kmod (not yet packaged in OpenWrt) 433 MHz RC power outlets (switches)

You can connect 5V digital signal sensors if you use a voltage devider to get a 3.3V range signal.You need to get acces to GND and 5V-power from the router and connect the sensor to them. Sensor signal output is in the 5V range, connect it to the voltage devider!



Many times some GPIOs cannot be controlled by the kernel because they are multiplexed, and they are not acting as GPIOs. It might be possible to undo the multiplexing by writing some particular memory registers, and then recover the GPIO functionality. But probably on most cases those GPIOs were multiplexed for some good reason, like using a pin on the SoC for purposes like a signal on an ethernet phy, SPI, PCI, or another purpose.

GPIO Interrupts

GPIO interrupts are useful when a GPIO is used as input and you need to manage high signal frequencies. Without interrupts, GPIO inputs must be managed using the polling method. With polling you cannot manage signal inputs with high frequencies, but still can be used for simple tasks like reading the input on the device buttons.

GPIO IRQs are also useful for detecting the edge from an input, it can be rising or falling. Some GPIO drivers also need this feature.

Not all boards have GPIO interrupts, or the GPIO kernel drivers don't provide IRQs because they aren't still implemented. As a result of this, some input drivers listed above (requiring GPIO IRQs) won't work in these boards.

Software

In linux GPIOs can be accesed through GPIO SYSFS interface: /sys/class/gpio/

Example
In this example we will use GPIO29 and use it as a switch.

With latest linux kernels you may need to first get the gpio base

cat /sys/class/gpio/gpiochip*/base | head -n1
200
and sum the base to your GPIO:
200 + 29 = 229

Now first step is making GPIO available in Linux:

echo "229" > /sys/class/gpio/export
then you need to decide if it will be input or output, as we will use it as a switch so we need output
echo "out" > /sys/class/gpio/gpio229/direction
and last line turns GPIO on or off with 1 or 0:
echo "1" > /sys/class/gpio/gpio229/value

Utilities

To control GPIOs you can use gpioctl-sysfs. Also with this simple script you can control GPIOs not used by buttons or leds.

#!/bin/sh
 
show_usage()
{
    printf "\ngpio.sh <gpio pin number> [in|out [<value>]]\n"
}
 
if [ \( $# -eq 0 \) -o \( $# -gt 3 \) ] ; then
    show_usage
    printf "\n\nERROR: incorrect number of parameters\n"
    exit 255
fi
 
GPIOBASE=`cat /sys/class/gpio/gpiochip*/base | head -n1`
GPIO=`expr $1 + $GPIOBASE`
 
#doesn't hurt to export a gpio more than once
(echo $GPIO > /sys/class/gpio/export) >& /dev/null
 
if [  $# -eq 1 ] ; then
   cat /sys/class/gpio/gpio$GPIO/value
   exit 0
fi
 
if [ \( "$2" != "in" \) -a  \( "$2" != "out" \) ] ; then
    show_usage
    printf "\n\nERROR: second parameter must be 'in' or 'out'\n"
    exit 255
fi
 
echo $2 > /sys/class/gpio/gpio$GPIO/direction
 
if [  $# -eq 2 ] ; then
   cat /sys/class/gpio/gpio$GPIO/value
   exit 0
fi
 
 
VAL=$3
 
if [ $VAL -ne 0 ] ; then
    VAL=1
fi
 
echo $VAL > /sys/class/gpio/gpio$GPIO/value  
Save the script somewhere with the name gpiocontrol.sh an give it execution permisions:

chmod +x gpiocontrol.sh

Example, put the GPIO14 on HIGH state:

./gpiocontrol.sh 14 out 1

Read the input value of GPIO14:

./gpiocontrol.sh 14 in

Finding GPIO pins on the PCB

Sometimes you do not know where the physical GPIO pins are on your device's PCB. In that case, you can use this little script and a multimeter to find out.

#!/bin/sh
 
GPIOBASE=`cat /sys/class/gpio/gpiochip*/base | head -n1`
GPIOmin=`expr $1 + $GPIOBASE`
GPIOmax=`expr $2 + $GPIOBASE`
 
cd /sys/class/gpio
for i in `seq $GPIOmin $GPIOmax`; do
echo $i > export; echo out >gpio$i/direction
done
nums=`seq $GPIOmin $GPIOmax`
while true; do
  for i in $nums; do
     echo 0 > gpio$i/value
 done
  sleep 1
  for i in $nums; do
     echo 1 > gpio$i/value
  done
  sleep 1
done

  1. Start with ./gpio 0 30, which means pin 0 to 30
  2. Press ctrl-c to stop the script, then check which GPIOs have been created: find /sys/class/gpio/gpio*
  3. Restart the script and measure with a multimeter which pins "blink".
  4. When you find one, then cut the 0-30 range from above in half;
  5. Repeat until you have identified the gpio number

script "static"

#!/bin/sh
GPIOBASE=`cat /sys/class/gpio/gpiochip*/base | head -n1`
GPIOmin=`expr $1 + $GPIOBASE`
GPIOmax=`expr $2 + $GPIOBASE`
 
cd /sys/class/gpio
for i in `seq $GPIOmin $GPIOmax`; do
     echo "[GPIO$i] Trying value $3"
     echo $i > export; echo out >gpio$i/direction
     echo $3 > gpio$i/value
     echo $i > unexport
done

  1. Measure continuosuly the voltage of the pin where you suspect there is a GPIO wired, with a multimeter or another device.
  2. Put all GPIOs on HIGH state ./gpio 0 31 1
  3. Put all GPIOs on LOW state ./gpio 0 31 0
  4. If the pin changes the voltage, then cut the 0-31 range from above in half ./gpio 16 31 1
  5. If the pin doesn't change the voltage,then use the other half range ./gpio 0 15 1
  6. Cut again the new range.
  7. Repeat until you have identified the gpio number

Note: some GPIOs may return an error because they're already used by the Linux kernel (i.e LEDS).

Finding GPIO pins (input) on the PCB

Sometimes you do not know where the physical GPIO pins (input) are on your device's PCB. In that case, you can use this little script and see screen to find the input.

#!/bin/sh
GPIOBASE=`cat /sys/class/gpio/gpiochip*/base | head -n1`
GPIOmin=`expr $1 + $GPIOBASE`
GPIOmax=`expr $2 + $GPIOBASE`
 
cd /sys/class/gpio
for i in `seq $GPIOmin $GPIOmax`; do
echo $i > export; echo in >gpio$i/direction
done
nums=`seq $GPIOmin $GPIOmax`
while true; do
  for i in $nums; do
     echo read gpio$i 
     cat /sys/class/gpio/gpio$i/value
 done
  sleep 1
done

  1. Start with ./gpio 0 30, which means pin 0 to 30
  2. Press button or change the value input.
  3. The script returns on screen: 'read gpio+number' followed by '0' or '1'.
  4. Press ctrl-c to stop the script, then check which GPIOs have been created: find /sys/class/gpio/gpio*
doc/hardware/port.gpio.txt · Last modified: 2016/02/08 11:55 by danitool