From 7ec153d397754d383f6b71b26376395c3d9b57cf Mon Sep 17 00:00:00 2001 From: William Clark <wrvc96@gmail.com> Date: Thu, 28 Dec 2023 18:10:34 +0000 Subject: [PATCH] interrupt generation --- Makefile | 3 +- interrupt.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++ interrupt.h | 11 +++++ main.c | 46 +++++++++++++------- 4 files changed, 162 insertions(+), 17 deletions(-) create mode 100644 interrupt.c create mode 100644 interrupt.h diff --git a/Makefile b/Makefile index 8003108..9514ba9 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,9 @@ CC=gcc CFLAGS=-O2 -std=c89 -W -Werror -Wall -Wextra -pedantic -I. LFLAGS=-lm +CFILES=$(wildcard ./*.c) all: - $(CC) $(CFLAGS) main.c i2c.c lis3dh.c -o lis3dh $(LFLAGS) + $(CC) $(CFLAGS) $(CFILES) -o lis3dh $(LFLAGS) clean: rm -rf lis3dh diff --git a/interrupt.c b/interrupt.c new file mode 100644 index 0000000..9919da4 --- /dev/null +++ b/interrupt.c @@ -0,0 +1,119 @@ +/* + SYSFS gpio interrupt example for Raspberry Pi +*/ +#define _GNU_SOURCE +#include <stddef.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <poll.h> +#include "interrupt.h" + + +static int write_file(const char *path, const char *str) { + int fd = 0; + + if ((fd = open(path, O_WRONLY)) == 0) { + fprintf(stderr, "unable to open %s\n", path); + return 1; + } + + if (write(fd, str, strlen(str)) < 1) { + fprintf(stderr, "unable to write to %s\n", path); + close(fd); + return 1; + } + + close(fd); + return 0; +} + +/* Register a sysfs GPIO pin to be interruptable + similar to: + $ echo 12 > /sys/class/gpio/export + $ echo both > /sys/class/gpio12/edge + $ echo in > /sys/class/gpio12/direction + +*/ +int int_register(int pin) { + + char path[1024]; + char buffer[64]; + + /* begin by unregistering supplied pin, just in case */ + (void) int_unregister(pin); + + memset(buffer, 0, 64); + sprintf(buffer, "%d", pin); + if (write_file("/sys/class/gpio/export", buffer) != 0) { + return 1; + } + + /* sleep 500 ms to let linux set up the dir .. */ + usleep(500000); + + memset(path, 0, 1024); + sprintf(path, "%s%d/%s", "/sys/class/gpio/gpio", pin, "edge"); + if (write_file(path, "both") != 0) { + return 1; + } + + memset(path, 0, 1024); + sprintf(path, "%s%d/%s", "/sys/class/gpio/gpio", pin, "direction"); + if (write_file(path, "in") != 0) { + return 1; + } + + + return 0; +} + +/* unregister an interrupt gpio config + similar to: + $ echo 12 > /sys/class/gpio/unexport +*/ +int int_unregister(int pin) { + char buffer[64]; + + memset(buffer, 0, 64); + sprintf(buffer, "%d", pin); + if (write_file("/sys/class/gpio/unexport", buffer) != 0) { + return 1; + } + + return 0; +} + +/* poll a gpio pin for interrupt event + blocking +*/ +int int_poll(int pin) { + int fd; + struct pollfd pfd; + char path[1024]; + char buf[16]; + + memset(path, 0, 1024); + sprintf(path, "%s%d/%s", "/sys/class/gpio/gpio", pin, "value"); + + if ((fd = open(path, O_RDONLY)) == 0) { + fprintf(stderr, "unable to open %s\n", path); + return 1; + } + + pfd.fd = fd; + pfd.events = POLLPRI | POLLERR; + + lseek(fd, 0, SEEK_SET); + read(fd, buf, sizeof buf); + + poll(&pfd, 1, -1); + + lseek(fd, 0, SEEK_SET); + read(fd, buf, sizeof buf); + + return 0; +} diff --git a/interrupt.h b/interrupt.h new file mode 100644 index 0000000..70da9dc --- /dev/null +++ b/interrupt.h @@ -0,0 +1,11 @@ +#ifndef INTERRUPT_H +#define INTERRUPT_H + +/* + Note: `pin' is GPIO No. +*/ +int int_register(int pin); +int int_unregister(int pin); +int int_poll(int pin); + +#endif \ No newline at end of file diff --git a/main.c b/main.c index 4802e92..7a0da58 100644 --- a/main.c +++ b/main.c @@ -4,8 +4,11 @@ #include <unistd.h> #include <math.h> #include "lis3dh.h" +#include "interrupt.h" #include "i2c.h" +#define GPIO_INTERRUPT_PIN 12 + /* calc magnitude of accel [x y z] vector */ float mag(float x, float y, float z) { return sqrt( powf(x, 2) + powf(y, 2) + powf(z, 2) ); @@ -14,6 +17,7 @@ float mag(float x, float y, float z) { /* print message then exit */ void quit(const char *msg, lis3dh_t *lis) { lis->dev.deinit(); + int_unregister(GPIO_INTERRUPT_PIN); fprintf(stderr, "%s\n", msg); exit(1); } @@ -22,7 +26,7 @@ int main() { lis3dh_t lis; struct lis3dh_fifo_data fifo; - int i, k; + int k; /* set fn ptrs to rw on bus (i2c or SPI) */ lis.dev.init = i2c_init; @@ -37,34 +41,44 @@ int main() { quit("init()", &lis); } + /* register interrupt */ + if (int_register(GPIO_INTERRUPT_PIN)) { + quit("int_register()", &lis); + } + /* set up config */ lis.cfg.mode = LIS3DH_MODE_NORMAL; lis.cfg.range = LIS3DH_FS_2G; lis.cfg.rate = LIS3DH_ODR_100_HZ; lis.cfg.fifo.mode = LIS3DH_FIFO_MODE_STREAM; + lis.cfg.fifo.trig = LIS3DH_FIFO_TRIG_INT1; + lis.cfg.pin1.overrun = 1; + /* write device config */ if (lis3dh_configure(&lis)) { quit("configure()", &lis); } - - for (i=0; i<100; i++) { - /* poll fifo reg */ - if (lis3dh_poll_fifo(&lis)) { - quit("poll_fifo()", &lis); - } + /* wait for interrupt from LIS3DH */ + if (int_poll(GPIO_INTERRUPT_PIN)) { + quit("int_poll()", &lis); + } - /* read stored fifo data into `fifo' struct */ - if (lis3dh_read_fifo(&lis, &fifo)) { - quit("read_fifo()", &lis); - } + /* read stored fifo data into `fifo' struct */ + if (lis3dh_read_fifo(&lis, &fifo)) { + quit("read_fifo()", &lis); + } - for(k=0; k<fifo.size; k++) { - printf("%04.04f %04.04f %04.04f %04.04f\n", - fifo.x[k], fifo.y[k], fifo.z[k], - mag(fifo.x[k], fifo.y[k], fifo.z[k])); - } + for(k=0; k<fifo.size; k++) { + printf("%04.04f %04.04f %04.04f %04.04f\n", + fifo.x[k], fifo.y[k], fifo.z[k], + mag(fifo.x[k], fifo.y[k], fifo.z[k])); + } + + /* unregister interrupt */ + if (int_unregister(GPIO_INTERRUPT_PIN)) { + quit("int_unregister()", &lis); } /* deinitalise struct */