TMR2 Interrupt-Problem: TIMSK2 cannot be written

Hello,

I've changed the title of this post to reflect the actual issue.
The now interesing part starts with contribution #8 (scroll down).

I'm working on a project using the Arduino Pro Minit (ATmega328). I've stripped the program down to the essential part to understand the problem.
The program uses two interrupt sources to wake up from sleep: external interrupt INT0 and TMR2 interrupt. Basically this works but...

When entering the main loop, the program goes to sleep with the external interrupt enabled only. When the interrupt occurs it wakes up and enables the TMR2 interrupt + said external interrupt before it goes to sleep again.
But the TMR2 interrupt doesn't occur and the microcontroller doesn't wake up from it.
Another external interrupt causes a wakeup and the TMR2 interrupt is enabled again. This time it runs as expected and causes a wakeup.
From then on the device wakes up every time the TMR2 interrupt is used as a wakeup source.

My question: Why doesn't the TMR2 interrupt work when it is enabled first?

What I have tried so far:

  • I've reordered the setup of TMR2 as this might cause problems otherwise.
  • When changing the initial interrupt source in main() from EXTERNAL_INTERRUPT to TIMEOUT_INTERRUPT the timer interrupt works even the first time
  • I've added some debug output to see what's going on.

Here's the complete code:

#include <avr/sleep.h>

// **************** Definitions ****************

// Push Button
#define BUTTON_INT          2
#define BUTTON              7

// Timer
#define TIMER_INTERVAL      3

// **************** Global Variables ****************
volatile bool buttonPress = false;

unsigned int timeoutSeconds = 0;
volatile bool timeoutFlag = false;

enum wakeupSources
{
    EXTERNAL_INTERRUPT,
    TIMEOUT_INTERRUPT
};


// **************** Sleep and Wakeup, Interrupts and Timer2 ****************

// Interrupt INT0 for push button
void ISR_BUTTON(void)
{
    detachInterrupt(digitalPinToInterrupt(BUTTON_INT));
    buttonPress = true;
    Serial.print("iB"); Serial.flush();                                         // DEBUG
}

// Interrupt Timer2
ISR(TIMER2_COMPA_vect)
{
    static unsigned long counter = 0;

    counter++;
    if (counter >= ((unsigned long)(timeoutSeconds) * 40UL))
    {
        timeoutFlag = true;
        counter = 0;
        TIMSK2 = 0;                                                             // disable interrupt
    }

    if (counter & 0x02) Serial.print("."); Serial.flush();                      // DEBUG (only show every 4th occurence)

    return;
}

// Sleep
void enterSleep(wakeupSources source, unsigned int timeout_sec)
{
    Serial.print("\r\nenter sleep, wait for ");
    if (source == EXTERNAL_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
        Serial.print("EXT INT... ");

        buttonPress = false;
    }
    else if (source == TIMEOUT_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
        Serial.print("TMR INT... ");

        // Setup TMR2: interrupt every 25ms
        TCCR2B = 0;                                                             // set TCCRXB register to 0
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
        OCR2A = 194;                                                            // set compare match register of timer 2
        TCNT2 = 0;
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt

        timeoutSeconds = timeout_sec;
        timeoutFlag = false;
    }
    Serial.flush();

    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts

    sleep_bod_disable();
    do                                                                          // loops when timer interrupts
    {
        cli();
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
        sleep_enable();
        sei();
        sleep_cpu();
        sleep_disable();
        Serial.flush();
    }
    while ( (buttonPress == false) && (timeoutFlag == false));

    Serial.println("-Wakeup");
    Serial.flush();

    return;
}


// **************** Setup ****************
void setup(void)
{
    Serial.begin(115200);
    Serial.println();
    Serial.println("\r\nHello!");

    // Button
    pinMode(BUTTON_INT, INPUT);                                                 // external pull-Up
    pinMode(BUTTON, INPUT);
}

// **************** Main ****************
void loop(void)
{
    enum wakeupSources wakeupSource;
    unsigned int wakeupTimeout;

    wakeupSource = EXTERNAL_INTERRUPT;                                          // initial wakeup source

    // -------- Push Button
    if (buttonPress == true)
    {
        buttonPress = false;
        Serial.println("button");

        while(digitalRead(BUTTON) == LOW)
            delay(100);

        wakeupSource = TIMEOUT_INTERRUPT;
        wakeupTimeout = TIMER_INTERVAL;
    }

    // -------- Timeout
    if (timeoutFlag == true)
    {
        static unsigned char timeoutCount = 0;
        
        timeoutFlag = false;
        timeoutCount++;
        Serial.print("timeout #"); Serial.println(timeoutCount);

        if (timeoutCount <= 2)
        {
            wakeupSource = TIMEOUT_INTERRUPT;
            wakeupTimeout = TIMER_INTERVAL;
        }
        else
        {
            timeoutCount=0;
            wakeupSource = EXTERNAL_INTERRUPT;
        }
    }

    // -------- Sleep
    enterSleep(wakeupSource, wakeupTimeout);
};

