NRF9160 I2C/TWI recovery and microsecond resolution timer

Hi,

Something locks-up my I2C sometimes and I need to make I2C recovery. It looks like Nordic has not implemented the zephyr i2c_recover_bus function, so I guess I need to make it manually?

I've already drafted a somehow working code:

static inline void wait() {
  for (int i = 0; i < 60; i++) {
    __asm__("nop");
  }
}

void recover_i2c() {
  const struct device* gpio_dev = NULL;
  gpio_dev = device_get_binding("GPIO_0");
  if (gpio_dev == NULL) {
    k_panic();
  }
  int err = gpio_pin_configure(gpio_dev, I2C_SCL, GPIO_OUTPUT);
  if (err < 0) {
    LOG_ERR("I2C recover, GPIO configure failed: %d", err);
  }
  for (int i = 0; i < 10; i++) {
    err = gpio_pin_set(gpio_dev, I2C_SCL, 0);
    if (err < 0) {
      LOG_ERR("I2C recover, GPIO set failed: %d", err);
    }
    wait();
    err = gpio_pin_set(gpio_dev, I2C_SCL, 1);
    if (err < 0) {
      LOG_ERR("I2C recover, GPIO set failed: %d", err);
    }
    wait();
  }
  err = gpio_pin_configure(gpio_dev, I2C_SCL, GPIO_DISCONNECTED);
  if (err < 0) {
    LOG_ERR("I2C recover, GPIO configure failed: %d", err);
  }
  k_sleep(K_MSEC(1));
}

But I am not very comfortable with it. It looks like k_usleep does not work(sleeping 5us can take 30us), so I just pulled the wait loop out from thin air. Internet and my brains tell me that it is very bad idea. So the actual questions:

- There is no built in I2C recovery in NRD91 SDK, right?

- What is the preferred way to do it? Capture the I2C pin to GPIO like that? Or maybe convert I2C clock to PWM on the fly? Can you do that?

- If the preferred way needs a microsecond resolution timing, what is the correct way to do that?

Related