Interrupt triggering on rising and falling edge

Hi all,

I have a ESP32 with an Arduino Nano pulsing voltage via a relay for 500 milliseconds every 10 seconds.

The ESP32 has an interrupt that should trigger on the rising edge. Note that the ESP32 uses reverse logic so that means it should trigger when the voltage pulse stops.

The interrupt is initialized like this:
Before setup

void ICACHE_RAM_ATTR LogSensorReading();

In setup:

  pinMode(sensorPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(sensorPin), LogSensorReading, RISING);

And the interrupt is:

void LogSensorReading () {
  if (inloop == true) { //when the board first boots up unfortuantly it runs the interrupt and resets all our credentials, so we need to ensure that we are in the loop before the option to reset the credentials comes available
    /* GET THE CURRENT TIME */
    DateTime now = rtc.now();

    /* AND PUT THE CURRENT YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS INTO ONE STRING */
    int currentYear = now.year(); //put the current year into a variable
    int currentMonth = now.month(); //put the current month into a variabl
    int currentDay = now.day(); //put the current day into a variable
    int currentHour = now.hour(); //put the current hours into a variable
    int currentMinute = now.minute(); //put the current minutes into a variable
    int currentSecond = now.second(); //put the current seconds into a variable

    String receivedTimeDate = (String(currentYear) + "-" + toStringAddZero(currentMonth) + "-" + toStringAddZero(currentDay)) + ("T") + (toStringAddZero(currentHour) + ":" + toStringAddZero(currentMinute) + ":" + toStringAddZero(currentSecond)) + ("Z");

    if (stringQueue.isFull()) {
      Serial.println("Queue full removing item....");
      Serial.println(stringQueue.dequeue());
      Serial.println("======================================================");
    }
    stringQueue.enqueue(receivedTimeDate); //enqueue the date and time
    Serial.println(receivedTimeDate);
  }
}

I will post full code shortly, but can anyone see what I am doing wrong? Would you like me to create and upload a wiring diagram?

Thanks,

Zeb

but can anyone see what I am doing wrong?

It appears that you are attempting an i2c read and serial printing from within the isr.

These two activities are both inappropriate for an isr, because they require interrupts to be enabled to function properly, and interrupts are disabled within the isr.

Hi cattledog,

Thank you for your help!

How do enable interrupts?

Thanks again,

Zeb

What's done as a result of an interrupt needs necessarily to be exceedingly brief.

Where's this "reverse logic" bit written?
Many of the ESP32 GPIOs aren't for casual use (like Arduino GPIO), they're pulled-up or
have states that cannot be violated at boot and so on.

cattledog:
It appears that you are attempting an i2c read and serial printing from within the isr.

These two activities are both inappropriate for an isr, because they require interrupts to be enabled to function properly, and interrupts are disabled within the isr.

it is possible to read an I2C from within an ISR by giving the I2C a higher interrupt priority than the ISR doing the read - never attempted this on an Arduino though
certainly never attempt console IO from within an ISR

How do enable interrupts?

I would not go down that rabbit hole.

You have an inappropriate isr where you are trying to do too much within the isr. Enabling interrupts to make it all happen is not the correct solution to whatever you are trying to do. Why do you need an interrupt to detect a 500ms pulse in order to log something to the nearest second?

An isr should be short and simple.

I want to store the time and date each time a pulse comes in and then do a HTTPS post, but if the pulse comes while doing the HTTPS post it needs to store this and then post it later.

How could I get the interrupt to be simple?

I need it to:
Get the current time and date
Enqueue the time and date

@runaway_pancake I want it to trigger when the pulse ends so I say when it "RISES" (1 = LOW, 0 = HIGH)

Thanks for your help!

Zeb

have a look at

it appears that the interrupt priorities on the ATmega328 are fixed (lower addresses having the higher priority)

In the ISR, record the time. Next in loop(), do something with it. When done, clear the recorded time to zero.

Or maybe better, also set a flag in the ISR that a new time was recorded and clear that once the time is processed in loop().

Note that it's advisable to disable interrupts in loop(), make a copy of the recorded time to work with and immediately enable the interrupts again. That way, a new interrupt will not corrupt the time that you're processing.

Hi all,

Thank you very much for all your help!

I don't think that the issue is to do with what is in the interrupt because I removed everything except for a Serial.println and it still triggered when the voltage "ROSE" and "FELL". Is that a correct conclusion?

@horace thank you for the link but I don't think that the link applies to me as I am using an ESP32. Is that correct?

Thanks again,

Zeb

I know I am not supposed to use Serial.println commands in an interrupt..... Could that be the problem? (testing in progress)

ZebH:
horace thank you for the link but I don't think that the link applies to me as I am using an ESP32. Is that correct?

in #1 you stated the host micro was a Arduino Nano which is based on the ATmega328 processor - hence the comment about fixed interrupt priorities
I was thinking back to when I was using a PIC24FJ256GA705 which enables interrupt device priorities to be set, e.g. the I2C priority could be set higher than the timer eanbling the I2C functions to be called from a timer interrupt service routine

certainly do not call console IO functions such as Serial.println from interrupt service routines

OK, thanks! I will remove the Serial.println.

The Nano controls a relay to send voltage pulses, and the ESP32 "detects" the pulses :slight_smile:

if you do a web search for ESP32 Technical Reference Manual - Espressif Systems page 36 covers interrupts
a couple of useful guides
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/intr_alloc.html

the ESP32 forum may also be able to help

What are you doing to debounce the input signal?
Also, it would be simpler to save the time in unix time format, then do the conversion to human readable date/time outside the interrupt.

Hi horace,

Thanks for the links.

I have removed the Serial.println from the interrupt and just have it toggling a variable and the same problem is occurring (triggering on RISING and FALLING of voltage)

I have tried the code in last minute engineers tutorial but still have the same problem.

I will try the ESP32 forum as well.

Thanks,

Zeb

could you be getting some switch bounce from the relay so even on a falling edge you get bounce which triggers rising edge interrupt?
if you do a web search removing switch bounce you will get plenty of links

So it appears there are multiple issues.

First is the multiple interrupts likely do to "bounce" from the relay. Do you have a scope to look at the signal? Because of the interrupt context, you can only use a lockout period for software debounce. Hardware debounce can open up additional possibilities.

Second, you have the issue of the HTTP post blocking the recording of a time stamp without the interrupt. As has been previously suggested, using a unix format time stamp will simplify things.

I would not get the time stamp from an rtc, but rather use a time library which is periodically synched to an rtc or ntp call for accuracy. You can eliminate the i2c call and rtc reading from the interrupt.

Finally, you might wish to explore the using of the dual cores of the ESP 32 to split the time stamp logging from the HTTP sending. I don't know if this is actually possible, using the Arduino core, or how you would do it.

You can't be the first person to run into issues with real time tasks blocked by the HTTP. Certainly if the HTTP task can be stopped and restarted by an interrupt you can likely manage this with other techniques. There must be "non blocking" methods to send out small pieces.

ZebH:
I need it to:
Get the current time and date
Enqueue the time and date

I would recommend installing the 'Time' library by Michael Margolis. Then set your RTC as the time source so the Time library will synchronize with it periodically. Between synchronizations, it uses the system clock to keep track of time. That way you can get the current time in your ISR without trying to read it from the RTC. You can also get the time in the form of a single unsigned long value. You can easily make a queue for the timestamps. Your loop() function can take timestamps out of the queue, convert them to text, and send them out.