ADXL345 over SPI Not Working

I cannot get an ADXL345 (Adafruit breakout) to work with an NRF52840DK over SPI (Zephyr). Wiring is normal: SCK -> P1.5 MOSI -> P1.6, MISO 1.7 and CS 1.8

This is my .overlay:

&pinctrl {
spi1_default: spi1_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 5)>,
<NRF_PSEL(SPIM_MOSI, 1, 6)>,
<NRF_PSEL(SPIM_MISO, 1, 7)>;
};
};
spi1_sleep: spi1_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 5)>,
<NRF_PSEL(SPIM_MOSI, 1, 6)>,
<NRF_PSEL(SPIM_MISO, 1, 7)>;
low-power-enable;
};
};
};

&spi1 {
compatible = "nordic,nrf-spi";
status = "okay";
cs-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
adxl345: adxl345@0 {
compatible = "adi,adxl345";
status = "okay";
reg = <0>;
spi-max-frequency = <2000000>;
};
};

This is the prj.conf:

CONFIG_CPP=y
CONFIG_LOG=y
CONFIG_SENSOR=y
CONFIG_GPIO=y
CONFIG_SPI=y

And this is the C++ implementation:

#include <stdlib.h>
#include <stdio.h>

#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/drivers/spi.h>

#include <zephyr/bluetooth/gatt.h>

/** Use standard Zephyr logging. */
LOG_MODULE_REGISTER(adxl345);

#define SLEEP_TIME_MS 500

static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_NODELABEL(led0), gpios);
static const struct device *adxl345 = DEVICE_DT_GET(DT_NODELABEL(adxl345));

int main()
{
    int rc;

    if (!device_is_ready(led.port)) {
        LOG_ERR("The LED is not ready.");

        return EXIT_FAILURE;
    }

    if ((rc = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE)) < 0) {
        LOG_ERR("Failed to configure pin %d (error %d).", led.pin, rc);

        return EXIT_FAILURE;
    }


    if (!device_is_ready(adxl345)) {
        LOG_ERR("The ADXL345 sensor is not ready.");

        return EXIT_FAILURE;
    }

    LOG_INF("Entering the main loop.");
    while (1) {
        struct sensor_value sensor_value_accel_xyz[3];

        sensor_sample_fetch(adxl345);

        sensor_channel_get(adxl345, SENSOR_CHAN_ACCEL_XYZ, sensor_value_accel_xyz);

        float accel_x = sensor_value_to_float(&sensor_value_accel_xyz[0]);
        float accel_y = sensor_value_to_float(&sensor_value_accel_xyz[1]);
        float accel_z = sensor_value_to_float(&sensor_value_accel_xyz[2]);

        LOG_INF("x: %f, y: %f, z: %f", static_cast<double>(accel_x), static_cast<double>(accel_y), static_cast<double>(accel_z));

        if ((rc = gpio_pin_toggle_dt(&led)) < 0) {
            LOG_ERR("Failed to toggle pin %d (error %d).", led.pin, rc);
        }

        k_msleep(SLEEP_TIME_MS);
    }
    return EXIT_SUCCESS;
}

This is the output:

[00:00:00.434,661] <err> ADXL345: Read PART ID failed: 0xcb (0)

*** Booting Zephyr OS build v3.7.0-2948-g96386eac0ba2 ***
[00:00:00.434,722] <err> adxl345: The ADXL345 sensor is not ready.

or

[00:00:00.251,983] <inf> adxl345: Entering the main loop.
[29:00:50.034,698] <err> spi_nrfx_spi: Timeout waiting for transfer complete
[29:00:50.034,729] <err> ADXL345: Samples read failed with rc=-116
[29:00:50.034,729] <err> ADXL345: Failed to fetch sample rc=-116
[29:00:50.034,790] <inf> adxl345: x: -16.242264, y: -16.242264, z: -16.242264

Something strange is going on with the SPI. I was wondering if you have any ideas?

  • It seems like you have correctly set up the SPI communication in your device tree overlay file and your C++ implementation seems to be in order as well. However, the error messages indicate that there might be an issue with the SPI communication itself.

    One possible issue could be the SPI clock speed. According to a this thread, the ADXL345 datasheet specifies that the maximum SPI clock speed is 5 MHz with 100 pF maximum loading, and the timing scheme follows clock polarity (CPOL) = 1 and clock phase (CPHA) = 1. You might want to check if these settings match with your current configuration.
    Another possible issue could be the wiring or the GPIO pin configuration. As mentioned here, that the GPIO pins used for the CS line should not be defined in the SPI samples when using SPIS. Instead, the driver expects to use the hardware CS line embedded in the SPI transceiver hardware.
    It might be helpful to further debug the SPI communication to identify the root cause of the problem. You could use an oscilloscope or a logic analyzer to check the SPI signals, or add some debug prints in your code to check the values of the SPI registers and buffers.
Related