How to recover an I2C bus when SDA is stuck low? Edit: SDA line stuck high See edit at the end of the message.

I have an Arduino in master mode connected via I2c to a slave, with 2k pull-up resistors on SDA and SCL. Sometimes the SDA line is stuck low, which causes my program to hang indefinitely.

How to recover from such a scenario?

Edit1: Since the SDA line is tied low the problem probably comes from the master. My guess is that the slave waits for the rest of the clock pulses that never come.

I'm not using the Wire library. I wrote my own implementation based on the AMmega328P datasheet.

void TWIInit() {
  TWSR = 0x00;
  TWBR = 0x48; // SCL = 100khz
  TWCR = (1 &lt;&lt; TWEN);
}

void TWIStart() {
  TWCR = (1 &lt;&lt; TWINT) | (1 &lt;&lt; TWSTA) | (1 &lt;&lt; TWEN);
  while ((TWCR &amp; (1 &lt;&lt; TWINT)) == 0);
}

void TWIStop() {
  TWCR = (1 &lt;&lt; TWINT) | (1 &lt;&lt; TWSTO) | (1 &lt;&lt; TWEN);
  while (TWCR &amp; (1 &lt;&lt; TWSTO));
}

void TWIWrite(uint8_t data) {
  TWDR = uint8_data;
  TWCR = (1 &lt;&lt; TWINT) | (1 &lt;&lt; TWEN);
  while ((TWCR &amp; (1 &lt;&lt; TWINT)) == 0);
}
unsigned int TWIReadACK() {
  TWCR = (1 &lt;&lt; TWINT) | (1 &lt;&lt; TWEN) | (1 &lt;&lt; TWEA);
  while ((TWCR &amp; (1 &lt;&lt; TWINT)) == 0);
  return TWDR;
}

unsigned int TWIReadNACK() {
  TWCR = (1 &lt;&lt; TWINT) | (1 &lt;&lt; TWEN);
  while ((TWCR &amp; (1 &lt;&lt; TWINT)) == 0);
  return TWDR;
}

unsigned int TWIGetStatus() {
  unsigned int statusOfRegister;
  statusOfRegister = TWSR &amp; 0xF8;
  return statusOfRegister;
}

int TWISendBytes(uint8_t slaveAddr, uint8_t regAddr, uint8_t buf[], int numbBytes) {
  TWIStart();
  if (TWIGetStatus() != 0x08) {
    TWIStop();
    return 1;
  }
  // send address and Write bit
  TWIWrite(slaveAddr &amp; 0xFE);
  if (TWIGetStatus() != 0x18) {
    TWIStop();
    return 1;
  }
  // send the register address
  TWIWrite(regAddr);
  if (TWIGetStatus() != 0x28) {
    TWIStop();
    return 1;
  }
  // send bytes
  for (int i = 0; i &lt; numbBytes; i++) {
    TWIWrite(buf[i]);
    if (TWIGetStatus() != 0x28) {
      TWIStop();
      return 1;
    }
  }
  TWIStop();
  return 0;
}

int TWIGetBytes(uint8_t slaveAddr, uint8_t regAddr, uint8_t buf[], int numbBytes) {
  TWIStart();
  if (TWIGetStatus() != 0x08) {
    TWIStop();
    return 1;
  }
  // send address and Write bit
  TWIWrite(slaveAddr &amp; 0xFE);
  if (TWIGetStatus() != 0x18) {
    TWIStop();
    return 1;
  }
  // send the register address
  TWIWrite(regAddr);
  if (TWIGetStatus() != 0x28) {
    TWIStop();
    return 1;
  }
  // repeated start
  TWIStart();
  if (TWIGetStatus() != 0x10) {
    TWIStop();
    return 1;
  }
  // send address and Read bit
  TWIWrite(slaveAddr | 0x01);
  if (TWIGetStatus() != 0x40) {
    TWIStop();
    return 1;
  }
  // get bytes
  for (int i = 0; i &lt; numbBytes; i++) {
    if (i == (numbBytes - 1)) {
      buf[i] = TWIReadNACK();
      if (TWIGetStatus() != 0x58) {
        TWIStop();
        return 1;
      }
    } else {
      buf[i] = TWIReadACK();
      if (TWIGetStatus() != 0x50) {
        TWIStop();
        return 1;
      }
    }
  }
  TWIStop();
  return 0;
}


Edit2: The SDA line, and SCL, is held high not low as I first incorrectly assumed (I probably did something wrong when I measured it and thought it was low but anyway.) The problem was that the resistors I was using as pull-up resistors were in fact 1k not 2k. I changed them for 2k resistors and the problem disappeared.
I solved the problem by replacing the pull-up resistors with 2k Ohm resistors. I thought I connected 2k Ohm resistors when in fact their value was 1k. So sometimes the SDA line couldn't be driven low due to the too strong pull-up resistors and that caused the hanging.