This is the debug output:

Hello!

enter sleep, wait for EXT INT... iB-Wakeup
button

enter sleep, wait for TMR INT... iB-Wakeup
button

enter sleep, wait for TMR INT... ............................................................-Wakeup
timeout #1

enter sleep, wait for TMR INT... ............................................................-Wakeup
timeout #2

enter sleep, wait for TMR INT... ............................................................-Wakeup
timeout #3

enter sleep, wait for EXT INT... 

It can be seen that first the external interrupt is used and the device wakes up from it.
Then the timer interrupt is enabled but never executed. Instead the wakeup is triggered manually by another external interrupt.
Then the timer interrupt is enabled again but this time it is actually executed.

It would be great if someone could point out what I am missing.
Thank you very much!

Cheers
Arlenne

How do you have your button wired up? You have the pin declared as INPUT so it needs an external pull-up/pull-down resistor. Is that resistor present?

Also, you should not be using Serial.print() inside an ISR. Serial requires interrupts to clock out the data and interrupts are off inside an ISR. It might be that the Serila.flush() call is blocking since transmission won't happen yet the ISR waits for it to finish. Much better to set a flag and do that outside the ISR.

Thanks for your reply.

The button has an external pull-up. Due to other circuit requirements it is wired to both the interrupt pin INT0 and a regular digital input. But this works fine.

It is totally clear that there shouldn't be a Serial.print() etc. inside an interrupt service routine. I just put it there so I can see that it is called.
But without the unfavorable code inside the ISR the program behaves as described.

So the question remains why the first time the timer interrupt is enabled it doesn't work after an external interrupt is executed.

Now I've removed the Serial.print() related stuff from the ISR. The flags are somewhat redundant but show quite well what's going on.

Here's the updated code:

#include <avr/sleep.h>

// **************** Definitions ****************

// Push Button
#define BUTTON_INT          2
#define BUTTON              7

// Timer
#define TIMER_INTERVAL      3

// **************** Global Variables ****************
volatile bool buttonPress = false;
volatile bool buttonInt = false;
volatile bool timerInt = false;
volatile unsigned long timerCnt = 0;

unsigned int timeoutSeconds = 0;
volatile bool timeoutFlag = false;

enum wakeupSources
{
    EXTERNAL_INTERRUPT,
    TIMEOUT_INTERRUPT
};


// **************** Sleep and Wakeup, Interrupts and Timer2 ****************

// Interrupt INT0 for push button
void ISR_BUTTON(void)
{
    detachInterrupt(digitalPinToInterrupt(BUTTON_INT));
    buttonPress = true;
    buttonInt = true;                                                           // DEBUG
}

// Interrupt Timer2
ISR(TIMER2_COMPA_vect)
{
    static unsigned long counter = 0;

    counter++;
    if (counter >= ((unsigned long)(timeoutSeconds) * 40UL))
    {
        timeoutFlag = true;
        counter = 0;
        TIMSK2 = 0;                                                             // disable interrupt
    }

    timerInt = true;                                                            // DEBUG
    timerCnt = counter;                                                         // DEBUG

    return;
}

// Sleep
void enterSleep(wakeupSources source, unsigned int timeout_sec)
{
    Serial.print("\r\nenter sleep, wait for ");
    if (source == EXTERNAL_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
        Serial.print("EXT INT... ");

        buttonPress = false;
    }
    else if (source == TIMEOUT_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
        Serial.print("TMR INT... ");

        // Setup TMR2: interrupt every 25ms
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
        TCCR2B = 0;                                                             // set TCCRXB register to 0
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
        OCR2A = 194;                                                            // set compare match register of timer 2
        TCNT2 = 0;
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt

        timeoutSeconds = timeout_sec;
        timeoutFlag = false;
    }
    Serial.flush();

    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts

    sleep_bod_disable();
    do                                                                          // loops when timer interrupts
    {
        buttonInt = false;                                                      // DEBUG
        timerInt = false;                                                       // DEBUG
        cli();
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
        sleep_enable();
        sei();
        sleep_cpu();
        sleep_disable();
        if (buttonInt == true)                              Serial.print("iB"); // DEBUG
        if ((timerInt == true) && ((timerCnt & 0x02) != 0)) Serial.print(".");  // DEBUG
        Serial.flush();
    }
    while ( (buttonPress == false) && (timeoutFlag == false));

    Serial.println("-Wakeup");
    Serial.flush();

    return;
}


