Skip to content

Slow Rise/Fall Times on GPIO inputs result in Spurious Interrupts #4172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
BjarneBitscrambler opened this issue Jul 15, 2020 · 8 comments
Closed
Labels
Status: Stale Issue is stale stage (outdated/stuck)

Comments

@BjarneBitscrambler
Copy link

Summary

I was having trouble getting one, and only one, interrupt per transition on a digital input pin. I noticed that there are at least 5 other issues ( #955, #1111, #1229, #1250, #2941 - all presently CLOSED) that report the same or similar difficulty.

I have figured out the cause in my situation, and believe the same explanation applies to the majority of the other reports. Since it crops up so frequently, I thought I would document my observations to help forestall future frustration. The 'scope shots are particularly good at illustrating why the problem occurs.

Briefly, in order for the rising- or falling-edge interrupts to function correctly on the ESP32 GPIO pins, both the rise and fall times of the input waveform must be short enough. My testing so far suggests that a 2 us (microsecond) or shorter transition between 10% and 90% logic levels avoids false triggering.

Background

I use an ESP32-WROVER-KIT, programmed with Platform.io using the latest Arduino code framework. I wish to measure the frequency of an AC waveform coming from an alternator. With a resistor-divider I bring the nominal 12V signal level down to 3V3 logic level. Since the signal travels several metres from the alternator, I also included some series resistance and parallel capacitance to protect against transients and filter out high-freq noise. What I wanted was a single interrupt each time the input waveform went positive. By counting the rate of the interrupts, I could determine the frequency of the alternator's output.

Problem

The reported frequency was between 1.5 to 3 times higher than it should have been. This suggested that multiple interrupts were occurring per single waveform cycle. Further, the error factor varied with the speed of the alternator, decreasing when the alternator speed was increased.

Investigation

I'll skip the deadend avenues... The setup that clearly reproduced the problem was feeding a signal from a waveform generator (GW model GFG8015G) to a GPIO pin on the ESP32. Using a waveform generator permitted varying the shape and frequency of the applied signal. ESP32 software configured the pin to trigger an interrupt on the rising edge of the input. The interrupt routine incremented a counter each time it was invoked, and set an output pin either high or low depending on whether the count was even or odd. By monitoring the input and output pins with an oscilloscope, it was easy to determine the relationship between the input signal and the resulting interrupts.

Here's the code snippet of the interrupt handler:

static void triggerIntHandler( void *args )
{   interrupt_count++;
    gpio_set_level( STATUS_OUTPUT_PIN, (interrupt_count % 2 ) ); //toggle output each time int called

}

Observations

Proper Triggering

Here's a scope shot showing proper interrupt behaviour. The Yellow trace is the input signal, a square wave of amplitude about 3.2 V and frequency about 100 Hz. The Blue trace is the output from the interrupt routine; each transition represents one invocation of the interrupt handler. As expected, a single interrupt occurs at each rising edge of the input waveform. Not shown, but verified, is that when the software is changed to call for interrupts on the falling edge, the output toggles on the expected falling edge of the input.
SDS00020

Erratic Triggering

Without changing the ESP32 software or hardware, the applied waveform was switched to a triangle wave, thus extending the rise- and fall-times of the transitions (to about 4 ms in this example). Here's the observed output: interrupts happen on both the rising and falling edges. Sporadically there are even two interrupts on a single rising or falling edge (e.g. the first triangle shows 2 triggers on its falling edge, and the second triangle shows 2 triggers on its rising edge).
SDS00019

By adjusting the waveform's rise and fall times, I observed the following two points (with the software configured to rising-edge interrupt):

  • a rising-edge duration shorter than about 200 us prevented most of the extra rising-edge triggers
  • a falling-edge duration shorter than about 40 us prevented most of the spurious falling-edge triggers
    SDS00021

When the rise-time was reduced to about 60 us, and the fall-time was reduced to about 4 us, the trigger behaviour was almost perfect (though not shown in the below scope shot, I did observe two instances of false triggering on the falling edge, over several hundreds of waveform cycles).
SDS00022

Conclusions

  • when relying on rising or falling edge triggering, ensure that the input waveform has a fast enough rise and fall time. This applies to both edges, regardless of which edge you wish to trigger on.
  • I haven't characterized the rise and fall times needed to ensure perfect triggering, but I suggest that edges should be kept to less than 2 us duration (measuring from the 10% to 90% amplitude crossings). A 4 us duration gave acceptable results for my application, but I did observe the occasional false trigger at this transition speed.
  • There may be an asymmetry in the behaviour re: falling edge rates vs. rising edge rates. My initial observations suggest that the ESP can tolerate slower rise times than fall times, but this was only when triggering on the rising edge. I didn't experiment with triggering on the falling edge, nor experiment with turning the internal pull-up resistor on/off.

Discussion

Signal Conditioning

It's usually desirable to condition signals that originate off-board before applying them to microcontrollers/CPUs. One wants to attenuate external noise and transients surges, while still allowing the desired signal through. In a manual switch application for example (issues #955, #1111, and #1229) one commonly sees a parallel capacitor used to 'debounce' the signal. Unfortunately while that may successfully merge multiple quick bounces into a single pulse, at least one of the edges on that pulse will be quite slow - in the millisecond range.

Similarly, when triggering on AC mains, the sinewave input has a long duration rise and fall time. Since the frequency is known (i.e. 50 or 60 Hz), it is possible (as I believe was done in issue #2941) to workaround the triggering problem by referencing subsequent software actions off the first interrupt, and using a timeout to keep from re-tripping during the remainder of the input cycle.

Schmitt Trigger Inputs

I didn't find in either the ESP32 Datasheet nor Technical Reference Manual any specification on maximum signal transition times. It seems clear that they are not using Schmitt trigger logic for the GPIO interrupts. To allow for this, when using signals that are slow-changing they should be fed through an external logic gate such as the 74LVC1G17 or many other similar ICs.

I2C Signals

Issue #1250, I believe, was not running afoul of the rise/fall-time problem (at least not entirely), but it did remind me of another situation in which one sees slowly-changing signals. The I2C protocol allows multiple devices to listen to the same bus, through the use of open-drain drivers together with pull-up resistors. This can result in rise-times that may be slow enough that the ESP32 records a double transition when there really is only one. I haven't delved into the ESP32 specs for their I2C module to see whether they have allowed for this or not, but it would be worth being aware of if using I2C.

Conclusion

Thanks to the other folks like @stickbreaker, @usmanshahid001, @ddieffen, @MacLeod-D, and @404-baitnotfound for posting your problems and solutions - it helps to know what others have tried. I hope I have summarized everyone's observations accurately. For sure, slow rise/fall times are not the only reason for unreliable interrupts, but are a big piece of the puzzle.

Comments & feedback are welcome!

@DougArmstrong
Copy link

Bjarne,
Thank you for the great work on this problem! I too was measuring the RPM of an alternator (wind generator) using an opto coupler to drive a GPIO interrupt pin. I have a new revision of my project PCB arriving this week and have added the external pull up. Hope to have that tested this week.

Again thanks for the work on this.

Best
Doug

@stale
Copy link

stale bot commented Sep 13, 2020

[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

@stale stale bot added the Status: Stale Issue is stale stage (outdated/stuck) label Sep 13, 2020
@RaveGun
Copy link

RaveGun commented Sep 24, 2020

WOW, just WOW.
@BjarneBitscrambler Excellent analysis.

I started a year ago to build a bike computer for my home trainer.

After months of procrastination and no idea how BT works, I managed to learn a minimal BT stack to implement some device.
I was thinking that reading two reed switches will be the easiest part, and boy, was I wrong 😄 .

Well, I guess nothing beats a Trigger Schmitt.

@stale
Copy link

stale bot commented Sep 24, 2020

[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.

@stale stale bot removed the Status: Stale Issue is stale stage (outdated/stuck) label Sep 24, 2020
@stale
Copy link

stale bot commented Nov 24, 2020

[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.

@stale stale bot added the Status: Stale Issue is stale stage (outdated/stuck) label Nov 24, 2020
@stale
Copy link

stale bot commented Dec 8, 2020

[STALE_DEL] This stale issue has been automatically closed. Thank you for your contributions.

@Elijahg
Copy link

Elijahg commented Sep 25, 2021

Awesome analysis @BjarneBitscrambler, thanks! Certainly helps understand what's happening with all these interrupt issues people are having. I've just created another issue in the ESP-IDF repo about this, and I'm going to give Espressif a few days after the weekend to reply - and if they don't, I'll keep bugging them until they do. It's ridiculous that they seem to be avoiding what is a serious issue, especially since I imagine almost every project uses an interrupt attached to a button in some form or other.

@gunicsba
Copy link

I personally found it working better if I use CHANGE type instead of falling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Stale Issue is stale stage (outdated/stuck)
Projects
None yet
Development

No branches or pull requests

5 participants