arkaik
Posts: 23
Joined: Mon Mar 20, 2017 3:42 pm

[POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Mon May 29, 2017 1:37 pm

Hi everyone,

I would like to know if there is a way to have a thread launched on GPIO interrupt but with real-time scheduling.

With pigpio API you can trigger an interrupt and pass parameters to the callback with

Code: Select all

int gpioSetISRFuncEx(unsigned gpio, unsigned edge, int timeout, gpioISRFuncEx_t f, void *userdata)
With POSIX it's also possible to configure thread priority between 0 and 99 with either FIFO or RR scheduling.

Is there a way to combine both behaviour and have the ISR callback at 99 priority with Round Robin scheduling for example?

If not how could I trigger the interrupt on GPIO pin by myself to launch the priorized thread?

Thanks for your answers ;)

arkaik
Posts: 23
Joined: Mon Mar 20, 2017 3:42 pm

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Tue May 30, 2017 4:03 pm

Hi guys,

I found that with the bcm2835 library it's possible to do what I want with functions like

Code: Select all

bcm2835_gpio_afen
However I tried this library to communicate through I2C but it seems to have this function missing

Code: Select all

uint8_t bcm2835_i2c_write_read_rs 	( 	char *  	cmds,
		uint32_t  	cmds_len,
		char *  	buf,
		uint32_t  	buf_len 
	) 	


I'm using the last version (1.52) but the documentation on the author's website seems to be outdated as function prototypes don't match with what I have in my bcm2835.h header.

For example on the website there is

Code: Select all

int bcm2835_i2c_begin(void)
but in my header there is

Code: Select all

void bcm2835_i2c_begin(void)
instead.

This lib seems to be awesome but without bcm2835_i2c_write_read_rs I can't write to a specified register.

Do you know if the lib is still under maintenance? The last release is from 2017-02-03 so I think it is but it's strange that website's documentation do not match with last release.

Thanks.

User avatar
joan
Posts: 13579
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Tue May 30, 2017 6:56 pm

Why don't you just make the thread which sets up the callback a RT thread. That is completely within your control.

arkaik
Posts: 23
Joined: Mon Mar 20, 2017 3:42 pm

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Wed May 31, 2017 7:38 am

Hi @joan,
I could but I would like to have my callback priorized comparing to its parent so I dont want the thread to just inherit its priority from the main thread.

What about the bcm2835 functions?

YCN-
Posts: 246
Joined: Fri Jun 10, 2016 3:18 pm

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Wed May 31, 2017 7:56 am

Hi,

Why don't you use classic POSIX scheduling ? I don't see why you want to do that within a library?

BTW I'm always wondering why this kind of libraries try to hide the POSIX stuff. It doesn't make it simpler and newbies will never learn how stuff works.

YCN-

arkaik
Posts: 23
Joined: Mon Mar 20, 2017 3:42 pm

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Wed May 31, 2017 3:15 pm

Hi @YCN,

I do want to use POSIX scheduling ^^.

About I2C, I don't need anything else than basic I2C implementation, so a library is both easier and faster to implement than developping my own one.

About threading and real-time it's something else, I want to be able to set priority and scheduling precisely.
I'm beginning with posix implementation and I'm ok with scheduling but I don't really know how to interact with environment and GPIO.

I was thinking about something like this. I don't add the error handling for easier reading.

Code: Select all

int main(int argc, char **argv)
{
    pthread_attr_t attr;
    struct sched_param param;
    pthread_t thread;

    bcm2835_init();
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
    bcm2835_gpio_aren(PIN);

    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

    param.sched_priority = 99;
    pthread_attr_setschedparam(&attr, &param);
    
    while (1)
    {
        if (bcm2835_gpio_eds(PIN))
        {
            bcm2835_gpio_set_eds(PIN);
            pthread_create(&thread, &attr, callback_acq, NULL);
        }
    }
    bcm2835_close();
    return 0;
}
My point is I would like to use an already-made i2c library because I really don't want to have to develop all the i2c communication by myself, I think you can understand ;)

About this kind of library I don't really agree with you, those libs exist to simplify programming for newbies as you said. Few years ago I was really happy to be able to communicate with devices without understanding how it works ^^.
When newbies got sufficient skills they can go further by themself but if those kinds of libs wouldn't exist, a lot of people would abandon in front of the complexity of the thing. But that's just my opinion ;)

