Solved RP continuous GPIO pin reading (polling)

Nicola Mingotti

Well-Known Member

Reaction score: 200
Messages: 494

step 3. Simple polling with a shell script

Code:
------ poll1.sh --------------
# We read continuously pin P9.23 for one minute
# $> timeout 1m ./poll1.sh | tee 1m-out.txt

# Set P9.23 as input pin pull-down
gpioctl -f /dev/gpioc1 -c 17 IN PD

# read continuously pin state
while `true`; do
   out=`gpioctl -f /dev/gpioc1 17`
   echo -n "$out "
done

Now,
1] launch a normal load on your machine, i am compiling Ruby
in my BBB for example.
2] Connect pin P9.21 with P9.23 (i put in the middle a 1KOhm resistor,
you never know)
3] Launch the polling script
timeout 1m ./poll1.sh | tee 1m-out.txt
This will run for a minte.

Considerations:
1] The script does not eat much resources, I am a bit surprised i confess.
2] You can see the script is extremely unreliable, indeed the speed of samplig varies in time ! And also you can see the distribution of "0" and "1" is not simmetric, where the wave is completely simmetric ==> It is not sampling uniformly in time.
3] If you do wc -w 1m-out.txt you count "0" and "1", i get 1476
=> It means the script sampled 1476/60 => ~25 Hz
=> This speed is very very low, and most importantly we saw the sampling is not uniform in time.

TODO.
Final step would be to do the sampler in C starting from obsigna code.
I expect an improvement factor of about x50 - x100.
But I guess the principle remains valid, the sampling will be faster but never homogeneous in time => this is a problem, unsolvable in a non RTOS, AFAIK.

Goodnight ! :)
 

Nicola Mingotti

Well-Known Member

Reaction score: 200
Messages: 494

step 4 (the last). polling in C

Code:
----- polling1.c ----------------------------
#include <stdint.h>
#include <unistd.h>
#include <libgpio.h>
#include <stdio.h>

int main() {
   gpio_handle_t gpio1;
   int state = 0;       // current status of the pin
   int state_old = 0;   // previous status recorded
   int counter = 0;     // counts the state change

   if ((gpio1 = gpio_open(1)) != GPIO_INVALID_HANDLE) {
      gpio_pin_input(gpio1, 17);

      while (1) {
 
    if (gpio_pin_get(gpio1, 17) == GPIO_PIN_LOW) { state = 0; }
    if (gpio_pin_get(gpio1, 17) == GPIO_PIN_HIGH) { state = 1; }

    printf("%i ",state);
    if (state != state_old) {
      state_old = state;
      counter += 1;
      // on change state write a newline, not necessary
      printf("\n");
    }
      }
      gpio_close(gpio1);
   }
   return 0;
}

1] It polls on pin 9.23
2] connect pin 9.21 to 9.23 (as said in step-3)
3] compile (just for completeness)
#> cc polling1.c -o cpoll1 -lgpio
4] put your system under load (again, i start the compile of Ruby port, without install this time)
5] start the polling for 1 minute and record results
timeout 1m ./cpoll1 | tee 1m-out.txt

OBSERVATIONS:
1] The polling eats about 88% cpu
2] The pollling is now quite fast ~ 40 Khz
3] You can see from the screen output the speed of polling is changing
4] If you insepect the file 1m-out.txt you will see some asymmetries
I attach you a big one i found.
4.1] Looking at the picture you see that realatively small blocks of "0", ok, it can happen that block collapses to length zero, in that case you have lost your push button event.

(my) CONCLUSION.
You can still improve and make the code faster, e.g. removing the output to screen or file. But when the system goes under load one should not trust polling (on the main system CPU) 100%.

It was a funnay exploration
bye
 

Attachments

  • cpoll-samples.png
    cpoll-samples.png
    15.1 KB · Views: 243
Top