Does I2C/TWI conflict with Timer1

I wonder if it is me doing something wrong or it is a general thing. But does the use of the Wire library conflict with using Timer1 on a Nano?

If I perform the I2C communication outside an ISR then everything works flawlessly but if done inside the program crashes.

What I want to achieve is a simple, but interrupt controlled, setting of a control device. I have no need of reading anything via I2C. Below is a sample code.

void ControlDevice() 
{
    Wire.beginTransmission(0x5A);
    Wire.write(2);  // Send start register

    Wire.write(7);

    Wire.endTransmission();
} 

ISR(TIMER1_COMPA_vect)    // Timer1 compare interrupt
{
    i++;
    ControlDevice();
    if (i >= maxI)
        done = true;
}

void DoControl()
{
    noInterrupts();
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;

    OCR1A = 25000;                 // 16 MHz/64/10
    TCCR1B = 0b00001011;           // CTC mode and 64 prescaler 
    TIMSK1 |= (1 << OCIE1A);       // Enable timer compare interrupt

    done = false;
    interrupts();

    while (!done);

    TIMSK1 = 0;
}

If I comment out Wire.endTransmission(); the program continues to run but the device does not get the end of transmission thus does no do what it is supposed to.

Thanks in advance.

The wire.endTransmission does the actual sending.
It returns an integer that indicates the status of the transmission.

what does it return?

void ControlDevice() 
{
    Wire.beginTransmission(0x5A);
    Wire.write(2);  // Send start register

    Wire.write(7);

    int x = Wire.endTransmission();
    Serial.println(x, DEC);
}

Unfortunately I cannot even get the return value of Wire.endTransmission(). The program stops before this happens.

dived a bit more into your (incomplete) code:

You call the I2C transmission from within an interrupt routine.

Better set a flag in the ISR and check that flag in loop to see if you need to send.
give it a try.

Also the comparison of i with some max value to set the done flag, better move the comparison to the blocking while(!done) ==> while (i<max);

Advise is keep the ISR as small as possible, otherwise you can get the situation that the ISR is called again before it is finished. ...

If you want more help post the complete code, including a description what you want to accomplish.

Sorry, there is a response the first time and it is 0. So according to this everything works. I have also tried with endTransmission(true) but the program still halts.

I would sat that I need to send to the I2C device almost every time. So I cannot skip it. OK I could do a bit optimization but perhaps less than 10% of the time.

A note: If I do the same with SPI I have no problems.

I will do some more investigations and be back.

The Wire library and I2C require interrupts to be enabled, but they are disabled within the ISR. Calling ControlDevice() from within the ISR will not work.

As Rob suggested, use the ISR to set a flag, and then check for that flag within the loop.

Hi cattledog and Rob

Thanks for the answers.

Pity that I2C needs interrupt when SPI doesn't. I will investigate my options 1) flag in ISR and evoke the ControlDevice() in the while loop and clear flag, or 2) I2C bit banging. I have plenty of time from interrupt to interrupt.

Hmm, if I enable global interrupts inside the ISR it works. Perhaps a bit of Jolly Roger programming but it looks safe so far.