// **************** Setup ****************
void setup(void)
{
    Serial.begin(115200);
    Serial.println();
    Serial.println("\r\nHello!");

    // Button
    pinMode(BUTTON_INT, INPUT);                                                 // external pull-Up
    pinMode(BUTTON, INPUT);
}

// **************** Main ****************
void loop(void)
{
    enum wakeupSources wakeupSource;
    unsigned int wakeupTimeout;

    wakeupSource = EXTERNAL_INTERRUPT;                                          // initial wakeup source

    // -------- Push Button
    if (buttonPress == true)
    {
        buttonPress = false;
        Serial.println("button");

        while(digitalRead(BUTTON) == LOW)
            delay(100);

        wakeupSource = TIMEOUT_INTERRUPT;
        wakeupTimeout = TIMER_INTERVAL;
    }

    // -------- Timeout
    if (timeoutFlag == true)
    {
        static unsigned char timeoutCount = 0;
        
        timeoutFlag = false;
        timeoutCount++;
        Serial.print("timeout #"); Serial.println(timeoutCount);

        if (timeoutCount <= 2)
        {
            wakeupSource = TIMEOUT_INTERRUPT;
            wakeupTimeout = TIMER_INTERVAL;
        }
        else
        {
            timeoutCount=0;
            wakeupSource = EXTERNAL_INTERRUPT;
        }
    }

    // -------- Sleep
    enterSleep(wakeupSource, wakeupTimeout);
};

And this is the output of the serial monitor:


Hello!

enter sleep, wait for EXT INT... iB-Wakeup
button

enter sleep, wait for TMR INT... iB-Wakeup
button

enter sleep, wait for TMR INT... ............................................................-Wakeup
timeout #1

enter sleep, wait for TMR INT... ............................................................-Wakeup
timeout #2

enter sleep, wait for TMR INT... ............................................................-Wakeup
timeout #3

enter sleep, wait for EXT INT... 

Note the 2nd paragraph

enter sleep, wait for TMR INT... iB-Wakeup
button

Because the timer interrupt has been enabled I would expect the timer interrupt to be called, indicated by ............. Instead the wakeup has to be caused by a button press (external interrupt).

I hope this description is somewhat understandable.

So you had to press the external button a second time to get the 2nd paragraph? Otherwise, nothing?

Sorry for the late answer.
But that's correct: I have to push the button once (1st paragraph) then the timer interrupt is activated (2nd paragraph) but nothing happens until the button is pushed a second time (also 2nd paragraph).
Then the timer interrupt is activated again (3rd paragraph) and this time it is actually working.

As a quick and dirty fix of the problem I've enabled a dummy timer interrupt in setup(). And this is actually executed, i.e. it causes a wakeup.
But the next time the timer interrupt is enabled it is the same situation: It doesn't work any more.

Since this happens after the external interrupt it seems that there is some kind of conflict or interference.

Here's the new code with the change at the end of setup(). Also the multiple calls of the timer interrupt in main() has been removed for simplicity.

#include <avr/sleep.h>

// **************** Definitions ****************

// Push Button
#define BUTTON_INT          2
#define BUTTON              7

// Timer
#define TIMER_INTERVAL      3

// **************** Global Variables ****************
volatile bool buttonPress = false;
volatile bool buttonInt = false;
volatile bool timerInt = false;
volatile unsigned long timerCnt = 0;

unsigned int timeoutSeconds = 0;
volatile bool timeoutFlag = false;

enum wakeupSources
{
    EXTERNAL_INTERRUPT,
    TIMEOUT_INTERRUPT
};


// **************** Sleep and Wakeup, Interrupts and Timer2 ****************

// Interrupt INT0 for push button
void ISR_BUTTON(void)
{
    detachInterrupt(digitalPinToInterrupt(BUTTON_INT));
    buttonPress = true;
    buttonInt = true;                                                           // DEBUG
}

// Interrupt Timer2
ISR(TIMER2_COMPA_vect)
{
    static unsigned long counter = 0;

    counter++;
    if (counter >= ((unsigned long)(timeoutSeconds) * 40UL))
    {
        timeoutFlag = true;
        counter = 0;
        TIMSK2 = 0;                                                             // disable interrupt
    }

    timerInt = true;                                                            // DEBUG
    timerCnt = counter;                                                         // DEBUG

    return;
}

