Linux GPIO用户空间操作

           目前遇到一个问题,内核中已实现了gpio驱动,而且在内核空间可以正常使用
gpio_request,gpio_direction_output,gpio_free等gpiolib中提供的函数

          只是想在用户空间中对gpio进行操作,发现/dev下并没有相关的gpio设备
准备写个.ko实现ioctl来间接操作,想了一下,这么常用的gpio,这么强大的linux,不应该不提供相应的操作接口,于是百度
以下是我找到的方法。

命令行
echo 28 > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio28/direction
echo 1 > /sys/class/gpio/gpio28/value

既然找到了上面的接口,那么怎么在用户空间的程序使用呢

方法1.使用system()
        char setCmd[100]={0};

        sprintf(setCmd, "echo %d > /sys/class/gpio/export",RUN_LED);
        system(setCmd);

        memset(setCmd, 0, sizeof(setCmd));
        sprintf(setCmd, "echo \"out\" > /sys/class/gpio/gpio%d/direction",RUN_LED);
        printf("VALUE:%s\n",setCmd);
        system(setCmd);
        memset(setCmd, 0, sizeof(setCmd));
        sprintf(setCmd, "echo %d > /sys/class/gpio/gpio%d/value",onoff,RUN_LED);
        system(setCmd);

方法2.将几个echo写成脚本
使用execve()调用脚本
execve("gpio.sh", "/etc", NULL);
这个方法个人感觉没方法1好,所以具体实现略

方法3.这个比较正式的用法,mark
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>

 /****************************************************************
 * Constants
 ****************************************************************/
 
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define POLL_TIMEOUT (3 * 1000) /* 3 seconds */
#define MAX_BUF 64

/****************************************************************
 * gpio_export
 ****************************************************************/
int gpio_export(unsigned int gpio)
{
	int fd, len;
	char buf[MAX_BUF];
 
	fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
	if (fd < 0) {
		perror("gpio/export");
		return fd;
	}
 
	len = snprintf(buf, sizeof(buf), "%d", gpio);
	write(fd, buf, len);
	close(fd);
 
	return 0;
}

/****************************************************************
 * gpio_unexport
 ****************************************************************/
int gpio_unexport(unsigned int gpio)
{
	int fd, len;
	char buf[MAX_BUF];
 
	fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
	if (fd < 0) {
		perror("gpio/export");
		return fd;
	}
 
	len = snprintf(buf, sizeof(buf), "%d", gpio);
	write(fd, buf, len);
	close(fd);
	return 0;
}

/****************************************************************
 * gpio_set_dir
 ****************************************************************/
int gpio_set_dir(unsigned int gpio, unsigned int out_flag)
{
	int fd, len;
	char buf[MAX_BUF];
 
	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
 
	fd = open(buf, O_WRONLY);
	if (fd < 0) {
		perror("gpio/direction");
		return fd;
	}
 
	if (out_flag)
		write(fd, "out", 4);
	else
		write(fd, "in", 3);
 
	close(fd);
	return 0;
}

/****************************************************************
 * gpio_set_value
 ****************************************************************/
int gpio_set_value(unsigned int gpio, unsigned int value)
{
	int fd, len;
	char buf[MAX_BUF];
 
	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 
	fd = open(buf, O_WRONLY);
	if (fd < 0) {
		perror("gpio/set-value");
		return fd;
	}
 
	if (value)
		write(fd, "1", 2);
	else
		write(fd, "0", 2);
 
	close(fd);
	return 0;
}

/****************************************************************
 * gpio_get_value
 ****************************************************************/
int gpio_get_value(unsigned int gpio, unsigned int *value)
{
	int fd, len;
	char buf[MAX_BUF];
	char ch;

	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 
	fd = open(buf, O_RDONLY);
	if (fd < 0) {
		perror("gpio/get-value");
		return fd;
	}
 
	read(fd, &ch, 1);

	if (ch != '0') {
		*value = 1;
	} else {
		*value = 0;
	}
 
	close(fd);
	return 0;
}


/****************************************************************
 * gpio_set_edge
 ****************************************************************/

int gpio_set_edge(unsigned int gpio, char *edge)
{
	int fd, len;
	char buf[MAX_BUF];

	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
 
	fd = open(buf, O_WRONLY);
	if (fd < 0) {
		perror("gpio/set-edge");
		return fd;
	}
 
	write(fd, edge, strlen(edge) + 1); 
	close(fd);
	return 0;
}

/****************************************************************
 * gpio_fd_open
 ****************************************************************/

int gpio_fd_open(unsigned int gpio)
{
	int fd, len;
	char buf[MAX_BUF];

	len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
 
	fd = open(buf, O_RDONLY | O_NONBLOCK );
	if (fd < 0) {
		perror("gpio/fd_open");
	}
	return fd;
}

/****************************************************************
 * gpio_fd_close
 ****************************************************************/

int gpio_fd_close(int fd)
{
	return close(fd);
}

/****************************************************************
 * Main
 ****************************************************************/
