Interrupt vs. Delay - who wins?


#1

I haven’t been able to find any specific reference in the doco to this.

If a delay() is in progress, will an interrupt stop the delay and start the function?

In my situation, we are ‘activating a pump ignition sequence’.

We need the start, hold, start, hold sequence to follow exactly the timing we put in and not have an interrupt stop the sequence. I’m unsure if when an interrupt function runs, if it returns to the ‘top’ of the loop() function, or resumes the loop() in the same spot it left off.

Any insights would be greatly appreciated :slight_smile:


#2

I think i found a more appropriate solution… disable the interrupts while running time critical/ordered logic.

noInterrupts();

        digitalWrite(ignitionRelay, HIGH);  //1st trigger
        delay(pumpDelayTime);
        digitalWrite(ignitionRelay, LOW);   //Wait - off
        delay(pumpDelayTime);
        digitalWrite(ignitionRelay, HIGH);  //2nd trigger
        delay(pumpDelayTime);
        digitalWrite(ignitionRelay, LOW);   //Wait - off
        delay(pumpDelayTime);
        digitalWrite(ignitionRelay, HIGH); //3rd trigger
        delay(pumpDelayTime);
        digitalWrite(ignitionRelay, LOW); //turn ignition off
    interrupts();

#3

yes or you could try using:

ATOMIC_BLOCK()

realize however if you are not managing the cloud connection yourself, you may get into connection issues.

You may also want to look at the bit about System Modes, if you haven’t already.

**Alternatively you could perform that pump switching without delay().


#4

Good thought on ATOMIC_BLOCK

I wonder, would an ATOMIC_BLOCK stop my I2C communications if that ignitionRelay were actually on a connected I2C device… or accessed via a separate message bus?


#5

how long is ignitionRelay?

Have you tried to write a function that doesn’t use delay()?

EDIT Look at Spark Interval Timer or look at the Software Timers… either may be appropriate for your timing-critical event management.


#6

After an Interrupt code picks back up where it left off, anything else would surely be chaos.
Given all your are doing is turning something on and off, Could you not also do this with a Timer toggling a boolean state or the recommended millis().
If you have defined an interrupt it is precisely because you want it to interrupt your application to act on that trigger. Any code triggered by an interrupt should be very short, like setting a flag, at which point you return to your sequence with minimal consequence.
My limited understanding of the Particle system would suggest the only Particle defined interrupts that could interfere are probably linked to the Setup and Reset buttons.


#7

Thanks!

The ignition delay is between 1 to 3 seconds (depending on the pump used)

I was thinking about using timers (I’d need quite a few given the repeating)

When I’m running this function - I’m blocking all other functions and looped code from running by using some logic checks:

if (pumpStarting == 0)
{
//Do all other code
}
else
{
//Do nothing
}

Maybe I should swap delay() for delaymillis() that way I can maintain the connection.
I’m also using SYSTEM_THREAD(ENABLED) to help maintain the connection.

Am I right to say, delay only stops user code - but with SYSTEM_THREAD(ENABLED) my other connection and background tasks keep running in the other thread?


#8

You can use one, resetting and re-triggering it.

Yes, but threads can step on each other… using Timers would let you get your pump intervals in the interrupt queue.

@Cameron would only writing to a pin and resetting a timer, which he may easily make happen within the ISR.


#9

I was thinking that… but the logic I have was

  • I’m in a function outside of loop() and don’t want the loop() to continue
  • I don’t want the function to go to the next line of the function
  • I’m using SYSTEM_THREAD so the delay() wont impact the connection management (This is an assumption) - but looks like @BulldogLowell has confirmed this is the case :slight_smile:

#10

Thanks - I’ll have a look into leveraging a timer.

I’m still a little unclear what I gain from a timer vs. delay if I have system_thread(enabled) set to enabled and don’t want any loop(), interrupts or other code running in the mean time?

The only thing - I think if a SMS is received by the unit during the ‘delay’ event… I’m not sure what happens to the SMS hummm


#11

It may be better to keep loop() looping, managing the events with a state machine-like approach.

If you have the skills, you you may want to try to create a little class that inherits from Timer that includes at least two member functions. 1) starts the pump start sequence and 2) returns true if the sequence is active.

That’s one approach, but I’m spiraling out here… sorry.


#12

exactly… Asynchronous events are what makes a State Machine approach so simple and so popular.


#13

I think I just realised, I do want to block SMSs during that time…

If I receive a spam SMS during that time, I don’t want it interrupting the starting or shutdown sequence… that wouldn’t be ideal.

I think I’ll just force the user to assume a lack of SMS confirmation means their action wasn’t received. So I don’t have to ‘worry’ about that problem… fweph!.

Thanks for your help! I think we are okay with timers or delays, as long as the system_thread(enabled) mode enables the connection to be maintained :slight_smile:


#14

PS: Ideally… we’d get a damn pump that started off a single digital HIGH signal… sigh…


#15

Latching relay?


#16

Really? don’t you just want to handle them? if it is ‘spam’ you must know how to determine that.

No news is bad news? what if it isn’t working at all… no news is worse news!

Handle the SMS, return “I’m busy” if it is busy.

What you want to do isn’t that hard to do!


#17

1 second might seem short but its an age to a microcontroller switching threads every 1ms. Now if you were instead talking much smaller intervals, then you might need to be worried e.g the example shown here https://docs.particle.io/reference/firmware/photon/#single_threaded_block-
The only things you really need worry about are the synchronous calls that could cause blocking behaviour listed shortly before that example. But that’s easy enough, if the ignition sequence is in progress don’t call any Particle methods until it is done.


#18

Humm, I thought about this and wondered if that meant I needed to keep the latch state in memory - if we had power outages or used the bypass switch I’d end up with some complex logic… the alternative being I guess to use another relay to reset the latching - but that increases the pin count (already running low) and also makes it really hard for the onsite installer/electrician to wire it up.

Unless I’m missing something about the latching relay ponders


#19

Oh you mean - I should avoid Particle.publish?


#20

That is a good point!

I was thinking, disregard the SMS’s in memory as they may contradict each other.
e.g. One user turns the pump on, another user tries, someone tries to turn it off, someone tries to check the state. I’d end up with scrambled up perspectives of ‘state’ of the pumping unit.

Maybe the answer lies in your suggestion of ‘i’m busy’ … argh - that brings me back to the complex world of trying to read SMS messages. I have another thread going for that one! haha