Cannot read chip id for LIS3DH chip via I2C

Hello, I am using the LIS2DH sample (and the st,lis2dh driver, which is compatible with the LIS3DH accelerometer) to test out a LIS3DH IC attached to a custom board. However I keep getting the following error:

SEGGER J-Link V8.96 - Real time terminal output
SEGGER J-Link V12.0, SN=822000525
Process: JLinkExe
[00:00:00.265,258] <err> lis2dh: Failed to read chip id.
*** Booting nRF Connect SDK v3.2.1-d8887f6f32df ***
*** Using Zephyr OS v4.2.99-ec78104f1569 ***
Device LIS3DH is not ready

In our board (snippets from the schematic attached), the SDA and SCL lines are wired to GPIO P0.12 and P0.11 respectively. INT1, INT2 are wired to P0.07 and P0.08. SD0 is connected to P0.04. CS' is pulled high and I am not asserting it because he datasheet says that it must be tied high for I2C.

My goal is to get the sample running (reading data via the zephyr/drivers/sensor.h API). I am using the default dts for nrf52dk_nrf52832 with a device tree overlay:

&i2c0 {
	status = "okay";
	pinctrl-0 = <&i2c0_default>;
	pinctrl-1 = <&i2c0_sleep>;
	pinctrl-names = "default", "sleep";

	lis2dh@19 {
		compatible = "st,lis2dh";
		reg = <0x19>;
		label = "LIS3DH";
		irq-gpios = <&gpio0 7 GPIO_ACTIVE_LOW>, <&gpio0 8 GPIO_ACTIVE_LOW>; /* INT1 -> P0.07, INT2 -> P0.08  */
	};
};

&pinctrl {
	i2c0_default {
		group1 {
			psels = <NRF_PSEL(TWIM_SDA, 0, 12)>, /* SDA -> P0.12 */
					<NRF_PSEL(TWIM_SCL, 0, 11)>; /* SCL -> P0.11 */
		};
	};

	i2c0_sleep {
		group1 {
			psels = <NRF_PSEL(TWIM_SDA, 0, 12)>, 
					<NRF_PSEL(TWIM_SCL, 0, 11)>;
		};
	};
};

With the following prj.conf:

CONFIG_STDOUT_CONSOLE=y
CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_REBOOT=y

CONFIG_LOG=y
CONFIG_LOG_PRINTK=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y

and my main.c is:

/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <inttypes.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/reboot.h>

LOG_MODULE_REGISTER(generallogs,LOG_LEVEL_DBG);

static void fetch_and_display(const struct device *sensor)
{
	static unsigned int count;
	struct sensor_value accel[3];
	struct sensor_value temperature;
	const char *overrun = "";
	int rc = sensor_sample_fetch(sensor);

	++count;
	if (rc == -EBADMSG) {
		/* Sample overrun.  Ignore in polled mode. */
		if (IS_ENABLED(CONFIG_LIS2DH_TRIGGER)) {
			overrun = "[OVERRUN] ";
		}
		rc = 0;
	}
	if (rc == 0) {
		rc = sensor_channel_get(sensor,
					SENSOR_CHAN_ACCEL_XYZ,
					accel);
	}
	if (rc < 0) {
		printk("ERROR: Update failed: %d\n", rc);
	} else {
		printk("#%u @ %u ms: %sx %f , y %f , z %f",
		       count, k_uptime_get_32(), overrun,
		       sensor_value_to_double(&accel[0]),
		       sensor_value_to_double(&accel[1]),
		       sensor_value_to_double(&accel[2]));
	}

	if (IS_ENABLED(CONFIG_LIS2DH_MEASURE_TEMPERATURE)) {
		if (rc == 0) {
			rc = sensor_channel_get(sensor, SENSOR_CHAN_DIE_TEMP, &temperature);
			if (rc < 0) {
				printk("\nERROR: Unable to read temperature:%d\n", rc);
			} else {
				printk(", t %f\n", sensor_value_to_double(&temperature));
			}
		}

	} else {
		printk("\n");
	}
}

#ifdef CONFIG_LIS2DH_TRIGGER
static void trigger_handler(const struct device *dev,
			    const struct sensor_trigger *trig)
{
	fetch_and_display(dev);
}
#endif

