I am trying to use 4 pairs of I2C on nRF5340, why is one behaving differently?

Hello,

As mentioned in the title, I am trying to use 4 pairs of I2C on nRF5340. Each of the four I2C pairs will be connected to a TCA9548A (I2C MUX), but that is not important.

In the test program, each of the four pairs of I2C are threaded, so they should be processed in parallel.
I copy main.c below. I know that .overlay file and prj.conf are also needed, but copying them all would be redundant.
So I attach the entire project with zip.

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include "twim.h"
#include "tca9548a.h"

LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

// Device
#if defined(CONFIG_NRFX_TWIM0)
static const struct device *dev_twim0 = DEVICE_DT_GET(DT_NODELABEL(i2c0));
#endif
#if defined(CONFIG_NRFX_TWIM1)
static const struct device *dev_twim1 = DEVICE_DT_GET(DT_NODELABEL(i2c1));
#endif
#if defined(CONFIG_NRFX_TWIM2)
static const struct device *dev_twim2 = DEVICE_DT_GET(DT_NODELABEL(i2c2));
#endif
#if defined(CONFIG_NRFX_TWIM3)
static const struct device *dev_twim3 = DEVICE_DT_GET(DT_NODELABEL(i2c3));
#endif

static void imu_sensors_init(const struct device *dev)
{
	int err;
	uint8_t twim_buffer[8] = {0};

	// No.1
	twim_buffer[0] = CHANNEL0_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.1 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.1 has been initialized.");
	}

	// No.2
	twim_buffer[0] = CHANNEL1_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.2 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.2 has been initialized.");
	}

	// No.3
	twim_buffer[0] = CHANNEL2_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.3 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.3 has been initialized.");
	}

	// No.4
	twim_buffer[0] = CHANNEL3_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.4 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.4 has been initialized.");
	}

	// No.5
	twim_buffer[0] = CHANNEL4_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.5 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.5 has been initialized.");
	}

	// No.6
	twim_buffer[0] = CHANNEL5_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.6 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.6 has been initialized.");
	}

	// No.7
	twim_buffer[0] = CHANNEL6_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.7 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.7 has been initialized.");
	}

	// No.8
	twim_buffer[0] = CHANNEL7_ENABLED;
	err = twim_write_noreg(dev, TCA9548A_ADDR0, twim_buffer, 1);
	if (err < 0) {
		LOG_ERR("Failed to initialize I2C No.8 on %s.(%d)",dev->name, err);
	} else {
		LOG_INF("I2C No.8 has been initialized.");
	}
}

#if defined(CONFIG_NRFX_TWIM0)
static void sensors_init_twim0_work_thread(void)
{
	// Initialize IMU sensor(s)
	imu_sensors_init(dev_twim0);
}
K_THREAD_DEFINE(sensors_init_twim0, 1024, sensors_init_twim0_work_thread, NULL, NULL, NULL, K_PRIO_PREEMPT(15), 0, 0);
#endif

#if defined(CONFIG_NRFX_TWIM1)
static void sensors_init_twim1_work_thread(void)
{
	// Initialize IMU sensor(s)
	imu_sensors_init(dev_twim1);
}
K_THREAD_DEFINE(sensors_init_twim1, 1024, sensors_init_twim1_work_thread, NULL, NULL, NULL, K_PRIO_PREEMPT(15), 0, 0);
#endif

#if defined(CONFIG_NRFX_TWIM2)
static void sensors_init_twim2_work_thread(void)
{
	// Initialize IMU sensor(s)
	imu_sensors_init(dev_twim2);
}
K_THREAD_DEFINE(sensors_init_twim2, 1024, sensors_init_twim2_work_thread, NULL, NULL, NULL, K_PRIO_PREEMPT(15), 0, 0);
#endif

#if defined(CONFIG_NRFX_TWIM3)
static void sensors_init_twim3_work_thread(void)
{
	// Initialize IMU sensor(s)
	imu_sensors_init(dev_twim3);
}
K_THREAD_DEFINE(sensors_init_twim3, 1024, sensors_init_twim3_work_thread, NULL, NULL, NULL, K_PRIO_PREEMPT(15), 0, 0);
#endif

int main(void)
{
	// Settings
	if (IS_ENABLED(CONFIG_SETTINGS)) {
		LOG_INF("Settings have been loaded.");
		settings_load();
	}

	// Main loop
	while (true) {
		k_sleep(K_MSEC(500));
	}
}

4857.prj.zip

Since nothing is connected to the nRF7002 (nRF5340) evaluation board, this test program should produce an I2C error. As mentioned earlier, the four sets of I2C are threaded, so they are processed in parallel, so the error should occur in parallel. In fact, three of the four pairs (i2c1 to i2c3) output errors in parallel.
But only i2c0 behaves strangely. I think it is being processed in parallel, but the response time is very long.
My ideal error output would be

Error on i2c0
Error on i2c1
Error on i2c2
Error on i2c3
...
...
Error on i2c0
Error on i2c1
Error on i2c2
Error on i2c3

But here's the actual log

