I2C write-restart-read issue on nRF Connect SDK v3.2.x

Hello,

The following code performs an I2C write-restart-read operation that works correctly on a NRF52840 devkit with ncs v3.1.1, but fails with ncs v3.2.0 and v3.2.1. Note that this code works correctly on stock Zephyr versions v4.2.0 and v4.3.0, so the problem seems to be specific to nRF Connect SDK.

The I2C slave being used is a rs3028 RTC being driven directly (without the Zephyr sensor driver), but I imagine that the problem is independent of the I2C peripheral.

The project is adapted from ncs/v3.1.1/zephyr/samples/drivers/i2c/target_eeprom, where main.c has been replaced by:

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/i2c/target/eeprom.h>

static const struct i2c_dt_spec spec_i2c_clock = I2C_DT_SPEC_GET(DT_NODELABEL(i2cclock));

void write_read_blocking(void* out_data, size_t out_size, void* in_data, size_t in_size) {
    struct i2c_msg msg[2] = {
        {
            .buf = out_data,
            .len = out_size,
            .flags = I2C_MSG_WRITE,
        },
        {
            .buf = in_data,
            .len = in_size,
            .flags = I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP,
        },
    };

    // int retval = i2c_write_read_dt(&spec(), out_data, out_size, in_data, in_size);
    int retval = i2c_transfer_dt(&spec_i2c_clock, msg, 2);
	printk("retval: %d\n", retval);
}

int main(void)
{
	printk("i2c target sample\n");

	if (!i2c_is_ready_dt(&spec_i2c_clock)) {
		printk("I2C device not ready\n");
		return 0;
	}

	k_msleep(1000);

	uint8_t out[] = {0x00, };
	uint8_t in[7];

	write_read_blocking(out, sizeof(out), in, sizeof(in));

	return 0;
}

Both the i2c_write_read_dt and i2c_transfer_dt variants were tried, resulting in the same behavior. Here is the i2c.overlay file:

&spi0 { status = "disabled"; };
&spi1 { status = "disabled"; };
&spi2 { status = "disabled"; };

&i2c0 { status = "disabled"; };

&i2c1 {
	status = "okay";

	i2cclock: i2cclock@68 {
		compatible = "i2c-device";
		label = "I2CCLOCK";
		reg = <0x68>;
	};
};

And the build command:

west build -b nrf52840dk/nrf52840 -- -D DTC_OVERLAY_FILE=i2c.overlay

On ncs v3.1.1, one observes that the 52840 correctly writes the byte 0 to device 0x68, performs an I2C restart, and then reads 7 bytes of calendar data:

On ncs v3.2.1 and v3.2.0, one observes that the 52840 correctly writes the byte 0 to device 0x68, performs an I2C restart, and then terminates with retval=-5 (not clocking the read operation).

I am using nRF-Connect on Ubuntu 24.04.3 LTS, installed using the command-line approach described here:

https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/installation/install_ncs.html

  • Hello,

    I have tried your sample on nRF52840dk (with modified C code and the device tree) for both NCS v2.1.1 and NCS v3.1.1. My system is windows.

    Overlay file name: nrf52840dk_nrf52840.overlay

    Build command: west build -p -b nrf52840dk/nrf5284

    The application built and flashed ok.

    I got same output for both version

    In your application, you choose i2c1, so the SDA and SCL pin should show the output on the pin P 0.30 and P0.21 according to nRF52840 board file.

    Can you please share which pins you are using for seeing SDA and SCL output on logic analyser?

  • Hi, I am measuring the signals on P0.30 and P0.31.

    If you don't have an rv3028 RTC connected to these pins, it's normal that it would fail in both cases. If you have another I2C peripheral handy, you can change the address in the device tree overlay (and perhaps slightly adapt the main.c to read some other registers) and try with your own peripheral.

  • Hello,

    Can you try the following overlay to use the ''nordic,nrf-twim'' driver?

    &i2c1 {
        status = "okay";
        compatible = "nordic,nrf-twim"; <-- this line is added
        i2cclock: i2cclock@68 {
            compatible = "i2c-device";
            label = "I2CCLOCK";
            reg = <0x68>;
        };
    };

  • I think I have the same issue on SDK 3.2.1. I'm trying to complete the nRF Connect SDK Fundamentals lesson 6 exercise 1, and it's failing. My logic analyzer shows almost identical to yours. Address and single byte written get ACK, and then it returns with an error code, and lets the bus rise into "inactive" (no stop bit, no restart attempt).

    I tried adding debugging I2C with CONFIG_I2C_LOG_LEVEL_DBG=y which didn't give me answers. I tried disabling the SPI interfaces, I tried both I2C0 and I2C1 with no change. I ensured there are no device tree IO pin conflicts with the I2C pins. I tried i2c_write_read_dt (from the exercise) as well as i2c_write_dt, and both look good on the logic analyzer (including ACK), but both missing the restart/stop. I tried on both an nRF52832 and nRF52840. I even tried skipping the zephyr I2C drivers and configuring the registers directly with nrfx_twim_init, nrfx_twim_enable, and nrfx_twim_xfer.

    After several days of frustration and trying to track it down, I realized it works perfectly well on SDK 3.1.1, so something must have broken at 3.2.0 and/or 3.2.1

    Edit: I also looked at the analog levels of the I2C signals to ensure they are crisp and well within voltage expectations, and even tried multiple sets of pullup resistors from ~910 ohms up to 10k ohms. Changing pullup resistors didn't seem to make any difference in the outcome (still failed the same), although I could see the corresponding changes to the rise time of the signals on the oscilloscope. 10k looks a little weak for my setup, but on SDK 3.1.1 it still works perfectly fine.

  • Hello mt37,

    Can you show me the error log?

    Did you try to add the fix I mentioned in my (compatible = "nordic,nrf-twim";) reply? Also, you need to add bias-pull-up in the device tree file if you use internal pull-up resistor.

Related