int main(void)
{
	const struct device *const sensor = DEVICE_DT_GET_ANY(st_lis2dh);

	if (sensor == NULL) {
		printk("No device found\n");
		return 0;
	}
	if (!device_is_ready(sensor)) {
		printk("Device %s is not ready\n", sensor->name);
		k_msleep(2000); /* Reboot if fails. */
		sys_reboot(SYS_REBOOT_WARM);
	}

#if CONFIG_LIS2DH_TRIGGER
	{
		struct sensor_trigger trig;
		int rc;

		trig.type = SENSOR_TRIG_DATA_READY;
		trig.chan = SENSOR_CHAN_ACCEL_XYZ;

		if (IS_ENABLED(CONFIG_LIS2DH_ODR_RUNTIME)) {
			struct sensor_value odr = {
				.val1 = 1,
			};

			rc = sensor_attr_set(sensor, trig.chan,
					     SENSOR_ATTR_SAMPLING_FREQUENCY,
					     &odr);
			if (rc != 0) {
				printk("Failed to set odr: %d\n", rc);
				return 0;
			}
			printk("Sampling at %u Hz\n", odr.val1);
		}

		rc = sensor_trigger_set(sensor, &trig, trigger_handler);
		if (rc != 0) {
			printk("Failed to set trigger: %d\n", rc);
			return 0;
		}

		printk("Waiting for triggers\n");
		while (true) {
			k_sleep(K_MSEC(2000));
		}
	}
#else /* CONFIG_LIS2DH_TRIGGER */
	printk("Polling at 0.5 Hz\n");
	while (true) {
		fetch_and_display(sensor);
		k_sleep(K_MSEC(2000));
	}
#endif /* CONFIG_LIS2DH_TRIGGER */
}

based on a similar problem posed in another ticket I have added a reset command in the block where the device driver is not ready. The user reported that this approach worked for him but it keeps on failing in a loop for me.

If there is anything wrong that stands out in the above snippets, it would be great to know. Thank you for your time!

Parents
  • Try changing the irq-gpios to e.g. 26 and 27, to see if it makes a difference. If you are currently using UART logging, then the pins 07 and 08 is used by the UART. You can see on the back of the DK what pins that are used by default.

    Best regards,

    Edvin

  • Hi Edvin, thank you for the response. I am not using UART for logging because our board doesnt have UART pins exposed (and power consumption reasons) - only SWD pins so we use RTT for all our logging. I made the changes that you mentioned but I'm the same result as before. I could share the schematic for the LIS3DH itself if you want to have a look.

  • Ok. It was worth a shot. Did you disable the UART logging? (It will be on by default).

    If yes, have you tried scoping the I2C lines to see if there is any traffic, or if it fails before that?

    You are not able to reproduce this on a DK? Do you have a breakout board for the lis2dh?

    Best regards,

    Edvin

  • Hi thank you for your patience. UART logging was disabled. We might need to examine the I2C lines. We are thinking of procuring a separate breakout board and testing it out on a DK. Will keep you posted.

    Also, if I am not mistaken the wiring provided can also be used with SPI?

  • nik2k said:
    UART logging was disabled.

    Also make sure that the UART itself is disabled, as it will be enabled by default:

    &uart0 {
        status = "disabled";
    }

    in addition to disabling the UART logging in prj.conf.

    nik2k said:
    the wiring provided can also be used with SPI?

    From the nRF52832's perspective, yes. As long as they are not being used by any other peripherals (UART). Just remember that the pins P0.09 and P0.10 by default. You can use them, but it requires you to add this to your .overlay file:

    &uicr {
        nfct-pins-as-gpios;
    };

    (If you are using a DK, you need to modify the kit according to this description. (remove some 0R resistors, and solder them onto R27 and R28 on the DK).

    Best regards,

    Edvin

Reply
  • nik2k said:
    UART logging was disabled.

    Also make sure that the UART itself is disabled, as it will be enabled by default:

    &uart0 {
        status = "disabled";
    }

    in addition to disabling the UART logging in prj.conf.

    nik2k said:
    the wiring provided can also be used with SPI?

    From the nRF52832's perspective, yes. As long as they are not being used by any other peripherals (UART). Just remember that the pins P0.09 and P0.10 by default. You can use them, but it requires you to add this to your .overlay file:

    &uicr {
        nfct-pins-as-gpios;
    };

    (If you are using a DK, you need to modify the kit according to this description. (remove some 0R resistors, and solder them onto R27 and R28 on the DK).

    Best regards,

    Edvin

Children
No Data
Related