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?
