Questions about interrupt functions

Hello, I have questions about what I can do in an interrupt function and what I should not do.

I already know that Serial.write should not be used. But what about digitalRead and digitalWrite?

And what about the time consumption in the interrupt function? In general I understand it should be as low as possible, but is there a rule of thumb about how long it can be?

I have configured an timed interrupt. Part of my (yet not tested) code:

void setup()
{
  ...
  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 18200;
  TCCR1B |= (1 << CS10) | (1 << CS12);
  TIMSK1 |= (1 << TOIE1);
  sei();
}

ISR(TIMER1_OVF_vect)
{
  TCNT1 = 18200;

  ...
}

digitalWrite() and Read() will work as they don't require interrupts (which are turned off while processing an interrupt...)

Interrupts should be as short as possible. You can read or write a pin (etc) and then usually set a flag if additional non-time-critical event-related logic needs to occur; that can happen in the mainline code.

Thanks. Is there any information about which functions that require interrupts?

How long is too long depends on your application. If the foreground task is not doing much, or is not doing anything time-critical, you can spend quite a bit of time in the interrupt handlers. It all depends on the needs of the application, and no two are alike. I have some where most of the heavy lifting is done in interrupt handlers.

Regards, Ray L.

I think that below covers the basics: 1) Anything communication related. 2) Anything timing related.

You can search the Arduino install directory with e.g. grep (Linux, Mac) or grepWin (Windows) for the word ISR at the beginning of a line (optionally with whitespaces before it) using the regular expression ^\s*ISR.

Same for 3rd party directories.

On the system I'm currently using, I can find the following 3rd party libraries that use an ISR radiohead fastled irremote lowpower

It's trickier to find which standard functions that you use depend on interrupts. E.g. millis() will not update while interrupts are disabled but you basically will have to dig to find that the value that millis() returns is updated using an interrupt.

On the system I'm currently using, the easy to find standard ones hardwareserial softwareserial tone twi (I2C)

I have questions about what I can do in an interrupt function and what I should not do.

Don't use interrupts for detecting button presses. Buttons pressed by humans are very, very slow in processor terms, and don't need an interrupt, plus buttons usually need de-bouncing, which is somewhere between difficult and impossible to do properly with an interrupt.

Using grep on the source code was a good idea :) Thanks.

I'm using attachInterrupt to detect push buttons used for aborting a ongoing process. The interrupt function do only one thing - set a flag.

To detect other buttons I add code where the program do a loop, ie when scanning a keypad for input, something like:

char waitForKeypad(void)
{
  char key;

  do {
    key = keyapd.getKey();

    idleLoop();
  } while (NO_KEY == key);

  return key;
}

void idleLoop(void)
{
  // Add checks, like checking push buttons.
  checkPushButtons();

  // Add other checks here.
}

No ide what your ongoing process is. Checking a flag in your ongoing process or checking a button in your ongoing process is basically the same (though a digitalRead() will take a little more time.

The interrupt function do only one thing - set a flag.

Then it is very likely that you don't need to use an interrupt

If the purpose of the flag is to signal to the code in loop() that an input has changed state then at the point you test the flag you might just as well read the state of the input at that point. If the loop() function takes what you deem to be too long between input checks then there is probably something wrong with the structure of your program.

An ISR is used to handle some urgent event involving external hardware - urgent means microseconds to 100's of microseconds - or to schedule regular events with microsecond precision (using a timer interrupt), such as driving a DAC or ADC sampling rate.

I'm using attachInterrupt to detect push buttons used for aborting a ongoing process.

As I said, and others have repeated; don't use interrupts for buttons.

PerryBebbington: As I said, and others have repeated; don't use interrupts for buttons.

There will be exceptions to this. I had one very large app with a very busy UI and polling was just too slow. Interrupts in this case (read encoder switches) was the only option if I wanted a responsive UI.

econjack: There will be exceptions to this. I had one very large app with a very busy UI and polling was just too slow. Interrupts in this case (read encoder switches) was the only option if I wanted a responsive UI.

Errr, OK, but I was talking about button presses, not reading encoder switches. I am thinking you mean rotary encoders, is that right? When I was experimenting reading them I found I needed to poll them once per millisecond to be reliable. I had a timer driving an interrupt which polled the encoder inputs every millisecond. The encoders themselves did not cause the interrupt. There will be exceptions to any rule of course, but I suggest if you find yourself forced to use interrupts to detect button presses because loop() takes too long then you have other issues that need to be addressed. Based on my own experimentation I would think that polling buttons would work OK up to maybe 50 milliseconds.

I am confident that in this case interrupts are not the correct solution.

PerryBebbington: As I said, and others have repeated; don't use interrupts for buttons.

I most cases that is true, but for this project the controller is busy doing other things and one button is used to abort the ongoing process. I do this with an interrupt function using attachInterrupt and the interrupt function set a flag that can be checked in the ongoing process loop.

But this has nothing to do with the timed interrupt function.

the controller is busy doing other things

Such as ?

For this project the controller is busy doing other things

Then there is something fundamentally wrong with the way your code is written. It should not get tied up doing something for so long it does not return to loop() for ages. I would think that if it does not return to loop() at least every 10ms or so then it needs to be re-written so it does.

Blackfin: digitalWrite() and Read() will work as they don't require interrupts (which are turned off while processing an interrupt...)

Interrupts should be as short as possible. You can read or write a pin (etc) and then usually set a flag if additional non-time-critical event-related logic needs to occur; that can happen in the mainline code.

What about digitalWrite using IO expandes like PCF8574?

thehardwareman: What about digitalWrite using IO expandes like PCF8574?

I2C uses interrupts; see reply #4 ;)

Ah... thanks. I have to rewrite the code a bit :)