Pin value under interrupt change

I have two IR LED beams that pulse differently. Both have a 50% duty cycle at 48KHz. one is on for 85usecs and off for 400usecs and the other is on for 170usecs and off for 315usecs. I use CHANGE in the interrupt attachment and then read the pin to see if it’s falling or rising. I never seem to be able to get a consistent value for the pulse.

example code:

#include "Particle.h"

void setup() {
    pinMode(D1, INPUT);

void loop() {
    if ( (pulse != 0) && (rise != 0) ) {
        Serial.printlnf("pulse = %lu)  rise = %lu)  fall = %lu)", pulse, rise, fall );
        pulse = rise = fall = 0;

void getpulseWidth() {
    if ( pinReadFast(beaconSensePinArray[0]) == LOW ) {
        if ( (fall == 0) && (pulse == 0) ) {
            fall = SYSTEM_TICK_COUNTER;
    } else {
        if ( (fall != 0) && (pulse == 0) ) {
            rise = SYSTEM_TICK_COUNTER;
            pulse = rise - fall;

You are using the lowest possible priority, that won’t help maximum accuracy as other interrupts may be preempting your ISR.

The average latency of ISRs on the Photon - even on the highest priority level - won’t allow a reliable detection of signals of less than 10µs. While the edge may be detected correctly the ISR won’t get to reading the triggering level in time.
With minimum priority this will just get worse.

BTW, I guess your code above is not complete as there are several definitions missing.

What ScruffR said. Also be careful using SYSTEM_TICK_COUNTER as the unit varies between Gen 2 and Gen 3 devices. The micros() function is normalized to microseconds based on the clock speed and is safe to call at ISR time.

For measuring pulses on STM32 devices it’s possible to connect a TMR and an EXTI source so the timer measures the pulse width with no interrupt latency. I don’t think I have an example of doing this, but the STM32 standard peripheral library is accessible from user firmware so it should be possible.

1 Like