How to properly use interruptions with twi (I2C) I would like to reprogram Wire.h, or a part, to use interruptions, in order to not waste time to wait. I'm using an Arduino Mega with an Adafruit motor shield v2.3.

In the datasheet, page 262, 24.9.2, bit 0, I can read that I have to set the TWIE flag to one to be able to catch the interruption.

So, I started to write this code :

//https://www.arduino.cc/en/uploads/Main/arduino-mega-schematic.pdf

#include &lt;avr/interrupt.h&gt;

#define ADDRSHIELD 0xC0//adresse sur 8 bits

#define TWI_FREQ 100000L
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &amp;= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |=  _BV(bit))

#define START       0x08  //TWI start
#define MT_SLA_ACK  0x18   //slave ACK has been received
#define MT_DATA_ACK 0x28   //master ACK has been received

#define LED0_ON_L 0x6

#define TWI_STATUS      (TWSR &amp; 0xF8)

int etat = 0;
uint8_t currentstep = 0;
uint8_t _addr;
uint8_t _data;

ISR(TWI_vect)
{
  //I remove the TWINT flag
  TWCR |= (1&lt;&lt;TWINT);

  switch(etat)
  {
    case 0:
      //start has been send, let's check if it's ok
      if(TWI_STATUS == START)
      {
        //on charge l'adresse dans TWDR et on clear le bit TWINT dans TWCR pour demarrer la transmission
        TWDR = _addr;
        TWCR = _BV(TWIE) | _BV(TWEN);
        etat = 1;
        //Serial.println(etat);
      }
      else
      {
        etat = -1;
      }
      break;
    //addr has been send
    case 1:
      if(TWI_STATUS == MT_SLA_ACK)
      {
        TWDR = _data;
        TWCR = _BV(TWIE) | _BV(TWEN);
        etat = 2;
        //Serial.println(etat);
      }
      else
      {
        etat = -2;
      }
      break;
    //data have been send
    case 2:
      if(TWI_STATUS == MT_DATA_ACK)
      {
        // disable twi module, acks, and twi interrupt
        TWCR = (1&lt;&lt;TWIE)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWSTO);
        etat = 3;
        //Serial.println(etat);
      }
      else
      {
        etat = -3;
      }
      break;
    //stop condition
    case 3:
      // desactivate internal pullups for twi.
      digitalWrite(SDA, 0);
      digitalWrite(SCL, 0);
      etat = 0;
      //Serial.println(etat);
      //Serial.println("Next");
      break;
  }
}


void sendData(uint8_t addr, uint8_t data)
{
  _addr = addr;
  _data = data;

  i2cSetup();
  //start condition
  TWCR = (1&lt;&lt;TWSTA)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWIE);
}

void i2cSetup(void)
{
  // activate internal pull-ups for twi
  sbi(PORTD, 0);
  sbi(PORTD, 1);

  // initialize twi prescaler and bit rate
  cbi(TWSR, TWPS0);
  cbi(TWSR, TWPS1);

  TWBR = ((F_CPU / 100000) - 16) / 2;
}

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  if(etat == 0)
  {
    sendData(0xC0, 0b1010101);
  }
  if(etat == 3)
  {
      Serial.println("Next");
  }  
  if(etat == -1)
  {
    Serial.println("Error from start");
    delay(100);
    exit(-1);
  }  
  if(etat == -2)
  {
    Serial.println("NACK");
    delay(100);
    exit(-1);
  }  
  if(etat == -3)
  {
    Serial.println("DATA NACK");
    delay(100);
    exit(-1);
  }  
}


My problem is, once I reset TWIE to one on my interruption, the code looks like to freeze(in ISR(), case 0, TWCR =...). In my mind, the interruption is call only when TWIE is set to one and when the twi module says (when he sets TWINT to one I guess) that he finished the job. I don't understand how to properly use this interruption.

EDIT : 
Thanks to @jfpoilpret, know I clearly know the problem, the slave doesn't reply by an acknowledge (in my switch, case 0, the status isn't equal to START (0x08)). In the datasheet, p246, they clearly explain how to use registers, but I'm not sure how to use the flag TWIE. I don't know if I have to set them both to one, or if i have to completely leave TWINT (I tried both, but nothing worked...).

Thanks for your help,
julien
After some tests, it's working !
First off all, I used Serial.println in my ISR, that's made it freeze apparently.
Second, apparently, I can't send more than 6 bits, else I'll have an error (data NACK), I thought it was 8.

This is my code working :

//https://www.arduino.cc/en/uploads/Main/arduino-mega-schematic.pdf

#include &lt;avr/interrupt.h&gt;

#define ADDRSHIELD 0xC0//adresse sur 8 bits

#define TWI_FREQ 100000L
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &amp;= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |=  _BV(bit))

#define START       0x08  //TWI start
#define MT_SLA_ACK  0x18   //slave ACK has been received
#define MT_DATA_ACK 0x28   //master ACK has been received

#define LED0_ON_L 0x6

#define TWI_STATUS      (TWSR &amp; 0xF8)

volatile int8_t etat = 0;
volatile uint8_t _addr;
volatile uint8_t _data;

ISR(TWI_vect)
{
  switch(etat)
  {
    case 0:
      //start has been send, let's check if it's ok
      if(TWI_STATUS == START)
      {
        //on charge l'adresse dans TWDR et on clear le bit TWINT dans TWCR pour demarrer la transmission
        TWDR = _addr;
        TWCR = _BV(TWIE) | _BV(TWEN);
        etat = 1;
      }
      else
        etat = -1;
      break;
    //addr has been send
    case 1:
      if(TWI_STATUS == MT_SLA_ACK)
      {
        TWDR = _data;
        TWCR = _BV(TWIE) | _BV(TWEN);
        etat = 2;
      }
      else
        etat = -2;
      break;
    //data have been send
    case 2:
      if(TWI_STATUS == MT_DATA_ACK)
      {
        // disable twi module, acks, and twi interrupt
        TWCR = (1&lt;&lt;TWIE)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWSTO);
        etat = 3;
      }
      else
        etat = -3;
      break;
    //stop condition
    case 3:
      // desactivate internal pullups for twi.
      digitalWrite(SDA, 0);
      digitalWrite(SCL, 0);
      etat = 0;
      break;
  }
  //I remove the TWINT flag
  TWCR |= (1&lt;&lt;TWINT);
}


void sendData(uint8_t addr, uint8_t data)
{
  _addr = addr;
  _data = data;

  i2cSetup();
  //start condition
  TWCR = (1&lt;&lt;TWSTA)|(1&lt;&lt;TWEN)|(1&lt;&lt;TWIE)|(1&lt;&lt;TWINT);
}

void i2cSetup(void)
{
  // activate internal pull-ups for twi
  sbi(PORTD, 0);
  sbi(PORTD, 1);

  // initialize twi prescaler and bit rate
  cbi(TWSR, TWPS0);
  cbi(TWSR, TWPS1);

  TWBR = ((F_CPU / 100000) - 16) / 2;
}

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  if(etat == 0)
  {
    sendData(0xC0, 0b0010101);
  }
  if(etat == 3)
  {
      Serial.println("Next");
  }

  if(etat == -1)
  {
    Serial.println("Error from start");
    delay(100);
    exit(-1);
  }  
  if(etat == -2)
  {
    Serial.println("NACK");
    delay(100);
    exit(-1);
  }  
  if(etat == -3)
  {
    Serial.println("DATA NACK");
    delay(100);
    exit(-1);
  }  
}


Thanks a lot to jfpoilpret !