Use a standard GPIO as Interrupt

By | 28. January 2014

Hi there, during one of my last projects I faced the problem, that I needed several GPIO Pins that support interrupts. Sadly, the sockets of the Gadgeteer Boards each only provide one interrupt. This means to access five interrupt pins I would need to use five sockets – which is not acceptable.

Goal

Let’s implement some logic to use a normal GPIO pin and add the interrupt capabilities on the software side. I’m going to call this the “VirtualInterrupt”. My plan is to develop a class that consumes a normal “DigitalInput” and extends it with an event called “Interrupt” that is fired if the state of the input changes from false to true and the other way around. Of course this will have one drawback because it’s only software – we can’t support the “ResistorMode” of a classic interrupt pin. This feature you will have to build by yourself, if you need it. Internally we’re going to use a polling mechanism to track the changes of the GPIO pin.

Implementation

public VirtualInterupt(DigitalInput digitalInput, int pollRate)
{
    if (digitalInput == null)
    {
        throw new ArgumentException("Digital input can't be null.", "digitalInput");
    }

    if (pollRate <= 0)
    {
        throw new ArgumentException("Polling rate must be greater than zero.", "pollRate");
    }

    this.digitalInput = digitalInput;
    this.inputState = digitalInput.Read();
    this.pollingTimer = new Timer(pollRate);
    this.pollingTimer.Tick += this.Tick;
    this.pollingTimer.Start();
}

The constructor needs two arguments, the digital input which gets extended with the interrupt event and a polling interval in milliseconds. The second argument determines the timespan between the state checks of the pin. Firstly, the pin state is queried as status quo, then we’re starting the timer which will fire an event every time the polling interval is reached. Then the pin state is queried and the result will be compared to the last pin state.

public delegate void InteruptEventHandler(object sender, bool state);
public event InteruptEventHandler Interupt;

Like the genuine interrupt pin, our virtual one needs an event that is fired as soon as the pin state switches to true or false. For this reason the class has the above delegate and event to communicate the state change to all observers.

private void Tick(Timer timer)
{
    bool current = this.digitalInput.Read();

    if (current != this.inputState)
    {
        this.Interupt(this, current);  
        this.inputState = current;
    }
}

The main sequence of our class is the Tick event of the timer. With every we read the state of the pin and compare it to the last state. If the states are the same nothing happens, only if the states differ the event is fired. Of course let’s not forget to save the current state as the last state for the next comparison.

Finalizing

With that we’re done! If needed we could make one more tweak: Add another argument to the constructor which will determine if every state change is reported, only state changed to true or only changes to false. This is usually called “FallingEdge” (Change from true to false) or “RisingEdge” (false to true). For my projects this wasn’t necessary, so I didn’t implement it and left it as a little exercise for you.

Leave a Reply