Any help would be appreciated. I’ve Googled, studied, and stared for many hours.
Problem: Using poll to watch a GPIO pin for change, poll returns “immediately” and persistently, with no value change, with POLLPRI set.
Background: This is a prep stage for implementing a software encoder counter where 2 GPIOs are connected to an external rotary encoder with leads A and B. I am working on a user space quadrature encoder routine based on the Linux driver rotary_encoder.c logic. It didn’t work and I traced it to failing to respond to the GPIO edge events using poll. I made a single GPIO interrupt response demonstrator (shown excerpted below) and it doesn’t work either. Further, it doesn’t work on either Beaglebone Blue or Raspberry Pi 3.
Hardware: The Blue shows ’ uname -a
Linux blue1 4.19.94-ti-r42 #1buster SMP PREEMPT Tue Mar 31 19:38:29 UTC 2020 armv7l GNU/Linux’
The RPi shows ’ uname -a
Linux raspberrypi 4.19.93-v7+ #1290 SMP Fri Jan 10 16:39:50 GMT 2020 armv7l GNU/Linux’
Both have the same wheel encoders (Pololu Romi encoders item #3542 or its 2.7v version). Both bots will correctly read the encoders. The Blue using the hardware encoder and the RPi via the software driver rotary-encoder. For this demonstrator, the Blue uses other GPIOs, specifically GP0.3 and GP0.4. Signal changes on these GPIOs are read correctly in the gpioN/value register via manual testing. The RPi uses the same GPIOs (2 or 3) as the encoder driver, but with the driver disabled to eliminate the competition.
Furthermore: This has been a long standing software challenge. Googling shows many things one needs to know. GPIOs in sysFS are deprecated, but they still work. Setting an edge is what enables polling on the value to pick up the transition. Initial reads are required to clear initial spurious values. sysFS requires POLLPRI events, since POLLIN always returns for sysFS. sysFS always returns POLLERR which can be ignored. One must LSEEK on the value fd before reading the value. One must read the value, wanted or not.
Notes on the demonstrator code: I have been working on a common hardware interface module to support bots built on Blue and RPi. I have long been following StrawsonDesign’s librobotcontrol. This code uses a few routines from Strawson. One is a function to tell whether the hardware is Beaglebone or RPI and another to launch a thread. I don’t show them here. I have elided all the error handling snippets, replacing them with “gripe” comments.
The program follows the StrawsonDesign librobotcontrol rc_test examples. In this case, the main checks inputs, sets up hardware, launches a worker thread, then waits for the user to quit via Ctrl-C. Here the worker thread sets up a repeated poll loop. In the eventual quadrature application, the GPIO events feed the quadrature state machine of rotary-encoder.c. A short timeout is set for my use so the thread can be readily killed by the main application, independent of GPIO arrivals. The version here leaves the GPIOs set up upon completion so we can inspect the state of things. The Blue has pinmux helpers for the user GPIOs on GP0 and GP1 which are used to set them to GPIO mode. The RPi doesn’t do that. Apparently user GPIOS are pre-set up.
The code produces the same result on both machines. The read after poll always fails with return -1. The event is 0x0a which is POLLPRI | POLLERR. While it does stream fast, I can never see a response to manually fiddling with the physical inputs. It never reports time out.
OBTW, if you can see into what is going on here, think about how this works when I switch to SCHED_FIFO. All my bot threads run in this ‘realtime’ mode. For a software encoder that responds to GPIO interrupts, I think this doesn’t present any problem that isn’t already presented by all the other threads. On RPi, tho, the kernel catches the GPIO interrupts and runs the quadrature logic, only letting the user’s poll get control after a complete turn of +1 or -1 occurs. I presume the rotary-encoder driver runs at kernel priority level, which is below the worker thread. At least, if my app consumes too much CPU, the kernel can’t keep with its many functions, one of which is this driver. I have done that in the past. Let’s get this code to work, then I’d like help thinking through this and its impact on CPUs like Blue and RPi. Because I’m getting lots of input about the CPU load of a software rotary encoder.
So, needless to say, I don’t get it. I hope someone can see what I’m missing. I need to get past this and get back to making bots go.
- @excerpts from my_test_gpio_interrupts.c
- as of 19 June 2020