Difference between using cli() sei() and TIMSK

Hi everyone, just have a quick question regarding use of cli() and sei(). I am using Timer1 which is of course 16bit. I have read that cli() should be used to globally disable interrupts when reading or writing to the counter registers TCNT1H and TCNT1L and followed up with sei().

However, my program is time critical and I only require one timer (Timer1) I am concerned that using sei() will enable ALL interrupts (inc other timers and checks for event interrupts etc) which may be wasting resources.

Would I be better off replacing cli() and sei() with TIMSK1 = 0 and TIMSK1 = (1<<OCIE1A) respectively to disable and re-enable the Timer1 interrupt before and after reading the registers? Would this work safely?

Many thanks

However, my program is time critical and I only require one timer (Timer1) I am concerned that using sei() will enable ALL interrupts

cli / sei don't work that way. They control a simple flag. If the flag is set, interrupts are allowed to pass to the processor. If the flag is clear, interrupts are blocked. They do NOT control what will and what will not GENERATE an interrupt.

Would I be better off replacing cli() and sei() with TIMSK1 = 0 and TIMSK1 = (1<<OCIE1A) respectively to disable and re-enable the Timer1 interrupt before and after reading the registers? Would this work safely?

I have no idea.

By default only timer0 is setup to generate interrupts (for millis()). Unless you are writing your own interrupt handler for timer1 (or using a library that uses one) there's no need to protect accesses to its registers.

When writing to TCNT1 you don't need to write to the high and low bytes seperatly. Just write to TCNT1 and the compiler will take care of disabling and re-enabling interrupts.

TCNT1  = *any value up to #FFFF*

So in short; don't worry about it.

Chris.

Would I be better off replacing cli() and sei() with TIMSK1 = 0 and TIMSK1 = (1<<OCIE1A) respectively to disable and re-enable the Timer1 interrupt before and after reading the registers? Would this work safely?

No! The AVR contains special hacks in its 16bit registers that require that the two bytes be written by consecutive instructions. So it's not just the timer1 interrupts that you would need to turn off, but ANY interrupt that might occur between the two byte reads/writes.
cli/sei are exactly what you want, and they are nice and quick. sei will not re-enable any individual interrupts that were not enabled before; it's not like the multi-level interrupt priority schemes on some more complex cpus.
@chris:the compiler will take care of 16bits, but it does not disable interrupts...

the compiler will take care of 16bits, but it does not disable interrupts...

on closer inspection of the datasheet I see that you are quite right. My apologies :-[

The AVR contains special hacks in its 16bit registers that require that the two bytes be written by consecutive instructions.

Quick question: How can it be a hack if it is the way it is designed? :smiley:
Also, having read the datasheet more carefully it can be seen that the second part of that statement is not strictly correct; The updating of the 16 bit registers is triggered by writing to the low byte and it is possible to re-use the high byte, therefore it does not require the bytes to be written by consecutive instructions but just that the high byte be written before the low byte.

From the datasheet:

If writing to more than one 16-bit register where the high byte is the same for all registers written, then the high byte only needs to be written once.

The reason to disable the interrupts prior to updating the 16bit registers is not to ensure that the two instructions take place consecutively, but to ensure that nothing else updates the registers in between the two instructions. If an interrupt did occur, but it didn't access the 16bit register you were previously in the middle of updating, the 16bit register would still be updated correctly.

But generally speaking it would be a bloomin' good idea to disable interrupts prior to writing to the 16bit registers.
I'm off to update some of my code accordingly...... oops!

Chris

Probably you're better off using the macros for defining atomic and nonatomic blocks in util/atomic.h

http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html