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?