cli() and sei()

Hi all! I have a question on whether something that came to me as an idea stands as a good programming practice. Assume, there is a method which while executed should not be interrupted and let us call it foobar() in this example. This method is invoked from within the loop() method. Is it ok to surround the method with cli and sei as follows (i.e. is it functional and efficient)?

void loop(){
  // Some code here
  cli();
  foobar();
  sei();
  // Some more code afterwards
}

I read somewhere that one can do pretty much the same using atomic blocks? Could you give an example and summarize the pros and cons of each approach? Thanks a lot in advance.

Yes it can even be required when say using interrupt ISR where both the main loop function and the ISR have access to the same global variable. The Arduino platform offers two commands to accomplish this:

http://arduino.cc/en/Reference/NoInterrupts

http://arduino.cc/en/Reference/Interrupts

void setup() {}

void loop()
{
  noInterrupts();
  // critical, time-sensitive code here
  interrupts();
  // other code here
}

Lefty

retrolefty:
The Arduino platform offers two commands to accomplish this

I guess there shouldn't be a difference between these methods and cli/sei, is it? What about atomic?

chung:

retrolefty:
The Arduino platform offers two commands to accomplish this

I guess there shouldn't be a difference between these methods and cli/sei, is it? What about atomic?

Atomic, is to the best of my understanding, just a word to describe the need for a sequence of instructions that need to be guaranteed not to be interrupted. Interrupt/no interrupt is a method to insure that happens.

And I would stick with the Arduino supplied commands as your method is not dealing with should the flag bits be saved or not.

Lefty

Will the interrupt be "on hold" until interrupts(); is called or it will be completely missed ?

retrolefty:

void setup() {}

void loop()
{
  noInterrupts();
  // critical, time-sensitive code here
  interrupts();
  // other code here
}




Lefty

retrolefty:
And I would stick with the Arduino supplied commands as your method is not dealing with should the flag bits be saved or not.

The Arduino supplied commands aren't really commands...

From Arduino.h:

#define interrupts() sei()
#define noInterrupts() cli()
3 Likes

fuh:
Will the interrupt be "on hold" until interrupts(); is called

Yes.

or it will be completely missed ?

No.

What would we do without you?

Lefty

fuh:
Will the interrupt be "on hold" until interrupts(); is called or it will be completely missed ?

It won't be missed unless you take so long in your time critical code it can't keep up. For example, a timer overflow would (usually) occur twice in 2 mS, so the first one would be missed. Likewise, there is a limit to how much incoming serial data can be buffered before some is dropped.

Also remember serial writes rely on interrupts, and various other things (like delay). So go easy on disabling them.

What is this time-critical code? Perhaps it can be achieved with hardware timers. Or using SPI.

retrolefty:
Atomic, is to the best of my understanding, just a word to describe the need for a sequence of instructions that need to be guaranteed not to be interrupted. Interrupt/no interrupt is a method to insure that happens.

It is that, and there is also a header file <util/atomic.h> in AVR Libc that has macros that implement an alternate way to deal with blocks of code that need to be executed atomically. Obviously nothing that can't be done via sei(), cli(), saving and restoring SREG, just a different style approach.

The question is a bit general but the motivation comes from some experience I had recently with an LCD display (2lines, 16chars, Hitachi protocol). I attached an interrupt to my program which would be triggered once a button was pressed. I noticed that the LCD would go bananas sometimes when I pressed the button. (If communication with an LCD is interrupted then you need to reset it to come round). So that is an example of time-critical code. Maybe there is a different approach that would synchronize the LCD to the Arduino controller that would offer robust performance, but, I am very happy with the LiquidCrystal library to change it...

Er, but LCDs keep showing what you last sent them, don't they? Sounds like a straightforward bug to me. Or, put it another way, when you press the button, it should just set a flag in the ISR, not do something really lengthy (like wait for you to release the button).

Well this is how I fixed the problem: I used a flag in the interrupt method instead of printing to the LCD. Setting a flag takes considerably less time than sending signals to the device. However this approach doesn't seem to me systematic enough. It's almost like a workaround since there is no clear answer to the question "How long is an interrupt method allowed to run?". Although I have already solved the problem, it would be nice to go back there and see what happens if I use noInterrupts();

There's no clear answer to the question of how long your routine was taking either.

I suggest interrupts should be kept very short. Setting flags, saving a value or two. Bear in mind that while your ISR is active you are locking out other interrupts, like timers, async comms etc.

Well, as a rule of thumb you are right. But if you want to be absolutely sure that things will work smoothly in all cases, it's better to use noInterrupts() or any alternative method.

More often than not, I just poll buttons rather than use interrupts. Is there some reason an interrupt is required to interface this button?

chung:

[quote author=Nick Gammon link=topic=96156.msg722317#msg722317 date=1331531393]
I suggest interrupts should be kept very short. Setting flags, saving a value or two. Bear in mind that while your ISR is active you are locking out other

Well, as a rule of thumb you are right. But if you want to be absolutely sure that things will work smoothly in all cases, it's better to use noInterrupts() or any alternative method.
[/quote]

"to be absolutely sure" sounds like just not reviewing or understanding the sketch code well enough. The AVR is a very deterministic chip, it does only what it's told to do. The arduino init source code is avalible to show everything that is activated and set-up, including interrupts, so one can know when and what to do in a very predictable way. There shouldn't be a 'lets be absolutely sure' situation. If a section of code needs atomic protection then you need it, if not you don't.

If it works, it works. Interrupts have their uses, particularly if you happen to be doing enough, between polling, that you might miss a button press altogether. Then an interrupt can set a flag to "remember" it was pressed.

The situation where this is more likely is things like rotary encoders where the state changes are coming in thick and fast.

But I wouldn't add interrupts to code that is working, just for the sake of it.

One example of using an interrupt might be something like a remote control, where you want to go into a low-power state to save the battery. Then you can make the "on" button cause an interrupt to wake the device up.