Wednesday, 24 July 2013

Access GPIO from Linux user space

Access GPIO from Linux user space

GPIO mean "General Purpose Input/Output" and is a special pin present in some chip that can be set as input or output and used to move a signal high or low (in output mode) or to get the signal current status (in input mode). Usually these pin are directly managed by kernel modules but there are an easy way to manage these pins also from user space.

Standard Linux kernel have inside a special interface allow to access to GPIO pins. Once executed kernel menuconfig you can easily verify is this interface is active in your kernel and, in case, enable them. The kernel tree path is the following:

Device Drivers  ---> GPIO Support  ---> /sys/class/gpio/... (sysfs interface)

If not, enable this feature and recompile the kernel before continue to read. The interface to allow working with GPIO is at the following filesystem path:

/sys/class/gpio/

Basically if you want to work with a particular GPIO you must first to reserve it, set the input/output direction and start managing it. Once you reserved the GPIO and finished to use you need to free it for allow other modules or process to use them. This rule is valid in both cases you want to use GPIO from kernel level or user level.

Manage GPIO from command line or script

From the user level side this "operation" for reserve the GPIO is called "export" the GPIO. For make this export operation you simply need to echo the GPIO number you are interested to a special path as follow (change XX with the GPIO number you need):

echo XX > /sys/class/gpio/export

If operation successful (the possible case of operation failed is explained below) a new "folder" will show up in the GPIO interface path as example below:

/sys/class/gpio/gpioXX/

This new "folder" will allow you to work with the GPIO you just reserved. In particular if you want to set the in/out direction you simply need to execute the following echo commands:

echo "out" > /sys/class/gpio/gpioXX/direction

or

echo "in" > /sys/class/gpio/gpioXX/direction

In case you set out direction you can directly manage the value of GPIO. You can make this operation by executing additional echo commands like:

echo 1 > /sys/class/gpio/gpioXX/value

or

echo 0 > /sys/class/gpio/gpioXX/value

Since GPIO is a single pin the possible states allowed are high (1) and low (0). In case you set in direction you can read the current pin value by using the following command:

cat /sys/class/gpio/gpioXX/value

Once finished to use your GPIO you can free it by make the same echo command but to different path:

echo XX > /sys/class/gpio/unexport

In case of GPIO folder not showed after export operation is very likely that the GPIO is already reserved by some module. For verify the current reserved GPIO map you must first verify if in your kernel is enabled the following feature:

Kernel configuration ---> Kernel hacking ---> Debug FS

As usual, if not enabled, enable it and recompile the kernel. The next step is to launch the following command line for mount debugfs:

mount -t debugfs none /sys/kernel/debug

and dump the current GPIO configuration by using:

cat /sys/kernel/debug/gpio

The output will show you the current list og reserved GPIO.

Manage GPIO from application

All these same operations can be made using a software application. Follow short lines of C code showing how the reproduce the same steps as above (remember to change XX with the GPIO number you want to use).

Reserve (export) the GPIO:

int fd;
char buf[MAX_BUF]; 
int gpio = XX;

fd = open("/sys/class/gpio/export", O_WRONLY);

sprintf(buf, "%d", gpio); 

write(fd, buf, strlen(buf));

close(fd);

Set the direction in the GPIO folder just created:

sprintf(buf, "/sys/class/gpio/gpio%d/direction", gpio);

fd = open(buf, O_WRONLY);

// Set out direction
write(fd, "out", 3); 
// Set in direction
write(fd, "in", 2); 

close(fd);

In case of out direction set the value of GPIO:

sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);

fd = open(buf, O_WRONLY);

// Set GPIO high status
write(fd, "1", 1); 
// Set GPIO low status 
write(fd, "0", 1); 

close(fd);

In case of in direction get the current value of GPIO:

char value;

sprintf(buf, "/sys/class/gpio/gpio%d/value", gpio);

fd = open(buf, O_RDONLY);

read(fd, &value, 1);

if(value == '0')
{ 
     // Current GPIO status low
}
else
{
     // Current GPIO status high
}

close(fd);

Once finished free (unexport) the GPIO:

fd = open("/sys/class/gpio/unexport", O_WRONLY);

sprintf(buf, "%d", gpio);

write(fd, buf, strlen(buf));

close(fd);

An important note you have to keep in mind if you plan to set or, more important, get the value of a GPIO through this way in continous mode. If you open the "value" file for get the current GPIO status (1 or 0) remember that, after the fist read operation, the file pointer will move to the next position in the file. Since this interface was made to be read from cat command the returned string will be terminated by the new line character (\n). This mean after the first "valid" read all the next read operation will return always the last character in the file, in this case only the new line '\n'. For obtain a correct status value for each read operation you simply have to set the file pointer at the beginning of the file before read by using the command below:

lseek(fp, 0, SEEK_SET);

You will not have this problem if you open and close GPIO value file every time you need to read but, as you can know, for continuous read introduce a short delay. Since these short lines of codes are only an example if you want to use them in your code remember add the control for error in open GPIO file. 

No comments:

Post a Comment