Skip to content

external pin interrupt firing twice #2941

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
ddieffen opened this issue Jun 27, 2019 · 3 comments
Closed

external pin interrupt firing twice #2941

ddieffen opened this issue Jun 27, 2019 · 3 comments

Comments

@ddieffen
Copy link

ddieffen commented Jun 27, 2019

Hardware:

Board: ESP32 Dev Module
Core Installation version: 1.0.2
IDE name: Arduino IDE
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 921600
Computer OS: Windows 10

Description:

I'm building a simple triac based dimmer using an AC Light Dimmer from RoboDyn module and an ESP32 Wroom dev board. It worked on an ATEGA328 but fails with the ESP32.

GPIO4 is connected to the Zero Crossing output of the AC module
GPIO5 is connected to the Gate input of the AC module
the AC module is powered by the 3V3 regulator of the ESP32 dev board

As shown on the oscilloscope screenshot below, why is the interrupt triggered twice ?
The issue is the same if I use different GPIO pins for the interrupt and gate.
This behavior was not happening with a Arduino Nano, I wanted to replace the nano with the ESP32

DS1-Z-Quick-Print2
image hosting

Sketch: (leave the backquotes for code formatting)

const byte phaseCtrl = 5;
const byte interruptPin = 4;
const byte ledPin = 2;

int dimming = 10;

void setup() {
  Serial.begin(115200);
  pinMode(phaseCtrl, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), zero_crosss_int, RISING);
}

void loop() {

}

void zero_crosss_int()  // function to be fired at the zero crossing to dim the light
{
  int dimtime = (75 * dimming);  // For 75 uS for 50Hz signal (100Hz zc) in 128 steps of 75 uS each
  delayMicroseconds(dimtime);    // Off cycle
  digitalWrite(phaseCtrl, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, LOW);    // triac Off
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, LOW);    // triac Off
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, LOW);    // triac Off
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, LOW);    // triac Off
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, HIGH);   // triac firing
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
  digitalWrite(phaseCtrl, LOW);    // triac Off
  delayMicroseconds(10);         // triac On propagation delay (for 60Hz use 8.33)
}
@ddieffen ddieffen changed the title Dual external pin interrupt firing external pin interrupt firing twice Jun 27, 2019
@bertmelis
Copy link
Contributor

Can't really read your screenshot. But maybe your signal is too slow it the ESP too fast. So during transition, the rising edge is detected twice.

@lbernstone
Copy link
Contributor

This can be fixed by setting a global lock variable at the top of your interrupt routine. However, you are going to ultimately run into issues with your ISR taking too long and setting off the watchdog. You should set the lock variable in the ISR, and then do the triac processing in your main loop (or use FreeRTOS semaphores if you know how to do that).

@ddieffen
Copy link
Author

ddieffen commented Jun 28, 2019

Thanks, you were right, the issue was about a bouncy input signal.
The locking mechanism worked !

DS1-Z-Quick-Print3
image uploader

Below is my working code:

const byte phaseCtrl = 18;
const byte interruptPin = 5;

int dimming = 30;

volatile unsigned long risetime = 0;
volatile unsigned long lastrisetime = 0;
int debounce = 700; // debounce latency in ms
                    // very long to avoid firing on the falling slope

volatile int interruptCounter;
hw_timer_t * timer = NULL;

byte varCompteur = 0; // La variable compteur
bool zeroDetect = false;

void IRAM_ATTR onTimer() {
  if (zeroDetect && interruptCounter++ > dimming) {
    for (int i = 0; i <= 5; i++) {
      digitalWrite(phaseCtrl, HIGH);   // triac firing
      delayMicroseconds(10);
      digitalWrite(phaseCtrl, LOW);   // triac firing
      delayMicroseconds(10);
    }
    zeroDetect = false;
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  pinMode(phaseCtrl, OUTPUT);
  pinMode(interruptPin, INPUT);
  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 75, true);
  timerAlarmEnable(timer);
  attachInterrupt(digitalPinToInterrupt(interruptPin), zero_crosss_int, RISING);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available()) {
    //dimming = Serial.read(); //when reading two bytes
    dimming = Serial.parseInt(); //when reading ascii chars
    Serial.println(dimming, DEC);
  }
}

void zero_crosss_int()  // function to be fired at the zero crossing
{
  risetime = micros();
  if (risetime > lastrisetime + debounce)
  {
    timerWrite(timer, 0);
    interruptCounter = 0;
    zeroDetect = true;
    lastrisetime = risetime;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants