Getting zeros from ISM330DHCX accelerometers

Hello,

I am trying to read ISM330DHCX accelerometer (Adafruit product) data using nRF522832 but I am getting zeros all the time regardless whether the sensor is moved or not.  I am following the I2C protocol.  I can read the sensor on Arduino.  The sensor has pull up resistors for both SDA and SCL.

Here is the overlay file:

&i2c0 {
    mysensor: mysensor@6A{
        compatible = "i2c-device";
        reg = < 0x6A >;
        label = "MYSENSOR";
    };
};
Here is the main.c:
#include <zephyr/types.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/sys/printk.h>
#include <zephyr/kernel.h>

#define ISM330DHCX_I2C_ADDR 0x6A

// Define the I2C device specification
static const struct i2c_dt_spec i2c_dev = I2C_DT_SPEC_GET(DT_NODELABEL(mysensor));

static int ism330dhcx_init(void)
{
    uint8_t who_am_i;
    uint8_t config1[] = {
        0x10, // CTRL1_XL register address
        0x60  // 104 Hz, ±4g, Normal mode
    };

    // Write to CTRL1_XL to configure accelerometer
    int ret = i2c_write_dt(&i2c_dev, config1, sizeof(config1));
    if (ret != 0) {
        printk("Failed to configure ISM330DHCX CTRL1_XL (error: %d)\n", ret);
        return -EIO;
    }

    // Read WHO_AM_I register (0x0F)
    uint8_t reg_addr = 0x0F;
    ret = i2c_write_dt(&i2c_dev, &reg_addr, sizeof(reg_addr));
    if (ret != 0) {
        printk("Failed to set WHO_AM_I register address (error: %d)\n", ret);
        return -EIO;
    }

    ret = i2c_read_dt(&i2c_dev, &who_am_i, sizeof(who_am_i));
    if (ret != 0) {
        printk("Failed to read WHO_AM_I register from I2C device address %x\n", i2c_dev.addr);
        return -EIO;
    }

    printk("WHO_AM_I register value: 0x%02x\n", who_am_i);

    if (who_am_i != 0x6B) {
        printk("WHO_AM_I register mismatch: expected 0x6B, got 0x%02x\n", who_am_i);
        return -EIO;
    }

    printk("ISM330DHCX initialized successfully\n");
    return 0;
}

static int ism330dhcx_read(int16_t *ax, int16_t *ay, int16_t *az)
{
    uint8_t buffer[6];
    uint8_t status;
    int ret;

    // Check data ready status
    uint8_t reg_addr = 0x1E;
    ret = i2c_write_dt(&i2c_dev, &reg_addr, sizeof(reg_addr));
    if (ret != 0) {
        printk("Failed to set STATUS_REG address (error: %d)\n", ret);
        return -EIO;
    }

    ret = i2c_read_dt(&i2c_dev, &status, sizeof(status));
    if (ret != 0) {
        printk("Failed to read STATUS_REG from I2C device address %x\n", i2c_dev.addr);
        return -EIO;
    }

    if (!(status & 0x01)) {
        printk("No new accelerometer data available\n");
        return -EIO;
    }

    // Read accelerometer data starting from register 0x28
    reg_addr = 0x28 | 0x80; // 0x80 sets the auto-increment bit
    ret = i2c_write_dt(&i2c_dev, &reg_addr, sizeof(reg_addr));
    if (ret != 0) {
        printk("Failed to set accelerometer data start address (error: %d)\n", ret);
        return -EIO;
    }

    ret = i2c_read_dt(&i2c_dev, buffer, sizeof(buffer));
    if (ret != 0) {
        printk("Failed to read accelerometer data from I2C device address %x\n", i2c_dev.addr);
        return -EIO;
    }

    *ax = (int16_t)(buffer[0] | (buffer[1] << 8));
    *ay = (int16_t)(buffer[2] | (buffer[3] << 8));
    *az = (int16_t)(buffer[4] | (buffer[5] << 8));

    printk("Raw data read: X=%d, Y=%d, Z=%d\n", *ax, *ay, *az);

    return 0;
}

void main(void)
{
    int err;

    printk("Starting minimal ISM330DHCX example\n");

    if (!device_is_ready(i2c_dev.bus)) {
        printk("I2C device not found\n");
        return;
    }

    err = ism330dhcx_init();
    if (err) {
        printk("Failed to initialize ISM330DHCX\n");
        return;
    }

    int16_t raw_x, raw_y, raw_z;
    while (1) {
        err = ism330dhcx_read(&raw_x, &raw_y, &raw_z);
        if (err == 0) {
            printk("Accelerometer Data - X: %d, Y: %d, Z: %d\n", raw_x, raw_y, raw_z);
        } else {
            printk("Failed to read accelerometer data\n");
        }

        k_sleep(K_MSEC(500)); // Sleep for 500 milliseconds before reading again
    }
}


A screenshot of the VCode 


  • Hello,

    The default pin for i2C0 is SDA(26) and SCL (27) on nRf52832. Have you checked the pin set up?

    There is an existing a driver for this sensor

    https://github.com/nrfconnect/sdk-zephyr/tree/main/drivers/sensor/st/ism330dhcx; Is the sensor is correctly configured in your project's configuration file. The ISM330DHCX sensor should be enabled with CONFIG_ISM330DHCX=y.

  • Hello Kazi, 

    Thank you so much for bring this to my attention.  I was not aware there was a driver for sensors from ST.  I was under the impression that Zephyr/nRF drivers is capable by itself in handling it.  

    At first when I added CONFIG_ISM330DHCX=y in project configuration file (prj.conf), an error popped up and I was not sure.  The moment I built/flashed the kit, there was no error.  I finally made it work. Thank you so much Kazi!

    Here is my final code for others who might run into same issue or first time in nRF and ST sensors:

    main.c

    #include <zephyr/device.h>
    #include <zephyr/drivers/i2c.h>
    #include <zephyr/drivers/sensor.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/kernel.h>
    
    #define ISM330DHCX_I2C_ADDR 0x6A
    
    void main(void)
    {
        const struct device *sensor = DEVICE_DT_GET_ONE(st_ism330dhcx);
        int ret;
    
        if (!device_is_ready(sensor)) {
            printk("Sensor device not found\n");
            return;
        }
    
        // Example setup for 104 Hz ODR, ±4g full scale
        uint8_t config1[] = {0x10, 0x88}; // CTRL1_XL: ODR=104 Hz, FS=±4g
        struct i2c_dt_spec i2c_dev = I2C_DT_SPEC_GET(DT_NODELABEL(mysensor));
        ret = i2c_write_dt(&i2c_dev, config1, sizeof(config1));
        if (ret != 0) {
            printk("Failed to configure ISM330DHCX CTRL1_XL (error: %d)\n", ret);
            return;
        } else {
            printk("ISM330DHCX configured successfully\n");
        }
    
        uint8_t raw_data[6];
        struct sensor_value accel[3];
    
        while (1) {
            ret = sensor_sample_fetch(sensor);
            if (ret) {
                printk("Sensor sample update error: %d\n", ret);
                continue;
            }
    
            // Read raw accelerometer data registers directly
            ret = i2c_burst_read(i2c_dev.bus, ISM330DHCX_I2C_ADDR, 0x28, raw_data, sizeof(raw_data));
            if (ret == 0) {
                // printk("Raw data: X_L=%02x X_H=%02x Y_L=%02x Y_H=%02x Z_L=%02x Z_H=%02x\n",
                //     raw_data[0], raw_data[1],
                //     raw_data[2], raw_data[3],
                //     raw_data[4], raw_data[5]);
    
                // Interpret the raw data into signed 16-bit integers
                int16_t raw_x = (int16_t)(raw_data[1] << 8 | raw_data[0]);
                int16_t raw_y = (int16_t)(raw_data[3] << 8 | raw_data[2]);
                int16_t raw_z = (int16_t)(raw_data[5] << 8 | raw_data[4]);
    
                // printk("Raw interpreted data: X=%d, Y=%d, Z=%d\n", raw_x, raw_y, raw_z);
    
                // Convert raw values to m/s^2 ( 1g = 9.80665 m/s^2)
                // const double scale = 9.80665 / 2050.0; // Convert from raw to m/s^2 - 16g
                const double scale = 9.80665 / 8197; // Convert from raw to m/s^2 - 4g
                double accel_x = raw_x * scale;
                double accel_y = raw_y * scale;
                double accel_z = raw_z * scale;
    
                printk("Acceleration (m/s^2): X=%.6f, Y=%.6f, Z=%.6f\n", accel_x, accel_y, accel_z);
            } else {
                printk("Failed to read raw data\n");
            }
    
            k_sleep(K_MSEC(300)); // Sleep for 500 milliseconds before reading again
        }
    }

    nrf52dk_nrf522832.overlay

    &i2c0 {
        status = "okay";
        mysensor: ism330dhcx@6a {
            compatible = "st,ism330dhcx";
            reg = <0x6a>;
            label = "ISM330DHCX";
        };
    };

    prj.conf (I do not believe you need all in the list)

    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    
    CONFIG_BT=y
    CONFIG_LOG=y
    CONFIG_BT_SMP=y
    CONFIG_BT_SIGNING=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_DIS=y
    CONFIG_BT_ATT_PREPARE_COUNT=5
    CONFIG_BT_BAS=y
    CONFIG_BT_HRS=y
    CONFIG_BT_IAS=y
    CONFIG_BT_PRIVACY=n
    CONFIG_BT_DEVICE_NAME="My_nRF52_Device"
    CONFIG_BT_DEVICE_APPEARANCE=833
    CONFIG_BT_DEVICE_NAME_DYNAMIC=y
    CONFIG_BT_DEVICE_NAME_MAX=65
    
    CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    
    CONFIG_BT_PERIPHERAL_PREF_MIN_INT=96
    CONFIG_BT_PERIPHERAL_PREF_MAX_INT=96
    
    CONFIG_GPIO=y  # Add this line for GPIO support
    
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    
    CONFIG_I2C=y
    CONFIG_I2C_NRFX=y
    CONFIG_SENSOR=y
    
    CONFIG_ISM330DHCX=y
    
    CONFIG_LOG=y
    CONFIG_PRINTK=y
    CONFIG_CBPRINTF_FP_SUPPORT=y








Related