int main(int argc, char **argv, char **envp)
{
	struct pollfd fdset[2];
	int nfds = 2;
	int gpio_fd, timeout, rc;
	char *buf[MAX_BUF];
	unsigned int gpio;
	int len;



	if (argc < 2) {
		printf("Usage: gpio-int <gpio-pin>\n\n");
		printf("Waits for a change in the GPIO pin voltage level or input on stdin\n");
		exit(-1);
	}

	gpio = atoi(argv[1]);

	gpio_export(gpio);
	gpio_set_dir(gpio, 0);
	gpio_set_edge(gpio, "rising");
	gpio_fd = gpio_fd_open(gpio);

	timeout = POLL_TIMEOUT;
 
	while (1) {
		memset((void*)fdset, 0, sizeof(fdset));

		fdset[0].fd = STDIN_FILENO;
		fdset[0].events = POLLIN;
      
		fdset[1].fd = gpio_fd;
		fdset[1].events = POLLPRI;

		rc = poll(fdset, nfds, timeout);      

		if (rc < 0) {
			printf("\npoll() failed!\n");
			return -1;
		}
      
		if (rc == 0) {
			printf(".");
		}
            
		if (fdset[1].revents & POLLPRI) {
			len = read(fdset[1].fd, buf, MAX_BUF);
			printf("\npoll() GPIO %d interrupt occurred\n", gpio);
		}

		if (fdset[0].revents & POLLIN) {
			(void)read(fdset[0].fd, buf, 1);
			printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
		}

		fflush(stdout);
	}

	gpio_fd_close(gpio_fd);
	return 0;
}


附:支持fs调试的配置方法


Configure the kernel for GPIO support in sysfs

Symbol: GPIO_SYSFS [=y]
  Prompt: /sys/class/gpio/... (sysfs interface)
    Defined at drivers/gpio/Kconfig:51
    Depends on: GPIOLIB && SYSFS && EXPERIMENTAL
     Location:
      -> Kernel configuration
        -> Device Drivers
         -> GPIO Support (GPIOLIB [=y])
 

Enable GPIO access from user space

GPIO=22

cd /sys/class/gpio
ls
echo $GPIO > export
ls

Notice on the first ls that gpio22 doesn't exist, but does after you export GPIO 22 to user space.

cd /sys/class/gpio/gpio$GPIO
ls

There are files to set the direction and retrieve the current value.

echo "in" > direction
cat value

You can configure the GPIO for output and set the value as well.


echo "out" > direction
echo 1 > value

GPIO interrupts from user space

Reference

  • http://bec-systems.com/site/281/how-to-implement-an-interrupt-driven-gpio-input-in-linux
  • http://www.spinics.net/lists/linux-newbie/msg01028.html
  • elinux.org/images/d/d4/Celf-gpio.odp
  • http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:gpio-sysfs

LeopoardBoard 365 GPIO 0 connection

On the LeopardBoard 365, the only GPIO I could find that was usable for interrupt input is GPIO0, also called CMOS_TRIGGER in the schematics. In looking at the schematics resistor R12 is not loaded and one of the pads connects to CMOS_TRIGGER. This R12 pad is the one closest to R11. If you hold the leopardboard 365 with the SD card slot facing you and rotate the board until the SD card slot is on the bottom edge, the the R12 pads are to the right of J6 and to the left of the SD card slot upper left corner.

Using poll() to monitor for GPIO 0 change

The gpio-int-test.c program (or gpiopin.cpp for those who prefer C++) shows one way of using the sysfs file /sys/class/gpio/gpio0/value to block program execution using poll() until the input level on GPIO0 changes. The tricky part was figuring out to use POLLPRI instead of POLLIN as the event to monitor. You must have GPIO support in sysfs for this program to work (or you will not see the /sys/class/gpio directory).


The gpio-int-test.c program uses poll() to wake up every 3 seconds (using poll() timeout mechanism) at which time it prints a period. The poll() function is also watching for input from stdin and for an interrupt from GPIO 0.

Here is an example output. I started gpio-int to watch GPIO 0. I waited around 12 seconds (4 timeout periods), then pressed the letter 'a' twice followed by enter key. Then I shorted the haywire to 3.3V that is accessible on pin 5 on the JTAG connector. JTAG pin 5 is across from the JTAG missing pin). I exited the program using cntl-C.

/root # gpio-int 0 

....aa

poll() stdin read 0xA61

poll() stdin read 0xA61

poll() stdin read 0xA0A
..
poll() GPIO 0 interrupt occurred (len 0)

poll() GPIO 0 interrupt occurred (len 0)

poll() GPIO 0 interrupt occurred (len 0)

poll() GPIO 0 interrupt occurred (len 0)
..^C

Viewing GPIO Configuration

You can use debugfs to videw the current GPIO configuration. You may also be able to use debugfs to see if the GPIO pin is multiplex as a GPIO or is dedicated to some other function.

Configure the kernel to enable debugfs:

Symbol: DEBUG_FS [=y]
   Prompt: Debug Filesystem
     Defined at lib/Kconfig.debug:77
     Depends on: SYSFS     
     Location:
       -> Kernel configuration
         -> Kernel hacking         

Boot the target hardware and mount debugfs:

mount -t debugfs none /sys/kernel/debug

Dump the GPIO configuration.

cat /sys/kernel/debug/gpio

Dump the pin multiplexing configuration.

cat /sys/kernel/debug/omap_mux/board      # for OMAP
cat /sys/kernel/debug/dm365_mux           # for DM36x


















你可能感兴趣的:(linux,GPIO,用户空间)