Incorrect SPI reads and inconsistent behavior on nRF54L15-DK when communicating with external sensor (ADXL372)

I'm using NCS v2.9.0 and attempting to communicate with an ADXL372 IMU over SPI. Occasionally, the MCU successfully reads from the IMU and begins printing values. However, most of the time it either fails during initialization with a "failed to read device ID" error or stalls while fetching data.

Initially, I suspected a clock polarity/phase mismatch or a breadboarding issue, but after troubleshooting these seem unlikely. The problem appears to be specific to the nRF54L15-DK when used with this sensor. I’ve experimented with various settings, including clock speed, high-drive mode, polling/trigger modes, pull-up/pull-down resistors, and soft/hard resets. Regardless of the configuration, the program remains "consistently inconsistent." I've also tried:

  • Testing communication with the ADXL372 IMU using different pins on the nRF54L15-DK (same issue)
  • Testing communication with the ADXL372 IMU using the same pins on a backup nRF54L15-DK (same issue)
  • Testing communication with a different IMU using the same pins on the nRF54L15-DK (works)
  • Testing communication with the ADXL372 IMU on an nRF52840-DK (works)

The IMU does correctly send data. Its expected IDs are 0xAD and 0xFA, the logic analyzer output reads 0xAD and 0xFA, but the Zephyr driver errors because the values it reads are 0x80 and 0xF8:

Does anyone know what the source of this issue could be? I've included my overlay, prj.conf, and main below.

/delete-node/ &mx25r64;

&spi00 {
	status = "disabled";
};

&spi21 {
	status = "okay";
	pinctrl-0 = <&spi21_default>;
	pinctrl-names = "default";
	cs-gpios = <&gpio2 10 (GPIO_ACTIVE_LOW | (1 << 8))>;
	adxl372@0 {
		compatible = "adi,adxl372";
		reg = <0x0>;
		spi-max-frequency = <DT_FREQ_M(8)>;
		int1-gpios = <&gpio0 0 0>;
		odr = <4>;
		bw = <4>;
		hpf = <0>;
		zephyr,deferred-init;
	};
};

&pinctrl {
	spi21_default: spi21_default {

		group2 {
			psels = <NRF_PSEL(SPIM_MISO, 1, 11)>;
			bias-pull-up;
		};

		group1 {
			psels = <NRF_PSEL(SPIM_SCK, 1, 8)>, <NRF_PSEL(SPIM_MOSI, 1, 12)>;
			nordic,drive-mode = <NRF_DRIVE_H0S1>;
		};
	};
};

CONFIG_STDOUT_CONSOLE=y
CONFIG_LOG=y
CONFIG_LOG_BACKEND_UART=y
CONFIG_LOG_MODE_IMMEDIATE=n
CONFIG_SENSOR_LOG_LEVEL_DBG=y
CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_LOG_PRINTK=y

CONFIG_SPI=y
CONFIG_SENSOR=y
CONFIG_ADXL372=y
CONFIG_ADXL372_TRIGGER_GLOBAL_THREAD=n
CONFIG_ADXL372_MEASUREMENT_MODE=y
CONFIG_CBPRINTF_FP_SUPPORT=y

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>

static void fetch_and_display(const struct device *sensor)
{
	printf("fetch_and_display\n");
    int rc = sensor_sample_fetch(sensor);
    printf("rc: %d\n", rc);
}

#ifdef CONFIG_ADXL372_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(adi_adxl372);
	k_sleep(K_MSEC(500));
	device_init(sensor);

	if (sensor == NULL) {
		printf("No device found\n");
		return 0;
	}
	if (!device_is_ready(sensor)) {
		printf("Device %s is not ready\n", sensor->name);
		return 0;
	}

#if CONFIG_ADXL372_TRIGGER
	{
		struct sensor_trigger trig;
		int rc;

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

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

		printf("Waiting for triggers\n");
		while (true) {
			k_sleep(K_MSEC(2000));
		}
	}
#else /* CONFIG_ADXL372_TRIGGER */
	printf("Polling at 2 Hz\n");
	while (true) {
		fetch_and_display(sensor);
		k_sleep(K_MSEC(500));
	}
#endif /* CONFIG_ADXL372_TRIGGER */
}

Parents
  • I managed to capture a better representation of the problem. Here I am using the nRF54L15-DK, ADXL372, and a Saleae LA. Right before 2s, I set SW4 on the DK to the "ON" position to enable power. The two devices communicate properly until I press the "RESET" button on the DK at around 11.5s. In the same exact conditions, the board no longer reads from the ADXL372 properly.

    Full session:

    Power on:

    After reset:

    Could it be related to this anomaly?

    54l15dk_adxl372_comm.sal

  • Thanks for all this information Marcus, Seems like the SPI master on the nRF54L15 is somewhat different than on nRF52840. Can you please give me your full project so that I can replicate this and investigate to see if this is a known anomaly with a workaround or if this is something we can fix with some other initialization configurations.

  • Hi Susheel,

    This turned out to be a problem with the specific IC, at least as far as I can tell. Using a new ADXL372 breakout worked, and works consistently across all builds and DKs now. I'm still not sure why the original only had problems on nRF54L15-DKs but I'm unable to replicate it with another ADXL372 so the problem is more or less solved on my end. Although, I'm happy to provide the firmware anyway if you still want to look into this further. I would just need to remove some of the proprietary details from the code -- let me know.

Reply
  • Hi Susheel,

    This turned out to be a problem with the specific IC, at least as far as I can tell. Using a new ADXL372 breakout worked, and works consistently across all builds and DKs now. I'm still not sure why the original only had problems on nRF54L15-DKs but I'm unable to replicate it with another ADXL372 so the problem is more or less solved on my end. Although, I'm happy to provide the firmware anyway if you still want to look into this further. I would just need to remove some of the proprietary details from the code -- let me know.

Children
  • Marcus,

    Thanks for that info, we have seen some sensor boards behave different in such a small way that the edge sensing seems a bit different with our particular soc. In this case the faulty breakout board seem to have wrong polarity at some particular instance which seems to have highlighted on nRF54L15 due to its more accurate clock mechanism. In other variants, this small issue was somehow masked. We do not need to debug this as you said that this happens on one (very few) custom boards. This is not an issue on the nRF side. 

Related