Counting events

I want to use a hall effect motor encoder to determine the number of revolutions of a wheel. Using the BB-KEYS I am able to set up /dev/inputs/event1 that captures the event and records the number of interrupts in /proc/interrupts. I believe setting /sys/class/gpio/gpioxx/edge will do pretty much the same. I haven’t been able to figure out how to count them in a C/C++ code. Is it bes to set up an interrupt and count or try to read the /proc/interrupt file? Polling is not an option because there are two wheel that need to be counted. I would prefer to have and ISR that counts each time it is triggered, but I have not been able to figure out how to set it up. Any help would be greatly appreciated since I have spent the last few days trying to research this without much luck.

Thanks,
Dorian

I need to do something similar counting pulses generated by a hall effect sensor in a flow meter.
Haven’t started looking at it yet, if you solve this please post back to the thread.

Dorian,

I haven’t tried any of these myself but I see no reason why they shouldn’t work.

  • you could use a fork to create a child process. In this child process use the poll()/select() calls to detect a change in the edge file. When this happens a variable could be incremented and piped back to the parent process.
  • You could use threads…i.e. a thread calls poll()/select() to detect a change in the edge file and then updates a counts variables…with threads all threads share the variables so this will be easier. but could be more convoluted…
  • You could try monitoring the edge file with GDK/GTK libs monitoring I/O calls https://developer.gnome.org/gtk-tutorial/2.90/x1770.html. Qt has a QIODevice class that does the same thing.
  • You could also attach the SIGIO signal to the file descriptor for the edge file and write a signal handler that increments a variable…though Linux purists do not recommend this
    Hussam

Something like SIGIO is what I was trying to do. I was trying signal(SIGINT, IRQHandler), but something is not right. How do I attach it, and why do Linux enthusiasts not recommend this?

Dorian, here’s a little example. First open the file and get a file descriptor, then use FCNTL with SETOWN command to send SIGIO to current process. Use fcntl to set the FASYNC flag then populate the signal structure. This code was not tested but hopefully should give you an idea as to what to do…

int counter = 0;

int main(){
struct sigaction saio;
int fd ;
fd = open("/sys/class/blahblah/edge",O_RDWR | O_NONBLOCK); // open file descriptor for the edge

/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);

/* allow the process to receive SIGIO /
fcntl(fd, F_SETOWN, getpid());
/
Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL…) */
fcntl(fd, F_SETFL, FASYNC);

}

void signal_handler_IO (int status)
{
counter++;

}

Linux purists generally don’t like using signals,too many can cause many conflicts/race conditions that are hard to debug. http://ajaxxx.livejournal.com/62378.html

most of the above code was taken from this link that has code for SIGIO asynchronous serial port access:
http://www.tldp.org/HOWTO/pdf/Serial-Programming-HOWTO.pdf

For more on signals in general
http://beej.us/guide/bgipc/
http://ph7spot.com/musings/introduction-to-unix-signals-and-system-calls
http://www.linuxprogrammingblog.com/all-about-linux-signals?page=1

For more on fcntl:
http://linux.die.net/man/2/fcntl

There’s also real-time signals. I haven’t heard of those before today. But they seem to have less race conditions issues. I’ll have to read up on them. Unfortunately My Linux Signal Programming fu is very limited. I recommend that you get yourself a good text reference on Linux System Programming as well. It will help.

Regards,

Hussam

Thanks a lot Hussam!

I could not get it working using the /sys/class/gpio/gpioxx/edge. Maybe /sys/class/gpioxx/value would work? But by modifying the sample device tree overlay from www.hipstercircuits.com and /dev/input/event1. I was able to get it going using the following code.

#include <stdio.h>
#include <stddef.h>
#include <time.h>
#include
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
using namespace std;

volatile int counter = 0;

void IRQHandler(int sig){

counter ++;
cout << counter;

}

int main(void){
struct sigaction saio;
int fd1;
fd1 = open("/dev/input/event1", O_RDWR|O_NONBLOCK);
saio.sa_handler = IRQHandler;
//saio.sa_mask = 0;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
fcntl(fd1, F_SETOWN, getpid());
fcntl(fd1, F_SETFL, FASYNC);
while(1){

}

}