Fastest method for reading a GPIO value from user space

Hi,

I have a function within an application which blocks until a GPIO input value of 0 is detected. I’m currently using the standard sysfs approach to continuously open the /value file, read it, and if the value is 1, close the file, and then repeat. This is obviously not a very effective method for checking the GPIO value; it requires that the chip controlling the GPIO maintains the active low condition for quite a long time to ensure the Apalis reads the /value file at the right time, and also leads to considerable latency as the closing, opening and reading sequence takes time.

I have read elsewhere (including on this forum) about instead accessing the GPIO value using mmap. What I haven’t been able to determine is how I find the address of a given GPIO. In which datasheet would this information be listed? Finally, would this mmap approach be the fastest method for checking a GPIO value? I’ve considered the use of gpiod as well, but I’m not sure if this would offer a substantial improvement over sysfs.

Thanks!

HI @jars121

Thanks for writing to the Toradex Community!

Regarding your application, why are you closing and opening the file again? You can also just keep the FD open and do polling.

I have read elsewhere (including on this forum) about instead accessing the GPIO value using mmap.

The address of the GPIOs will be in Reference Manual.

Finally, would this mmap approach be the fastest method for checking a GPIO value?

What is your requirement? Which delay are you trying to achieve?

Best regards,
Jaski

Hi,

I would use poll() and wait for a FALLING_EDGE event on the line.
Here is a minimal working C example:

If your program is written in another language, you can either do sth. similar there,
or send a SIGNAL from the C programm in order to notify your programm of the PIN event.
(eg. “SIGUSR1”)

#include <stdlib.h>
#include <stdio.h>
#include <error.h>

#include <gpiod.h>
#include <poll.h>

 
#define INT_LINE_OFFSET 15   //IMX6 SODIMM 98 (GPIO1_15 -> gpiochip0, offset 15)
 
int main(void)
{
	/*Setup gpiod line interrupt on falling edge trigger*/
	struct gpiod_chip* gpiochip0 = gpiod_chip_open_by_name("gpiochip0");
	struct gpiod_line* INT_line = gpiod_chip_get_line(gpiochip0, INT_LINE_OFFSET);
 
	if (gpiod_line_request_falling_edge_events(INT_line, "MY_INTERRUPT_LINE") < 0){
		perror("gpiod request failed");
	}
 
	//Setup poll, add more file-descriptors to pollfd structure as needed
	struct pollfd fds[1];
	fds[0].fd = gpiod_line_event_get_fd(INT_line);
	fds[0].events = POLLIN | POLLPRI;
	int poll_events = 0;
 
	while (1){
		printf("Polling for FALLING EDGE event (timeout=10s)\n");
		poll_events = poll(fds, 1, 10000); //timeout = 10000ms (-1 == wait forever)
 
		if (poll_events < 0){
			perror("poll() failed");
 
		}else if(poll_events==0){
			printf("poll() timed out after 10s without event happening\n");

		}else if (fds[0].revents & POLLIN){
			printf("Detected FALLING EDGE event!\n");
		}
	}

	gpiod_line_release(INT_line);
	gpiod_chip_close(gpiochip0);

	return EXIT_SUCCESS;
}

I know I’m responding to an older discussion, but I’m just trying the polling code example and have an issue. Once you get an event, the event trigger isn’t being cleared. In other examples I’ve see, after the event you need to read the fd to clear it, or next time you call poll it will “succeed” immediately. And that’s what I’m seeing running this as is. I’m on a Verdin development board with a GPIO connected to one of the push buttons. I just push the button once and get and endless output of “Detected FALLING EDGE event!”.

You need to call following api to clear the event in the event callback function:

  struct gpiod_line_event ev;
  gpiod_line_event_read_fd(fd, &ev);

Hi @techczech !

If you are still facing issues, please create a new question here in the Community. It will be better from the organizational point of view.

Best regards,