2 critical interrupts question

Hi,
I need to do two time critical operations simultaneously. Each of them would probably require an interrupt:

  1. phase controlling a triac - this requires to catch the time when AC crosses zero level
  2. measure pulse frequency from my power meter (converts measured watts to frequency - pulses)

My question is, if there is a way to do this using one Arduino without missing any of the two events, or if I will have to use two Arduinos.

You need to give a bit more info on the pulse you receive from your power meter.

On Triac control with Arduino there is much info online to be found: example Arduino Playground - ACPhaseControl

I have a power meter, connected to digital pin of the Arduino. It sends pulses through an optocoupler. Frequency varies from 0.5Hz (4 Watts measured) to approx 700Hz at maximum load (5.5kW). I'm using interrupt to catch the pulses and measure the frequency (which multiplicated by some constant is the measured power).

On the other hand I need to connect a second optocoupler, where the mains AC is driving it's LED, and connect it to another digital pin of the Arduino. I also need to catch the pulse starts, as they indicate the voltage crossing the zero axis. I want to wait some calculated time (value depends on the measured power above) afterwards and then fire a triac, driven from another digital pin (again through some driver inteface).

My problem is, how to do this simultaneously. I have to modify the triac firing moment depending on the power consumption measured by the power meter. When I will miss or wrongly measure the frequency from the power meter, the Watts value will be wrong. If I will miss or inproperly time the triac phase control, the system will malfunction... So both things are critical and I'm asking, if there is some programming possibility to do both things with one Arduino, or if I will have to use two separate boards for each thing.

I mean - I am worried about catching two interrupts simultaneously, because if one interrupt is called, the other may be missed at that time. Also the micros() value is stopped at that time.

pavelp:
Hi,
I need to do two time critical operations simultaneously. Each of them would probably require an interrupt:

  1. phase controlling a triac - this requires to catch the time when AC crosses zero level
  2. measure pulse frequency from my power meter (converts measured watts to frequency - pulses)

My question is, if there is a way to do this using one Arduino without missing any of the two events, or if I will have to use two Arduinos.

You should be able to handle them both using the two user interrupts pins on the standard Uno type board (pins 2 and 3 the mega board has more avalible). The individual interrupts are stored and buffered internally such that even if one interrupt ISR is active when the other interrupt arrives, when the first completes the second 'stored' interrupt on the other pin will be serviced. The events you are processing are relatively slow by the AVR 16Mhz speed, so I wouldn't expect any problems for you.

Lefty

Thanks Lefty. I have no idea how long may it take to process one simple ISR (~6 lines of code, substracting integers and storing variables only). But probably you are right, it will not make any significant delay to harm the process.... 16MHz is much more than 700Hz :slight_smile:

pavelp:
Thanks Lefty. I have no idea how long may it take to process one simple ISR (~6 lines of code, substracting integers and storing variables only). But probably you are right, it will not make any significant delay to harm the process.... 16MHz is much more than 700Hz :slight_smile:

The key always to using interrupts effectively is to keep the ISR function as short and fast as possible, usually by just setting or resetting flag variables and let the normal loop function test those flag variable to take action that takes more time or complexity.

Good luck on your project.

Lefty

retrolefty:
You should be able to handle them both using the two user interrupts pins on the standard Uno type board (pins 2 and 3 the mega board has more avalible). The individual interrupts are stored and buffered internally such that even if one interrupt ISR is active when the other interrupt arrives, when the first completes the second 'stored' interrupt on the other pin will be serviced. The events you are processing are relatively slow by the AVR 16Mhz speed, so I wouldn't expect any problems for you.

Lefty

I'm little confused here. Are you sure about the interrupt calls being buffered in this case?
I have read some information about automatically disabled interrupts during the ISR. That would mean the other coming interrupt will be ignored.

In my project I need to catch hardware interrupts on pins 2 and 3 (Arduino Ethernet board) and I also need to do some timer1 triggered software interrupt [ISR(TIMER1_COMPA_vect)]. I need to be sure there will be none of the events missed.

It actually depends on the type of interrupt. Here's how the spec sheet explains it:

When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user soft-
ware can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current
interrupt routine. The I-bit is automatically set when a Return from Interrupt instruction – RETI – is executed.

There are basically two types of interrupts. The first type is triggered by an event that sets the Interrupt Flag. For
these interrupts, the Program Counter is vectored to the actual Interrupt Vector in order to execute the interrupt
handling routine, and hardware clears the corresponding Interrupt Flag. Interrupt Flags can also be cleared by writ-
ing a logic one to the flag bit position(s) to be cleared. If an interrupt condition occurs while the corresponding
interrupt enable bit is cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the
flag is cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt Enable bit
is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the Global Interrupt Enable bit is
set, and will then be executed by order of priority.

The second type of interrupts will trigger as long as the interrupt condition is present. These interrupts do not nec-
essarily have Interrupt Flags. If the interrupt condition disappears before the interrupt is enabled, the interrupt will
not be triggered.

When the AVR exits from an interrupt, it will always return to the main program and execute one more instruction
before any pending interrupt is served.

I don't know if the ethernet interrupts are level triggered or edge triggered. I expect they are edge triggered, and it should queue them up.

Timer interrupts are edge triggered and will queue up just fine. The only problem would be if somebody took so much time in the ISR that two interrupts hit before the first one was handled.

The other problem would be if more than one interrupt were to be multiplexed onto one interrupt pin. For example, Pin Change interrupts. If you happened to be handling a higher priority interrupt and got two pin change interrupts that were multiplexed to the same PCINT, the PCINT would be queued up, but the ISR would only be called once and you would have to figure out in the ISR that two pins had changed.

Nesting interrupts is possible. Carefully.

OK and what happens, if I simply put "Interrupts();" as the first line of the ISR? Will it allow to nest the other one correctly? I mean the attachInterrupt (0....) and attachInterrupt (1....) for example.

pavelp:
OK and what happens, if I simply put "Interrupts();" as the first line of the ISR? Will it allow to nest the other one correctly? I mean the attachInterrupt (0....) and attachInterrupt (1....) for example.

Yes.

That is exactly how to do it. Or, you could use the ISR(xxx, NO_BLOCK) attribute which is supposed to do it for you.

The problem with that is that you then need to make sure your ISR is re-entrant. Which means no static variables, and critical sections around global variable usage and such. What would happen if you're in the middle of using a global variable, and you get interrupted in the middle by the same interrupt, and execute the same code? It could get messy.

If your interrupts don't happen too close together, it might be easier to try to make the ISR as short as possible. Then if an interrupt hits while you're processing the interrupt, just let it queue up. When you iret it will execute one instruction and pop back into the ISR.