GPIO input in C++ raspberry pi zero W

Hello,

I’m using the library on an rpi zero w running dietpi and a custom c++ code to display an animated gif on a matrix. I advance the display to the next animated image in a folder using a physical button connected to one of my free gpio pins. I’ve got the code working properly, but currently I’m just polling the AwaitInputChange() as frequently as I can to try and catch the button press. Is there some way that I can use this function as a system interrupt, similar to how one sets up ctrl+c to set a flag that will exit the program with the sigterm? I’m definitely a basic c++ user so I apologize if this is something rudimentary. I’d love to learn some better ways to handle this from those with more experience though!

I don’t see anything wrong with this. Interrupts are typically used where a quick response to an event is important, and a user pressing a button obviously doesn’t fall into that category.
Using an interrupt to handle a button will cause debouncing problems, which isn’t exactly easy to handle in an interrupt.
In my opinion, polling is exactly what’s best for a button.

Hmm, okay that’s a good point. I guess I was just concerned I was slowing down the animation by polling the button. Thanks for the input!

FWIW, I do a similar thing, but I use C#

If you are new to coding (Or C++), C# may be a bit easier to work with? In C#, I don’t have to mess with interrupts, I just use a library to subscribe to buttons, and an event is fired when I press one of them.

My project plays from a playlist on a loop, and have 4 buttons that can interrupt the normal playlist, play something, and then resume the playlist afterwards.

It has a full UI that is served on a web interface (To be used on a phone)

My repo is here: GitHub - evilC/WearWare: An application to drive a LED matrix t-shirt using a Raspberry Pi, controllable via a web interface · GitHub maybe you could find some useful stuff in there.

IDK tho, it’s probably too heavyweight for a zero W, I used to use a zero 2W but upgraded to a 4B because it could not deliver a high enough framerate. Maybe without all the web ui stuff (And in C++) it will be OK for you tho, but to be fair, all my C# code does is call the C++ API to handle playback

Oh wow, thank you. That looks like a great project. I’ll take a look and even if it doesn’t work for the zero, I’m sure there’s plenty that I can learn from reading through the code. I appreciate it! The web interface is a very slick idea. Probably too heavy for this application but maybe for a future implementation.

For what it’s worth, I managed to get things working relatively well. Thanks for all the input. I ended up diving into and learning about threading processes and the internal Linux scheduler. In case it helps anyone in the future, here is my code as it stands now. No interrupts, just regular polling of the buttons in a separate low-priority thread. Pressing the buttons feels like there is an instantaneous response from the program, so that’s a win in my book.

Maybe I’ve misunderstood the question… but a way to create a system interrupt is to use the gpiod library (libgpiod) which replaces the gpio library

Something like

#include <gpiod.hpp>
#include
#include

int main(void) {
// Define the GPIO pin number (BCM numbering)
const std::string consumer = “gpio_interrupt_handler”;
unsigned int pin_num = 17;

try {
    // Open the GPIO chip
    gpiod::chip chip("0");

    // Get the specific line (pin) from the chip
    gpiod::line line = chip.get_line(pin_num);

    // Request the line to listen for falling edge events (high-to-low transition)
    // This sets up the internal kernel interrupt for the pin
    line.request({
        consumer,
        gpiod::line_request::EVENT_FALLING_EDGE,
        0 // Default flags (no active-low or pull-up/pull-down overrides)
    });

    std::cout << "Listening for hardware interrupts on GPIO " << pin_num << "..." << std::endl;

    // Loop waiting for hardware interrupt events
    while (true) {
        // Block and wait for an event (timeout after 5 seconds to keep the loop alive)
        if (line.event_wait(std::chrono::seconds(5))) {
            // Read the event from the kernel buffer
            gpiod::line_event event = line.event_read();

            if (event.event_type == gpiod::line_event::FALLING_EDGE) {
                std::cout << "Interrupt detected! GPIO " << pin_num << " changed state to LOW." << std::endl;
                
                // interrupt handler logic here
            }
        } else {
            std::cout << "Waiting for event (timeout)..." << std::endl;
        }
    }
} 
catch (const std::exception& e) {
    std::cerr << "Exception encountered: " << e.what() << std::endl;
    return 1;
}

return 0;

}

Thanks jonms. That’s very helpful and I did look at the libgpiod as well as the pigpio libraries. Neither seemed to work once I incorporated the libraries and code for the matrix and it was my understanding that this library takes control of the gpio pins at a low level and doesn’t allow interaction with them through other means. That’s what led me here, to see if there was a way to use similar behavior within the confines of this library.

Yes - you have to go with one mechanism or the other.

libgpiod uses an exclusive kernel device drive, so once it takes ownership you can’t access the GPIO pins by other means. Same goes for lgpio (replacement for the defunct pigpio).

Reason for this is to prevent race-conditions.

Thinking aloud - perhaps use a system() call to access gpioget. That would put a lock on the pin and prevent contention. The pin would be released as soon as gpioget completes.

If there are pins which the matrix library doesn’t use then you could dedicate those to your button-press detector. The button-press-detector sends another pin high whenever a press is detected… a jumper to connect that ‘signal pin’ to a pin in the range the rgb-matrix uses would allow the signal to be read.

Finally… and this may be a thing… IIRC you can set a parameter in firmware/config.txt to turn a gpio-pin into a filesystem object. This would effectively turn a button press into something like a key-press on the keyboard. Have a google on that… the more I think about it, the more I recall that being a possibility.

Hope that helps!