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

Re: Reading GPIO input triggered by IRQ

Wed Oct 28, 2015 9:41 pm

davenull wrote:now are there encoder libs for pigpio providing quick IRQ-triggered pin reading?
(100µs for timer IRQs should fit actually, for pinchange interrupts perhaps quicker)
There is example code at http://abyz.co.uk/rpi/pigpio/examples.html

Note, these are examples, and are intended to show methods, not to be complete solutions in their own right.

Have you confirmed that the encoder doesn't work with your existing library?

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: Reading GPIO input triggered by IRQ

Thu Oct 29, 2015 8:30 am

thank you very much for this link!
Nevertheless, I don't see how you're doing the pinchang-e or timer-interrupt thing?

gpioDelay(20000); /* check pos 50 times per second */

so for 10,000 times p.sec. it should be

gpioDelay(100); /* check pos each 100µs safely ?? */

To run this in an extra pthread task surely would not perform quickly and safely enough, as it's again jittering in the pthread user space level, interfered by different program tasks and daemons running parallel...

OTOH, wiringPi mimics (or fakes) a pinchange interrupt, apart from delays or tasks/threads in the programming source code (using an own higher-priority task in the background):
wiringPiISR(pin_a,INT_EDGE_BOTH, updateEncoders);
wiringPiISR(pin_b,INT_EDGE_BOTH, updateEncoders);
http://theatticlight.net/posts/Reading- ... pberry-Pi/
https://github.com/astine/rotaryencoder ... yencoder.c

- this is what I actually had expected for the pigpio code, tooo...?
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

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

Re: Reading GPIO input triggered by IRQ

Thu Oct 29, 2015 9:33 am

davenull wrote: ...
Nevertheless, I don't see how you're doing the pinchang-e or timer-interrupt thing?
...
pigpio samples in the background 200 thousand times a second (by default). Level changes are reported by the callback mechanism used by the alert functions. The alert callback will get the gpio, edge, and time of event in microseconds. For fast rotary encoders you should be using the alert callbacks.

pigpio C also has interrupt callbacks but I would only use them when minimum latency is essential. Interrupts will be missed if several happen in rapid succession (probably even at your encoder rates).

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: Reading GPIO input triggered by IRQ

Thu Oct 29, 2015 9:44 am

yes, that's clear, but the pin-polling and encoder-calculating function is not running in the main task allone, but it has to run in a parallel task "in the background".
So even if the GPIOs are polled quickly - for encoder updating the pin readings have to be repeatedly re-calculated in a update-Encoder-function / task

Code: Select all

// do this following calculation for each single motor encoder for each single motor (up to 8 !!)  in real-time
void updateEncoders()
{
    struct encoder *encoder = encoders;
    for (; encoder < encoders + numberofencoders; encoder++)
    {
        int MSB = digitalRead(encoder->pin_a);  
        int LSB = digitalRead(encoder->pin_b);

        int encoded = (MSB << 1) | LSB;
        int sum = (encoder->lastEncoded << 2) | encoded;

        if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoder->value++;
        if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoder->value--;

        encoder->lastEncoded = encoded;
    }
}
or, in Arduino Due code:

Code: Select all

void EncoderHandler() {
 
  ISRab [ 0] <<= 2;
  ISRab [ 0] &= B00001100;
  ISRab [ 0] |= (digitalRead(pinenc0A) << 1) | digitalRead(pinenc0B);
  motenc[ 0] += schrittTab[ISRab[0]];           //

  ISRab [ 1] <<= 2;
  ISRab [ 1] &= B00001100;
  ISRab [ 1] |= (digitalRead(pinenc1A) << 1) | digitalRead(pinenc1B);
  motenc[ 1] += schrittTab[ISRab[1]];           //

  ISRab [ 2] <<= 2;
  ISRab [ 2] &= B00001100;
  ISRab [ 2] |= (digitalRead(pinenc2A) << 1) | digitalRead(pinenc2B);
  motenc[ 2] += schrittTab[ISRab[2]];           //

  ISRab [ 3] <<= 2;
  ISRab [ 3] &= B00001100;
  ISRab [ 3] |= (digitalRead(pinenc3A) << 1) | digitalRead(pinenc3B);
  motenc[ 3] += schrittTab[ISRab[3]];           //

  ISRab [ 4] <<= 2;
  ISRab [ 4] &= B00001100;
  ISRab [ 4] |= (digitalRead(pinenc4A) << 1) | digitalRead(pinenc4B);
  motenc[ 4] += schrittTab[ISRab[4]];           //

  ISRab [ 5] <<= 2;
  ISRab [ 5] &= B00001100;
  ISRab [ 5] |= (digitalRead(pinenc5A) << 1) | digitalRead(pinenc5B);
  motenc[ 5] += schrittTab[ISRab[5]];           //

 
}
so not the pin-reading itself is the limiting task, but the repeatedly, quickly, uninterrupted, uninterferred performed calculation of the pin readings by those BIT-shifted or AND-ed or OR-ed patterns to get the encoder positions updated.
Do you see the difference?
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

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

Re: Reading GPIO input triggered by IRQ

Thu Oct 29, 2015 1:13 pm

davenull wrote: ...
Do you see the difference?
I suppose so, but I would never do a digitalRead within an ISR. The pin state may easily have changed by the time the ISR has triggered.

You should be maintaining the GPIO levels from the event callbacks you have received. The events will be received in time order.

davenull
Posts: 1159
Joined: Thu Oct 22, 2015 7:22 am
Location: a small planet close to Betelgeuze

Re: Reading GPIO input triggered by IRQ

Thu Oct 29, 2015 2:09 pm

ok, but even if I'll do so then the calculating encoder update task will be faulty when the moment when it's been triggered is not regularly within quite/rather exactly always each 100µs.
Finally, what would exactly updated pin states help, if the processing of it's values is shaky and jittering?

What actually would be needed is a timer or pinchange interrupt, which triggers all the stuff, i.e. polling the pin states and processing the data immediately to an updated encoder result.

How can this be fixed by pigpio API functions?
#define S sqrt(t+2*i*i)<2
#define F(a,b) for(a=0;a<b;++a)
float x,y,r,i,s,j,t,n;int main(){F(y,64){F(x,99){r=i=t=0;s=x/33-2;j=y/32-1;F(n,50&S){t=r*r-i*i;i=2*r*i+j;r=t+s;}if(S){PointOut(x,y);}}}for(;;);}

Return to “C/C++”