3

I have an Adafruit 2.8" cap touch display, which has an interrupt pin (IRQ). I tried to use this with my Arduino Nano, but encountered a problem:

When trying to get the touched point from the display during a display triggered interrupt, it would not work because the touch screen is connected via I2C and according to this post, it is not possible to call I2C functions inside an ISR on an Arduino. Therefore the IRQ pin does not make much sense to me, as I would have to poll if the screen is touched inside the main loop.

My question now is: is this a problem specific for the AtMega 328p? I am thinking about getting an ESP32 based board. Would it be possible to get the I2C data inside an ISR on this chip? Or is it just not possible at all?

  • 2
    Use the ISR to set a boolean value. Have the main program read this value, to see if it needs to fetch an update from the display. – Gerben Nov 30 '17 at 10:19
  • @Gerben Though it is possible, I don't see much sense in doing this. I could as well just poll touch.istouched() via I2C directly, so I don't need the IRQ pin at all. – Lehue Nov 30 '17 at 10:21
  • 3
    Using the IRQ is a a bit faster, as touch.istouched() requires I2C communication. – Gerben Nov 30 '17 at 10:26
  • @Gerben as I wrote in the comment to ratchet's answer, what's the point of setting a boolean value in the ISR vs reading the pin in the loop? the only advantage is if the pin can stay high for a very short time, but this is not the case. So instead of calling an ISR to set a bool and then poll the bool in the loop, poll the pin in the loop. – frarugi87 Nov 30 '17 at 10:54
  • @frarugi87 if that's the case, than, with this device, using interrupts doesn't have any benefits. – Gerben Nov 30 '17 at 11:29
9

Here is an analogy for you to help you understand why using the IRQ is a good idea.

Imagine you are at a conference. There's hundreds of you in the audience, and you are in a question and answer session with the person on the stage. Maybe their presentation has just come to the end and they're fielding questions from the audience.

Lots of people have questions, and any member of the audience can raise their hand at any time to ask a question.

Now there's three ways of the presenter handling it.

The first way is your way of using an interrupt and responding to the interrupt within the interrupt handler itself. This is like the presenter stopping what he is saying mid sentence to answer the new question. That's just nasty, and both confusing for the presenter and the audience.

The second way is for the presenter to continue until the current question has finished being answered, then pick someone at random from the sea of hands. While the question is being answered people are getting antsy waving their hands around to get noticed, and there's no guarantee that it will be first come first served. People may then not be paying attention to what is a good answer to an important question because they are fixated on theirs. That's just the same as you polling the interrupt line, or polling the screen directly. If the interrupt line isn't active at the time you poll it you'll miss it.

The third, and best way, is if the presenter sees a hand go up while he's answering a question, and acknowledges that person with an "Ok, I'll come to you next.". Everyone else knows that waving their hand around is pointless, so don't bother - and the next question can be asked immediately after the current question has been answered. Everyone is happy. That's the proper way of handling a system like this - when the interrupt triggers you remember "Ok, I'll come to that interrupt signal in a moment when I'm ready". Then in your loop, when you have the time, you act on the interrupt that you remembered earlier. You get to respond at your speed to a signal that you may otherwise have missed.

So to sum up: using an interrupt to remember that something is pending and then act on that remembered state is how you should use interrupts to manage communication.

  • Great answer! I love to use analogies myself and think I got it now :) – Lehue Nov 30 '17 at 12:02
  • 1
    Well, in the third way there is no guarantee that first come is first served. Moreover it implies that when the presenter is mid sentence he stops, looks at the person with the raised hand, tells "yes, I noticed you, I'll answer you next" and then resumes from mid sentence. In my opinion your third way is applicable only n two cases. First is when "timid people" raise their hand for a brief moment and then lower it. If you are not fast enough to catch it then you may miss it. The second is if there is a very urgent task, and the person needs to be answered in a very quick time. In all the[...] – frarugi87 Nov 30 '17 at 12:56
  • 1
    [...] other cases, IMHO, it is useless to stop the main operations to just notice that something happened; you can check it later. So, to sum up, interrupts are good if 1) the event is so short you may miss it between polls or 2) the event is so important it requires immediate reply. In this case, a human interaction lasts for at least some hundreds of ms, and requires a reply in almost the same time, which is eternity compared to the microcontroller speed. If you cannot guarantee one check every, let's say, 50ms you have problems in responsiveness that you have to solve regardless of ISRs – frarugi87 Nov 30 '17 at 12:59
  • 1
    No analogy is ever perfect, that's why it's an analogy, not a similie. And in general most interrupt signals from peripherals come in 2 types: active until acknowledged, or a brief pulse. The former can be polled, the latter really requires an interrupt handler to catch it and latch it. – Majenko Nov 30 '17 at 13:23
  • exactly .. :D +1 – Mitu Raj Nov 30 '17 at 15:41
4

I started writing this as a comment, but the more I wrote the more I needed space to complete my thoughts, so here it is as answer.

In my opinion, reacting to a user interaction should NOT be put in ISR; consequently the best thing to do is to avoid the interrupt and poll that wire.

IMHO interrupts need to be used in very few cases, and only when the reactivity to a trigger is needed within (tenths of) microseconds. Whenever the latency can become greater than one millisecond it is much better to avoid the interrupt and all its problems, which are (not limited to)

  1. the need for the microcontroller to save the context
  2. interrupting other "tasks", which can be time critical (see for instance the timing in a software serial)
  3. interrupts can happen any time (maybe in the middle of a write to a int variable)
  4. variables shared between an interrupt and "normal" program cannot be optimized (should always be declared volatile)
  5. ISRs must be as short as possible
  6. usually you can't have multiple interrupts (you become blind to other interrupts, or they get delayed until your ISR is completed)

Point 1 delays your actions uselessly.

Point 2 will be a problem when trying to debug some strange problem in your communication or acquisition or software PWM or anything based on precise timing.

Point 4 implies that shared variables will always be read from memory rather than saved in register (and this will slow down your code)

Point 5 and 6 state that you cannot use long communication routines (serial, I2C, SPI, anything) inside the ISR.

These are common to all microcontrollers generally speaking, so my advice is don't use the interrupt, at least not in this case, since reacting to a user interaction is slow (even 50-100ms will not be noticeable). Poll the wire, then when you detect it ask the controller the position.

3

The better way to do it would be to set a volatile flag in the ISR and handle that in the main loop.

This relies on you making sure the main loop never blocks so the flag can be check often.

volatile bool isr_happened;

void isr(){
    isr_happened = true;
}

void loop(){
    if(isr_happened){
        //do i2c

        isr_happened = false;
    }

}
  • 1
    But then what's the point on having the ISR? Better to poll the pin periodically rather than polling the variable and have the ISR to block the normal code. This can be useful only when the pin can change very quickly, but a user interaction runs for at least 100ms, and moreover knowing that it was pressed but being unable to know where is useless, so I'd avoid the ISR as per my answer – frarugi87 Nov 30 '17 at 9:46
  • The ISR can react to the change in the signal's level much more reliably than polling, since it is always checking, whereas polling checks periodically. Checking the state of a single pin, or a boolean variable, is far more efficient than repeatedly transferring chunks of I2C data. Use the ISR as a latch to store when the IRQ pin has changed, and use that latched value at a time that suits you, not the display, to read the coordinates. – Majenko Nov 30 '17 at 11:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.