SEGGER J-Link V7.94e - Real time terminal output
SEGGER J-Link (unknown) V1.0, SN=1050716044
Process: JLink.exe
*** Booting nRF Connect SDK v2.7.0-5cb85570ca43 ***
*** Using Zephyr OS v3.6.99-100befc70c74 ***
[00:00:08.892,608] <inf> main: Settings have been loaded.
[00:00:08.893,371] <err> main: Failed to initialize I2C No.1 on i2c@9000.(-5)
[00:00:08.893,554] <err> main: Failed to initialize I2C No.1 on i2c@b000.(-5)
[00:00:08.893,615] <err> main: Failed to initialize I2C No.1 on i2c@c000.(-5)
[00:00:08.893,829] <err> main: Failed to initialize I2C No.2 on i2c@9000.(-5)
[00:00:08.893,951] <err> main: Failed to initialize I2C No.2 on i2c@b000.(-5)
[00:00:08.894,012] <err> main: Failed to initialize I2C No.2 on i2c@c000.(-5)
[00:00:08.894,226] <err> main: Failed to initialize I2C No.3 on i2c@9000.(-5)
[00:00:08.894,348] <err> main: Failed to initialize I2C No.3 on i2c@b000.(-5)
[00:00:08.894,409] <err> main: Failed to initialize I2C No.3 on i2c@c000.(-5)
[00:00:08.894,622] <err> main: Failed to initialize I2C No.4 on i2c@9000.(-5)
[00:00:08.896,728] <err> main: Failed to initialize I2C No.4 on i2c@b000.(-5)
[00:00:08.896,850] <err> main: Failed to initialize I2C No.4 on i2c@c000.(-5)
[00:00:08.897,064] <err> main: Failed to initialize I2C No.5 on i2c@9000.(-5)
[00:00:08.897,247] <err> main: Failed to initialize I2C No.5 on i2c@b000.(-5)
[00:00:08.897,369] <err> main: Failed to initialize I2C No.5 on i2c@c000.(-5)
[00:00:08.897,460] <err> main: Failed to initialize I2C No.6 on i2c@9000.(-5)
[00:00:08.897,644] <err> main: Failed to initialize I2C No.6 on i2c@b000.(-5)
[00:00:08.897,766] <err> main: Failed to initialize I2C No.6 on i2c@c000.(-5)
[00:00:08.897,827] <err> main: Failed to initialize I2C No.7 on i2c@9000.(-5)
[00:00:08.898,071] <err> main: Failed to initialize I2C No.7 on i2c@b000.(-5)
[00:00:08.898,712] <err> main: Failed to initialize I2C No.7 on i2c@c000.(-5)
[00:00:08.898,803] <err> main: Failed to initialize I2C No.8 on i2c@9000.(-5)
[00:00:08.898,986] <err> main: Failed to initialize I2C No.8 on i2c@b000.(-5)
[00:00:08.899,047] <err> main: Failed to initialize I2C No.8 on i2c@c000.(-5)
[00:00:09.393,432] <err> main: Failed to initialize I2C No.1 on i2c@8000.(-5)
[00:00:09.893,829] <err> main: Failed to initialize I2C No.2 on i2c@8000.(-5)
[00:00:10.394,226] <err> main: Failed to initialize I2C No.3 on i2c@8000.(-5)
[00:00:10.894,622] <err> main: Failed to initialize I2C No.4 on i2c@8000.(-5)
[00:00:11.395,019] <err> main: Failed to initialize I2C No.5 on i2c@8000.(-5)
[00:00:11.895,416] <err> main: Failed to initialize I2C No.6 on i2c@8000.(-5)
[00:00:12.395,812] <err> main: Failed to initialize I2C No.7 on i2c@8000.(-5)
[00:00:12.896,209] <err> main: Failed to initialize I2C No.8 on i2c@8000.(-5)

Considering the elapsed time in the log, it appears that only i2c0 is taking 0.5 seconds per error.

Why is this?
I don't think it is conflicting because I have disabled Uart0, but I think there might be something going on.
Or am I missing some setting?

Parents
  • Hi Yoshihiro

    This seemed very strange at first, but I think this could be related to the pins you've chosen for the I2C0 instance, as these by default are used by the 32.768kHz crystal and thus might behave a bit differently. I can't see in your project that you've set the nRF53 to use the internal RC oscillator instead of the external LF crystal which is the default by setting CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y

    If you have, and I've just missed it, I would either way try using some other GPIOs than P0.00 and P0.01 as the I2C0 GPIOs to check if the same behavior is seen on any pins or just these two.

    Best regards,

    Simon

Reply
  • Hi Yoshihiro

    This seemed very strange at first, but I think this could be related to the pins you've chosen for the I2C0 instance, as these by default are used by the 32.768kHz crystal and thus might behave a bit differently. I can't see in your project that you've set the nRF53 to use the internal RC oscillator instead of the external LF crystal which is the default by setting CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y

    If you have, and I've just missed it, I would either way try using some other GPIOs than P0.00 and P0.01 as the I2C0 GPIOs to check if the same behavior is seen on any pins or just these two.

    Best regards,

    Simon

Children
Related