-
Notifications
You must be signed in to change notification settings - Fork 9
GPIO
For available GPIO pins on the RasPi see expansion header.
For default pull-up/pull-down modes see Table 6-31 of BCM2835-ARM-Peripherals.pdf.
We use BCM pad 18 for testing with a LED + serial resistor. Connect the LED cathode (shorter wire) to GND (J8 pin 14) and LED anode (longer wire) via a serial resistor for current limiting to J8 pin 12 which is routed to BCM pin 18.
expansion header pin | pin funcion | SoC pin | connect |
---|---|---|---|
12 | GPIO | 18 | resistor -> LED anode |
14 | GND | LED cathode |
Note: the following uses the sysfs interface which is now deprecated. Since kernel 4.8 there is a new libgpiod interface. Todo: adapt to the new interface.
from the command prompt on your running Pi:
export (==make visible) GPIO pin 18:
root@raspberrypi3:~# echo 18 > /sys/class/gpio/export
make pin 18 an output:
root@raspberrypi3:~# echo out > /sys/class/gpio/gpio18/direction
set its value to 1 (high), the LED should switch on:
root@raspberrypi3:~# echo 1 > /sys/class/gpio/gpio18/value
set its value to 0 (low), the LED should switch off:
root@raspberrypi3:~# echo 0 > /sys/class/gpio/gpio18/value
If you like bash hacking, let the LED blink from the console. A main loop could look like:
while :
do
echo 1 > /sys/class/gpio/gpio18/value
sleep 1
echo 0 > /sys/class/gpio/gpio18/value
sleep 1
done
but it is still missing initialization and termination code:
- export must be done only once in the beginning when
/sys/class/gpio/gpio18/
does not yet exists - it is good style to unexport the pin if no longer needed (which also switches the LED off)
In the shell script this can be achieved with a
trap
line.
A complete example looks like:
# /bin/sh
# signal handler containing termination code
trap "echo 18 > /sys/class/gpio/unexport; exit" SIGHUP SIGINT SIGTERM
# initialization code
echo 18 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio18/direction
# main loop
while :
do
echo 1 > /sys/class/gpio/gpio18/value
sleep 1
echo 0 > /sys/class/gpio/gpio18/value
sleep 1
done
Timing can hardly be controlled when using a shell for GPIO toggling. Try the shortest possible pulse:
echo 0 > /sys/class/gpio/gpio18/value
echo 1 > /sys/class/gpio/gpio18/value
echo 0 > /sys/class/gpio/gpio18/value
Using a scope you may see a 3..5 ms wide pulse. But, there is guarantee for timing! So, using the shell interface is mainly useful for testing and slow peripherals like switching a LED on. It cannot be used for PWM or motor control.
This code can be one-to-one translated into C code using POSIX style file access functions. For a complete example see: http://www.netzmafia.de/skripten/hardware/RasPi/RasPi_GPIO_C.html
Note: The C equivalent of a trap command is a signal handler.
The timing may be faster, but remains rather unpredictable because the user mode C app may be interrupted by the Linux scheduler. Moreover, the sleep
function and its friends only guarantee minimum timeouts.
Example GPIO4 (header pin 7).
# export Pin
$ echo 4 > /sys/class/gpio/export
# activate falling edge interrupt
$ echo falling > /sys/class/gpio/gpio4/edge
# watch interrupts in shell
$ watch -n1 "cat /proc/interrupts"
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
int main()
{
// pin must already been exported and configured for interrupt (shell)
int fd = open( "/sys/class/gpio/gpio4/value", O_RDONLY);
if(fd < 0) {
perror("fd");
}
struct pollfd pollfds;
pollfds.fd = fd;
pollfds.events = POLLPRI;
static char buf[256];
lseek(fd, 0, SEEK_SET);
read(fd, buf, sizeof buf);
while(1) {
int result = poll (&pollfds, 1, 100);
if( result > 0 ) {
lseek(fd, 0, SEEK_SET);
read(fd, buf, sizeof buf);
printf("!");
fflush(stdout);
}
}
}
For best timing control, interrupt handling etc. you should consider writing a Kernel Module.