// Sleep
void enterSleep(wakeupSources source, unsigned int timeout_sec)
{
    Serial.print("\r\nenter sleep, wait for ");
    if (source == EXTERNAL_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
        Serial.print("EXT INT... ");

        buttonPress = false;
    }
    else if (source == TIMEOUT_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
        Serial.print("TMR INT... ");

        // Setup TMR2: interrupt every 25ms
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
        TCCR2B = 0;                                                             // set TCCRXB register to 0
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
        OCR2A = 194;                                                            // set compare match register of timer 2
        TCNT2 = 0;
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt

        timeoutSeconds = timeout_sec;
        timeoutFlag = false;
    }
    Serial.flush();

    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts

    sleep_bod_disable();
    do                                                                          // loops when timer interrupts
    {
        buttonInt = false;                                                      // DEBUG
        timerInt = false;                                                       // DEBUG
        cli();
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
        sleep_enable();
        sei();
        sleep_cpu();
        sleep_disable();
        if (buttonInt == true)                              Serial.print("iB"); // DEBUG
        if ((timerInt == true) && ((timerCnt & 0x02) != 0)) Serial.print(".");  // DEBUG
        Serial.flush();
    }
    while ( (buttonPress == false) && (timeoutFlag == false));

    Serial.println("-Wakeup");
    Serial.flush();

    return;
}


// **************** Setup ****************
void setup(void)
{
    Serial.begin(115200);
    Serial.println();
    Serial.println("\r\nHello!");

    // Button
    pinMode(BUTTON_INT, INPUT);                                                 // external pull-Up
    pinMode(BUTTON, INPUT);

    enterSleep(TIMEOUT_INTERRUPT, 0);                                           // This works!
    timeoutFlag = 0;                                                            // But 2nd call in main() doesn't !?

    Serial.println("End of setup()");
}

// **************** Main ****************
void loop(void)
{
    enum wakeupSources wakeupSource;
    unsigned int wakeupTimeout;

    wakeupSource = EXTERNAL_INTERRUPT;                                          // initial wakeup source

    // -------- Push Button
    if (buttonPress == true)
    {
        buttonPress = false;
        Serial.println("button");

        while(digitalRead(BUTTON) == LOW)
            delay(100);

        wakeupSource = TIMEOUT_INTERRUPT;
        wakeupTimeout = TIMER_INTERVAL;
    }

    // -------- Timeout
    if (timeoutFlag == true)
    {
        timeoutFlag = false;
        wakeupSource = EXTERNAL_INTERRUPT;
        Serial.println("timeout");
    }

    // -------- Sleep
    enterSleep(wakeupSource, wakeupTimeout);
};

Here's the output:


Hello!

enter sleep, wait for TMR INT... -Wakeup
End of setup()

enter sleep, wait for EXT INT... iB-Wakeup
button

enter sleep, wait for TMR INT... iB-Wakeup
button

enter sleep, wait for TMR INT... iB-Wakeup
button

enter sleep, wait for TMR INT... ........................................................-Wakeup
timeout

enter sleep, wait for EXT INT... 

The first paragraph shows the timer wakeup in setup().
Then main() is entered and the first call of the timer interrupt doesn't work again.

I've made some progress but still don't know the reason for this strange behaviour.
I've added other debug output to enterSleep() to show the value of TIMSK2 at different stages:

