Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
General Purpose IO Driver
Clone this wiki locally
General purpose I/O signals
Gpio driver provides a service for user applications to access general purpose I/O signals of the chip.
Only programms with root privileges are allowed to open gpio devices.
To enable gpio driver in the kernel, add the following lines to your kernel configuration file:
# General purpose I/O ports for 144-pin chip device gpio0 flags 0xc6ff # port A device gpio1 flags 0xffff # port B device gpio2 flags 0xf01e # port C device gpio3 flags 0xfeff # port D device gpio4 flags 0x03ff # port E device gpio5 flags 0x313f # port F device gpio6 flags 0xf3c3 # port G device gpio7 flags 0xffff # port H device gpio8 flags 0xffff # port J device gpio9 flags 0x00ff # port K
Every gpioN device corresponds to one 16-bit i/o port. Flags specify a bitmask of available signals. The mask depends on which signals are supported in hardware, and which of them you want to allow for the user applications. For chips with lower pin count, fewer signals are available, and ports H, J and K not present. It makes sense as well to disable signals allocated for UARTs, SPI ports, SD card etc.
When kernel starts, it prints the configuration of i/o ports. For example, for chipKIT WiFire board:
gpio0 at portA, pins -i---ii-iiiiiiii gpio1 at portB, pins i---i-iiiiiiiiii gpio2 at portC, pins iiii---------i-- gpio3 at portD, pins --ii------iiii-i gpio4 at portE, pins ------iiiiiiiiii gpio5 at portF, pins --ii--------i--- gpio6 at portG, pins iiii--iii-------
For every i/o port, two devices are created, /dev/confX and /dev/portX:
# ls -l /dev/conf? /dev/port? crw-rw-rw- 1 root operator 18, 64 Apr 3 18:48 /dev/confa crw-rw-rw- 1 root operator 18, 65 Apr 3 18:48 /dev/confb crw-rw-rw- 1 root operator 18, 66 Apr 3 18:48 /dev/confc crw-rw-rw- 1 root operator 18, 67 Apr 3 18:48 /dev/confd crw-rw-rw- 1 root operator 18, 68 Apr 3 18:48 /dev/confe crw-rw-rw- 1 root operator 18, 69 Apr 3 18:48 /dev/conff crw-rw-rw- 1 root operator 18, 70 Apr 3 18:48 /dev/confg crw-rw-rw- 1 root operator 18, 71 Apr 3 18:48 /dev/confh crw-rw-rw- 1 root operator 18, 72 Apr 3 18:48 /dev/confj crw-rw-rw- 1 root operator 18, 73 Apr 3 18:48 /dev/confk crw-rw-rw- 1 root operator 18, 0 Apr 3 18:48 /dev/porta crw-rw-rw- 1 root operator 18, 1 Apr 3 18:48 /dev/portb crw-rw-rw- 1 root operator 18, 2 Apr 3 18:48 /dev/portc crw-rw-rw- 1 root operator 18, 3 Apr 3 18:48 /dev/portd crw-rw-rw- 1 root operator 18, 4 Apr 3 18:48 /dev/porte crw-rw-rw- 1 root operator 18, 5 Apr 3 18:48 /dev/portf crw-rw-rw- 1 root operator 18, 6 Apr 3 18:48 /dev/portg crw-rw-rw- 1 root operator 18, 7 Apr 3 18:48 /dev/porth crw-rw-rw- 1 root operator 18, 8 Apr 3 18:48 /dev/portj crw-rw-rw- 1 root operator 18, 9 Apr 3 18:48 /dev/portk
I/O configuration device
Device /dev/confX defines the direction of the signals (input or output) and optional open-drain mode for outputs. You can display the current configuration by reading the devices, for example:
# cat /dev/conf? -i---ii-iiiiiiii o---o-oiooioooii iiii---------i-- --io------iooo-i ------iiiiiiiiii --ii--------i--- ooio--oio-------
Here you can see that some signals are configured as inputs "i", and some as outputs "o". Open drain signals would be marked as "d".
You can change the configuration by writing appropriate string to the device. For example, to configure pins PA0 and PA1 as input, PA2 as output and PA3 as open-drain output:
# echo .............doii > /dev/confa
Write to /dev/confX:
- 'i' - configure the corresponding port pin as an input;
- 'o' - configure the corresponding port pin as an output;
- 'd' - configure the corresponding port pin as an open-drain output;
- '.' - no action.
I/O port device
Device /dev/portX specifies the values of input or output signals. You can read the devices to view the current status af all pins, for example:
# cat /dev/port? -1---10-11001101 0---0-0000000000 1000---------0-- --11------1011-1 ------0000001111 --00--------0--- 0111--000-------
To modify the output value of some signals, write the needed string to the device. For example, to set pins A2 and A3 to high level:
# echo .............11.. > /dev/porta
Write to /dev/portX:
- '0' - set output pin low;
- '1' - set output pin high;
- '+' - invert the value of output pin;
- '.' - no action.
Command portio is a simple command line utility for more sophisticated control of the i/o ports.
The arguments consist of a list of actions. Option -v enables verbose mode:
portio [-v] action...
|-i port...||configure ports as input|
|-o port...||configure ports as output|
|-d port...||configure ports as open-drain output|
|-a port number||assign port value|
|-s port...||set ports to 1|
|-c port...||clear ports (set to 0)|
|-r port...||reverse ports (invert)|
|-g port...||get port values|
|-m number||delay in milliseconds|
Parameter "port" is a single pin name, or list of pin names, or a port name:
|b3-7,11||list of pins|
|c||same as c0-15|
Here is an example of multiple actions per single portio invocation:
# portio -o a1-2 c15 -i b0-3 d -s a1 c15 -c a2 -g b d
This call performs the following actions:
- Configure pins RA1, RA2 and RC15 as outputs
- Configure pins RB0-RB3 and RD0-RD15 as inputs
- Set pins RA1 and RC15 high
- Set pin RA2 low
- Get values of ports B and D (pins RB0-RB15 and RD0-RD15)
Option -m inserts a delay by given number of milliseconds.
From user application, the I/O pins can be controlled via ioctl() system call. You can use any of /dev/portX or /dev/confX devices, it ir irrelevant which one to open.
The generic interface is:
#include <fcntl.h> #include <machine/gpio.h> ... int fd = open("/dev/porta", O_RDWR); ioctl(fd, port_ident | operation, pinmask);
Port identifier is:
- GPIO_PORTA or GPIO_PORT(0) for port A;
- GPIO_PORTB or GPIO_PORT(1) for port B;
- GPIO_PORTC or GPIO_PORT(2) for port C;
- GPIO_PORTD or GPIO_PORT(3) for port D;
- GPIO_PORTE or GPIO_PORT(4) for port E;
- GPIO_PORTF or GPIO_PORT(5) for port F;
- GPIO_PORTG or GPIO_PORT(6) for port G;
- GPIO_PORTH or GPIO_PORT(7) for port H;
- GPIO_PORTJ or GPIO_PORT(8) for port J;
- GPIO_PORTK or GPIO_PORT(9) for port K.
Operation is one or multiple of:
|GPIO_CONFIN||configure pins as input|
|GPIO_CONFOUT||configure pins as output|
|GPIO_CONFOD||configure pins as open drain output|
|GPIO_STORE||set all output pins to given value|
|GPIO_SET||set output pins to 1|
|GPIO_CLEAR||set output pins to 0|
|GPIO_INVERT||invert output pins by mask|
|GPIO_POLL||get input values (pinmask ignored)|
Pins are specified as bitmask: bit 0 corresponds to pin 0, bit 1 - pin 1 etc.
A few examples:
// Configure pins RA1, RA2 and RC15 as outputs ioctl(fd, GPIO_PORTA | GPIO_CONFOUT, 1<<1 | 1<<2); ioctl(fd, GPIO_PORTC | GPIO_CONFOUT, 1<<15); // Configure pins RB0-RB3 and RD0-RD15 as inputs ioctl(fd, GPIO_PORTB | GPIO_CONFIN, 0x000f); ioctl(fd, GPIO_PORTD | GPIO_CONFIN, 0xffff); // Set pins RA1 and RC15 high ioctl(fd, GPIO_PORTA | GPIO_SET, 1<<1); ioctl(fd, GPIO_PORTC | GPIO_SET, 1<<15); // Set pin RA2 low ioctl(fd, GPIO_PORTA | GPIO_CLEAR, 1<<2); // Get values of ports B and D portb = ioctl(fd, GPIO_PORTB | GPIO_POLL, 0); portd = ioctl(fd, GPIO_PORTD | GPIO_POLL, 0);
Several operations for the same port can be combined in a single call. For example, to toggle pin A2 high then low, and get value of all PORTA pins:
val = ioctl(fd, GPIO_PORTA | GPIO_SET | GPIO_CLEAR | GPIO_POLL, 1 << 3);