Hardware interrupt to ISR execution latency on Photon 2

Hello.

I am trying out the new Photon 2 for a project that interfaces with a single-wire bus (not 1-wire). When using attachInterrupt() there is a significant and variable delay between the input event and when the ISR executes. I've reproduced the issue in a very basic example, below -- just using a hardware interrupt to detect changes on an input pin and mirror them to an output pin. Once the ISR begins executing, it's perfectly fast enough (as evidenced by quickly toggling the output a couple of times in the ISR) -- but there is a 40-70us lag between the input and the ISR.

#define PIN_OUT   D6
#define PIN_IN   D19

volatile bool current;

void isr_in() {
    current = !current;
    digitalWriteFast(PIN_OUT, current);
    digitalWriteFast(PIN_OUT, !current);
    digitalWriteFast(PIN_OUT, current);
}

void setup() {
    pinMode(PIN_OUT, OUTPUT);
    pinMode(PIN_IN, INPUT_PULLDOWN);

    attachInterrupt(PIN_IN, isr_in, CHANGE, 0); // highest priority

    current = pinReadFast(PIN_IN);
    digitalWriteFast(PIN_OUT, current);
}

void loop() {   
}


(cyan is input, magenta is output)

Is there anything I can do to reduce the ISR start lag?

I added/changed some code below which might help reduce the time delay. I compiled it but did not run it.
First, I would add only the first line to your code and see if it makes a difference. If not, add the rest of the changes and see what happens. The docs referenced in the code below cautions against using most API functions, with the exception of pinSetFast, pinResetFast, and analogRead, within an ISR.
Hope this helps! :grinning:

SYSTEM_THREAD(ENABLED);// added
#define PIN_OUT   D6
#define PIN_IN   D19

//volatile bool current;
bool current;// changed

volatile bool triggerDetect = false;// added

void isr_in() {// changed
    triggerDetect = true;//Generally, an ISR should be as short and fast as possible.
}

void captureTriggerInfo() {// added
    current = !current;
    digitalWriteFast(PIN_OUT, current);
    digitalWriteFast(PIN_OUT, !current);
    digitalWriteFast(PIN_OUT, current);
}

void setup() {
    pinMode(PIN_OUT, OUTPUT);
    pinMode(PIN_IN, INPUT_PULLDOWN);

    attachInterrupt(PIN_IN, isr_in, CHANGE, 0); // highest priority
    //https://docs.particle.io/reference/device-os/api/interrupts/attachinterrupt/
    
    current = pinReadFast(PIN_IN);
    digitalWriteFast(PIN_OUT, current);
}

void loop() {   
  if (triggerDetect) {
    triggerDetect = false;
    captureTriggerInfo();
  }
}

added:
BTW, there are two other threads with content I thought were interesting and are worth a look:
@rickkas7 Can the P2 run two Interrupts concurrently? - #4 by rickkas7
&
@peekay123 P2 - GPIO and Interrupt Latency

Thanks, robc!

I just tried your modified code, and unfortunately it produced the same output on the scope as the original example.

I thought SYSTEM_THREAD(ENABLED) would be the solution in my real program, too, due to parallel execution, but it did not help -- so I wrote this example with an empty loop. Likewise in the real program I have a similarly short ISR routine. In this example I am doing a couple of digitalWriteFast() calls (which internally call pinSetFast and pinResetFast with a small conditional overhead) just to prove that the signal I'm working with is not faster than the Photon can read/write. If you zoom in on the waveform, you can see the tiny blips in the magenta where I am toggling in the ISR.

If I run the same logic on Argon, the ISR consistently fires 10us after GPIO change

As such, my issue is not latency within the ISR, but latency between the pin change and the ISR firing.
That second link you posted (GPIO and Interrupt Latency) seems directly relevant... the original poster there is getting similar results of 40-70us delay, and Particle responded with:

"We are most likely however unable to achieve better timings due to the GPIO peripheral clock speed, which we have no control over."

...so I may be out of luck here.

1 Like

@parityerror, the delays are due to hardware and firmware latencies which are not affected by SYSTEM_THREAD(ENABLED). Interrupt pins are either dedicated or shared on the Interrupt Controller. I suspect user interrupts are shared.

In the case of the Photon2, there are two delays contributing to latency. The GPIO's time to respond to the interrupt condition is affected by the peripheral clock frequency which dictates the speed at which pin states are sampled. On the Photon2, this can be quite "slow" and likely in the order of 3-4uS. The second delay contributing to latency is the time the system-level ISR handler takes to decode the specific interrupt bit from the (shared) interrupt register. The code must test every interrupt flag bit and then call the matching user-level ISR. If there is only one active interrupt and the bit in the register is tested first, then the latency may be lower. If there are several interrupts pending, then each ISR must be called before getting to the specific user ISR.

So, on the Argon and Photon, the hardware latency is likely lower and the decoding may be more efficient. My suspicion is that you will not get better ISR latency then the 40uS I found in my own tests.

3 Likes

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