void enterSleep(wakeupSources source, unsigned int timeout_sec)
{
    Serial.print("\r\nenter sleep, wait for ");
    if (source == EXTERNAL_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);                                    // wakeup by ext. interrupt + WDT
        Serial.print("EXT INT... ");
        Serial.println();                                                       // DEBUG
        Serial.print("TIMSK2-A= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
        buttonPress = false;
    }
    else if (source == TIMEOUT_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
        Serial.print("TMR INT... ");
        Serial.println();                                                       // DEBUG
        Serial.print("TIMSK2-B= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
        // Setup TMR2: interrupt every 25ms
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
        TCCR2B = 0;                                                             // set TCCRXB register to 0
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
        OCR2A = 194;                                                            // set compare match register of timer 2
        TCNT2 = 0;
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
        TIMSK2 |= (1 << OCIE2A);                                                // enable timer2 compare interrupt
        Serial.print("TIMSK2-C= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
        TIMSK2 |= (1 << OCIE2A);                                                // DEBUG
        Serial.print("TIMSK2-D= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG

        timeoutSeconds = timeout_sec;
        timeoutFlag = false;
    }
    Serial.print("TIMSK2-E= 0b"); Serial.println(TIMSK2, BIN);                  // DEBUG
    Serial.flush();

    EIFR |= (1 << INTF0);                                                       // clear pending external interrupts

    sleep_bod_disable();
    do                                                                          // loops when timer interrupts
    {
        buttonInt = false;                                                      // DEBUG
        timerInt = false;                                                       // DEBUG
        cli();
        attachInterrupt(digitalPinToInterrupt(BUTTON_INT), ISR_BUTTON, LOW);    // power down accepts level-interrupts only
        sleep_enable();
        sei();
        sleep_cpu();
        sleep_disable();
        if (buttonInt == true)                              Serial.print("iB"); // DEBUG
        if ((timerInt == true) && ((timerCnt & 0x02) != 0)) Serial.print(":");  // DEBUG
        Serial.flush();
    }
    while ( (buttonPress == false) && (timeoutFlag == false));

    Serial.println("-Wakeup");
    Serial.flush();

    return;
}

The output is this:

Hello!

enter sleep, wait for TMR INT... 
TIMSK2-B= 0b0
TIMSK2-C= 0b10
TIMSK2-D= 0b10
TIMSK2-E= 0b10
-Wakeup
End of setup()

enter sleep, wait for EXT INT... 
TIMSK2-A= 0b0
TIMSK2-E= 0b0
iB-Wakeup
button

enter sleep, wait for TMR INT... 
TIMSK2-B= 0b0
TIMSK2-C= 0b0
TIMSK2-D= 0b10
TIMSK2-E= 0b10
............................................................-Wakeup
timeout

enter sleep, wait for EXT INT... 
TIMSK2-A= 0b0
TIMSK2-E= 0b0

The interesting part is the second befor last paragraph (before the .....):
TIMSK2 is written with the result that it still is 0x00 (output TIMSK2-C). Then it is written again but now the result is as it should be (output TIMSK-D).

The question is why writing TIMSK2 doesn't succeed at all times.

Embedding the first assignment in cli() and sei() doesn't change things:

        cli();
        TIMSK2 |= (1 << OCIE2A);
        sei();

To make sure that nothing strange happens I've extended the cli() / sei() to include the serial.print() and also, I've disabled the second write to the register:

else if (source == TIMEOUT_INTERRUPT)
    {
        set_sleep_mode(SLEEP_MODE_PWR_SAVE);                                    // also wakeup by TMR2
        Serial.print("TMR INT... ");
        Serial.println();                                                       // DEBUG
        Serial.print("TIMSK2-B= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
        // Setup TMR2: interrupt every 25ms
        // https://arduino.stackexchange.com/questions/53298/timer2-compare-interrupt-not-working-as-expected
        TCCR2B = 0;                                                             // set TCCRXB register to 0
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode
        OCR2A = 194;                                                            // set compare match register of timer 2
        TCNT2 = 0;
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
        cli();
        TIMSK2 |= (1 << OCIE2A);
        Serial.print("TIMSK2-C= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG
        sei();
//        TIMSK2 |= (1 << OCIE2A);                                                // DEBUG
//        Serial.print("TIMSK2-D= 0b"); Serial.println(TIMSK2, BIN);              // DEBUG

        timeoutSeconds = timeout_sec;
        timeoutFlag = false;
    }
    Serial.print("TIMSK2-E= 0b"); Serial.println(TIMSK2, BIN);                  // DEBUG
    Serial.flush();

The output is very interesting:

enter sleep, wait for TMR INT... 
TIMSK2-B= 0b0
TIMSK2-C= 0b10
TIMSK2-E= 0b0

According to this writing TIMSK2 is successful (output TIMSK2-C). The second write access has been commented out. But in the end the register is 0x00 again and no interrupt is triggered.

The output is the same even if Serial.print() of TIMSK2-E also is embedded in another pair of cli() and sei().

So who or what resets the TIMSK2 register?

Finally I've found the reason for this strange behaviour:
A timer interrupt occurs while configuring the timer. So the solution is to disable interrupts during timer configuration and to clear the timer interrupt flag.
With this everything works fine now.

The timer setup looks like this:

        cli();
        // Setup TMR2: interrupt every 25ms
        TCCR2B = 0;                                                             // stop the timer and reset WGM22
        TCCR2A |= (1 << WGM21);                                                 // enable timer2 CTC mode with top in OCR2A
        OCR2A = 194;                                                            // set compare match register of timer 2
        TCNT2 = 0;                                                              // initialize counter value to 0
        TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);                      // 1:1024 prescaling for timer 2
        TIFR2 |= (1 << OCF2A);
        TIMSK2 |= (1 << OCIE2A);
        sei();

Thanks for any suggestions!