PCINT handling overhead

Hello all, I’m new, (actually quite old!). Can anyone help with my understanding of PCINT. Please correct me if I’m wrong:

On a Mega 2560…
At a hardware level the interrupt is generated when any pin on the port changes.
It is then up to the ISR to sort out if it is the pin of interest.
Does this mean if I use another pin on the port for a fast changing signal it will add a large software overhead handling lots of unwanted interrupts?

Or does the hardware mask only the pins wanted for PCINT and ignore changes on other pins of that port?

I’ve tried looking in the AT Mega datasheet but can’t make much sense of how it handles ports.

Your wisdom is gratefully requested.

Have You tried the Arduino/reference section about Interupt?

The PCMSK registers allow you to disable / enable pin change interrupts on specific pins.

Any reason why you can't use normal interrupts?

On the Mega 2560, normal external interrupts are available on pins 2, 3, 18, 19, 20, and 21. These can be attached using attachInterrupt and support modes like RISING, FALLING, or CHANGE.

If that's not enough, you can use pin change interrupts, which are available through three groups: PCINT0 for digital pins 10 to 13 and 50 to 53, PCINT1 for analog inputs A8 to A15, and PCINT2 for analog inputs A0 to A7.

Each PCINT group has its own mask register: PCMSK0 for PCINT0 (PORTB), PCMSK1 for PCINT1 (PORTJ), and PCMSK2 for PCINT2 (PORTK). By setting individual bits in these registers, you enable pin change interrupts only for the specific pins you want. The ISR still triggers for the whole port, but only masked pins can cause it.

These interrupts are PORT based, meaning that when any enabled pin in a PCINT group changes state, the corresponding ISR is triggered, but it does not specify which pin caused the change, so software must detect it.

This can be easy if there is only one pin in the PCINT group that can trigger the ISR. If you have activated more than one in the group, then it's up to you to track the change in the ISR.

The typical way to do this is to declare a static byte to hold the previous port state. Read the current port input register for the PCINT group. Compare the current state with the stored previous state using XOR to find which pins changed. Update the static byte with the current state for the next interrupt. Then check which specific pins changed by testing bits in the XOR result. This lets you detect exactly which pins triggered the interrupt.

May be something like that (typed here not tested) for PORTB (PCINT0 group)

ISR(PCINT0_vect) {
  const byte pinMask = 1 << PCINT3; // PCINT3 is BIT #3 so pin 50 in PORTB
  static byte prevState = 0;
  byte currState = PINB;
  byte changedPins = currState ^ prevState;
  prevState = currState;

  if (changedPins & pinMask) {
    if (currState & pinMask) {
      // Pin 50 went HIGH
    } else {
      // Pin 50 went LOW
    }
  }
}

Already using all six for timing critical signals.

Thanks, that’s what I hoped. I’m running out of pins and can’t poll these as they are phase critical.

how often do they trigger ?

Remember that they already come with apriority order (pin 2 highest, then pin 3, pin 21, pin 20, pin 19, and pin 18 lowest).

PCINT interrupts have lower priority than the normal external interrupts.

Also remember that if an interrupt on pin 2 occurs and is being processed, then interrupts on pin 50 (a PCINT) and pin 3 occur, before the processor finishes handling the pin 2 interrupt first then interrupt on pin 3 before the PCINT on pin 50, because pin 3’s external interrupt has higher priority than PCINT.

➜ the interrupt on pin 50 waits until both pin 2 and pin 3 interrupts are fully handled.

if you have too many interruptions on normal pins and the processing takes a long time, then your PCINT might not even be handled or delayed significantly.

Up to around 20kHz but I am selectively enabling them and putting the phase critical signals on the INT pins to minimise the software induced jitter. I can also re-sample if I get a wildly variant timing issue caused by a perfect storm of signals coinciding.

OK - just be aware that an empty ISR will cost you 4 to 6 µs, you need to then add to that the time for the code you execute within the ISR.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.