User avatar
[email protected]
Posts: 1984
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Thu Jun 01, 2017 4:24 pm

Maybe have a look at how the wiringPiISR code works?

(and copy/adapt it for your own needs?)

Or just use it.

Along with the I2C helpers - I2C is built into the Linker kernel - almost always no need to write your own.

What is it that you are actually trying to do?

-Gordon
--
Gordons projects: https://projects.drogon.net/

arkaik
Posts: 23
Joined: Mon Mar 20, 2017 3:42 pm

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Fri Jun 02, 2017 11:57 am

Hi gordon,

I was basically using your library which is a really good, but I needed to give arguments to my callback and wiringPi didn't allow it from what I had seen.

I took a look at your source files and I was not aware that programing i2c was that easy (at least it seems easy when you have source code on your screen ^^). Thanks to it, I understand better how I can interract with peripherals.

Concerning wiringPiISR I saw that you are using pthread so I think I'll try to implement an extended function which allows to pass parameters to my callback and to define its priority and scheduling; and why not its affinity after all ^^

I'll come back to tell you if I suceeded ;)

Edit :

So I tried to build a modified version of your lib by compiling with ./build. The build succeded but after pasting the library on my computer and compiling it, my new function wiringPiISR is not found by the linker.
I checked the symbols table for libwiringPi.so and there is no flag for this function, did I missed something?

What I did:
1) Copy the already built wiringPi lib from my computer to my Rpi
2) Modify wiringPi.c and wiringPi.h to add my function in
3) Build the modified lib
4) Paste it on my computer
5) Try to compile with Makefile as always but using the modified library instead of the regular one.

The function I added to wiringPi.c

Code: Select all

int wiringPiISREx (int pin, int mode, void (*function)(void), void *arg, int priority, int policy)
{
  pthread_t threadId ;
  const char *modeS ;
  char fName   [64] ;
  char  pinS [8] ;
  pid_t pid ;
  int   count, i ;
  char  c ;
  int   bcmGpioPin ;
  pthread_attr_t attr;
  struct sched_param param;
  int err;

  if ((pin < 0) || (pin > 63))
    return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-63 (%d)\n", pin) ;

  /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED)
    return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ;
  else if (wiringPiMode == WPI_MODE_PINS)
    bcmGpioPin = pinToGpio [pin] ;
  else if (wiringPiMode == WPI_MODE_PHYS)
    bcmGpioPin = physToGpio [pin] ;
  else
    bcmGpioPin = pin ;

// Now export the pin and set the right edge
//	We're going to use the gpio program to do this, so it assumes
//	a full installation of wiringPi. It's a bit 'clunky', but it
//	is a way that will work when we're running in "Sys" mode, as
//	a non-root user. (without sudo)

  if (mode != INT_EDGE_SETUP)
  {
    /**/ if (mode == INT_EDGE_FALLING)
      modeS = "falling" ;
    else if (mode == INT_EDGE_RISING)
      modeS = "rising" ;
    else
      modeS = "both" ;

    sprintf (pinS, "%d", bcmGpioPin) ;

    if ((pid = fork ()) < 0)	// Fail
      return wiringPiFailure (WPI_FATAL, "wiringPiISR: fork failed: %s\n", strerror (errno)) ;

    if (pid == 0)	// Child, exec
    {
      /**/ if (access ("/usr/local/bin/gpio", X_OK) == 0)
      {
	execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
	return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
      }
      else if (access ("/usr/bin/gpio", X_OK) == 0)
      {
	execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
	return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
      }
      else
	return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ;
    }
    else		// Parent, wait
      wait (NULL) ;
  }

