Skip to main content
Visitor II
February 28, 2025
Solved

Receiving a NMAK when reading out WhoAmI register - lsm6dsox

  • February 28, 2025
  • 1 reply
  • 493 views

Hi everyone,

I am currently trying to get a lsm6dsox to interface with a Nordic nRF52833 board using i2c communication. I am looking to read accelerometer/gyro values.

I am able to write to the sensor but I am unable to read from the sensor without receiving a NMAK. 

I am using the STEVAL-MKI217V1 adapter board to connect to my nRF52833.

I have connected the VDD/VDDIO pins to VCC, my SCL/SDA pins to the pins I configured for i2c communication, I have connected CS to VDD, GND pins to GND, and SDO to ground. 

This is my result from the Logic analyzer

 
Screenshot 2025-02-28 175333.png

This is my source code:

Main.c:

/*
 * Copyright (c) 2020 Yestin Sun
 *
 * SPDX-License-Identifier: Apache-2.0
 */

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

static inline float out_ev(struct sensor_value *val)
{
    return (val->val1 + (float)val->val2 / 1000000);
}

static void fetch_and_display(const struct device *dev)
{
    struct sensor_value x, y, z;
    static int trig_cnt;

    trig_cnt++;

    /* lsm6dso accel */
    sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ);
    sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &x);
    sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &y);
    sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &z);

    printf("accel x:%f ms/2 y:%f ms/2 z:%f ms/2\n",
            (double)out_ev(&x), (double)out_ev(&y), (double)out_ev(&z));

    /* lsm6dso gyro */
    sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ);
    sensor_channel_get(dev, SENSOR_CHAN_GYRO_X, &x);
    sensor_channel_get(dev, SENSOR_CHAN_GYRO_Y, &y);
    sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &z);

    printf("gyro x:%f rad/s y:%f rad/s z:%f rad/s\n",
            (double)out_ev(&x), (double)out_ev(&y), (double)out_ev(&z));

    printf("trig_cnt:%d\n\n", trig_cnt);
}

static int set_sampling_freq(const struct device *dev)
{
    int ret = 0;
    struct sensor_value odr_attr;

    /* set accel/gyro sampling frequency to 12.5 Hz */
    odr_attr.val1 = 12.5;
    odr_attr.val2 = 0;

    ret = sensor_attr_set(dev, SENSOR_CHAN_ACCEL_XYZ,
            SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr);
    if (ret != 0) {
        printf("Cannot set sampling frequency for accelerometer.\n");
        return ret;
    }

    ret = sensor_attr_set(dev, SENSOR_CHAN_GYRO_XYZ,
            SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr);
    if (ret != 0) {
        printf("Cannot set sampling frequency for gyro.\n");
        return ret;
    }

    return 0;
}

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

static void test_trigger_mode(const struct device *dev)
{
    struct sensor_trigger trig;

    if (set_sampling_freq(dev) != 0)
        return;

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

    if (sensor_trigger_set(dev, &trig, trigger_handler) != 0) {
        printf("Could not set sensor type and channel\n");
        return;
    }
}

#else
static void test_polling_mode(const struct device *dev)
{
    if (set_sampling_freq(dev) != 0) {
        return;
    }

    while (1) {
        fetch_and_display(dev);
        k_sleep(K_MSEC(1000));
    }
}
#endif

int main(void)
{
    const struct device *const dev = DEVICE_DT_GET_ONE(st_lsm6dso);

    if (!device_is_ready(dev)) {
        printk("%s: device not ready.\n", dev->name);
        return 0;
    }

#ifdef CONFIG_LSM6DSO_TRIGGER
    printf("Testing LSM6DSO sensor in trigger mode.\n\n");
    test_trigger_mode(dev);
#else
    printf("Testing LSM6DSO sensor in polling mode.\n\n");
    test_polling_mode(dev);
#endif
    return 0;
}
 
Overlay file:
#include <zephyr/dt-bindings/sensor/lsm6dso.h>
&i2c0 {
    status = "okay";
    compatible = "nordic,nrf-twim";
    pinctrl-0 = <&i2c0_default>;
    pinctrl-1 = <&i2c0_sleep>;
    pinctrl-names = "default", "sleep";
    lsm6dsox:lsm6dsox@6A {
        compatible = "st,lsm6dso";
        status = "ok";
        label = "LSM6DSO";
        reg = <0x6A>;
        accel-odr = <LSM6DSO_DT_ODR_1Hz6>;
    };
};
&pinctrl {
    i2c0_default: i2c0_default {
        group1  {
            psels = <NRF_PSEL(TWIM_SCL, 0, 27)>, <NRF_PSEL(TWIM_SDA, 0, 26)>;
            bias-pull-up;
        };
    };

    i2c0_sleep: i2c0_sleep {
        group1  {
            psels = <NRF_PSEL(TWIM_SCL, 0, 27)>,
                    <NRF_PSEL(TWIM_SDA, 0, 26)>;
            low-power-enable;
        };
    };
};
 
Is there something I am missing to ensure that I can read via i2c?
I appreciate anyone's help as I am very stuck on this.
Thanks,
Regina
Best answer by Federica Bossi

Hi @ReginaA101 ,

As written in LSM6DSOX DS, in the description of I2C communication, for READs transactions, the last ACK is a NotMasterACK.

FedericaBossi_0-1741364290147.jpeg

I think that the protocol communication analyzer is not able to discriminate between slave and master ACKs.

1 reply

Federica Bossi
Federica BossiBest answer
Technical Moderator
March 7, 2025

Hi @ReginaA101 ,

As written in LSM6DSOX DS, in the description of I2C communication, for READs transactions, the last ACK is a NotMasterACK.

FedericaBossi_0-1741364290147.jpeg

I think that the protocol communication analyzer is not able to discriminate between slave and master ACKs.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.