// Now pre-open the /sys/class node - but it may already be open if
//	we are in Sys mode...

  if (sysFds [bcmGpioPin] == -1)
  {
    sprintf (fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin) ;
    if ((sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0)
      return wiringPiFailure (WPI_FATAL, "wiringPiISR: unable to open %s: %s\n", fName, strerror (errno)) ;
  }

// Clear any initial pending interrupt

  ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ;
  for (i = 0 ; i < count ; ++i)
    read (sysFds [bcmGpioPin], &c, 1) ;

  isrFunctions [pin] = function ;

// Prepare pthread attributes
  
    pthread_attr_init(&attr);
    
    if((err = pthread_attr_setschedpolicy(&attr, policy)) != 0)
    {
    	fprintf(stderr, "setschedpolicy: %s\n", strerror(err));
    	exit(EXIT_FAILURE);
    }
    
    if((err = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0)
    {
    	fprintf(stderr, "setinheritsched: %s\n", strerror(err));
    	exit(EXIT_FAILURE);
    }

    param.sched_priority = priority;
    if((err = pthread_attr_setschedparam(&attr, &param)) != 0)
    {
    	fprintf(stderr, "setschedparam: %s\n", strerror(err));
    	exit(EXIT_FAILURE);
    }

  pthread_mutex_lock (&pinMutex) ;
    pinPass = pin ;
    pthread_create (&threadId, &attr, interruptHandler, arg) ;
    while (pinPass != -1)
      delay (1) ;
  pthread_mutex_unlock (&pinMutex) ;

  return 0 ;
}
The ./build output

Code: Select all

[email protected]:~/wiringPiEx $ ./build 
wiringPi Build script
=====================


WiringPi Library
[UnInstall]
[Compile] wiringPi.c
[Compile] wiringSerial.c
[Compile] wiringShift.c
[Compile] piThread.c
[Compile] piHiPri.c
[Compile] wiringPiI2C.c
[Compile] softPwm.c
[Compile] mcp23008.c
[Compile] mcp23016.c
[Compile] mcp23017.c
[Compile] mcp23s08.c
[Compile] sr595.c
wiringPi.c:1247:21: warning: ‘digitalRead8Dummy’ defined but not used [-Wunused-function]
 static unsigned int digitalRead8Dummy        (UNU struct wiringPiNodeStruct *node, UNU int UNU pin)            { return 0 ; }
                     ^
wiringPi.c:1248:21: warning: ‘digitalWrite8Dummy’ defined but not used [-Wunused-function]
 static         void digitalWrite8Dummy       (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
                     ^
[Compile] pcf8574.c
[Compile] pcf8591.c
[Compile] mcp3002.c
[Compile] mcp3004.c
[Compile] mcp4802.c
[Compile] mcp3422.c
[Compile] ads1115.c
[Compile] sn3218.c
[Compile] bmp180.c
[Compile] htu21d.c
[Compile] ds18b20.c
[Compile] rht03.c
[Compile] drcNet.c
[Compile] pseudoPins.c
[Compile] wpiExtensions.c
[Link (Dynamic)]
[Install Headers]
[Install Dynamic Lib]

WiringPi Devices Library
[UnInstall]
[Compile] maxdetect.c
[Compile] lcd128x64.c
[Compile] scrollPhat.c
[Compile] lcd.c
[Link (Dynamic)]
[Install Headers]
[Install Dynamic Lib]

GPIO Utility
[Compile] gpio.c
[Compile] readall.c
[Compile] pins.c
[Link]
[Install]

All Done.

NOTE: To compile programs with wiringPi, you need to add:
    -lwiringPi
  to your compile line(s) To use the Gertboard, MaxDetect, etc.
  code (the devLib), you need to also add:
    -lwiringPiDev
  to your compile line(s).
The return of objdump

Code: Select all

[email protected]:~/cross-tools$ objdump -t wiringPiEx/wiringPi/libwiringPi.so | grep ISR
000046a8 g     F .text	000003c0              wiringPiISR
Edit 2 :

Finally I started again from a fresh clone and everything compiled fine :D apparently shared libraries are not compiled again if the repository was already built.

However the callback is never called on rising edge which is quite strange because I didn't modify anything except for pthread_create and when I use it outside the library it works fine ^^.

I will investigate around to see what's not working.

Thanks a lot for your great advices. I'll come back to tell you how it evolves ;)

DaanNL
Posts: 1
Joined: Fri Aug 11, 2017 12:56 pm

Re: [POSIX-PIGPIO] Real-time thread on GPIO interrupt?

Fri Aug 11, 2017 12:58 pm

Did you ever find a good solution for using realtime on rpi using pigpio? i'm currently porting the homeduino library for pimatic to pigpio.... I want to be able to capture images from camera's and use pimatic on the same rpi... whenever i start the v4l capture thread with sched_idle and the homeduinolibrary with sched_fifo it never receives any interrupts.

Return to “C/C++”