Re: lsm6dsl full registers access #sensor #sst26


Lawrence King
 

At a high level, between the sensor driver you found in drivers/sensor/lsm6dsl and your program, Zephyr provides an interface layer that makes the calls to sensor_attr_set() reasonably independent of the sensor you are using. Here is a fragment of code (not complete) example of setting things up for a lsm9ds1, this is not the sensor you are using, but all of the general concepts are the same.

 

/*

*      imu.c - routines to run the imu (Inertial Measurement Unit)

*

* imu_init()                   - forks a process to deal with the imu

* imu_main()                   - the main-loop for the imu process

* imu_trigger_handler()        - interrupt handler for the imu and magnetometer

*

*/

 

/* Zephyr specific includes */

#include <zephyr.h>

#include <zephyr/types.h>

#include <logging/log.h>

#include <device.h>

#include <drivers/sensor.h>

 

/* Generic 'C' includes */

#include <stdio.h>

#include <stddef.h>

#include <string.h>

#include <ctype.h>

 

#ifndef TEST_ROUTINE

/* project specific includes */

#include "imu.h"

#include "crash.h"

#endif

 

LOG_MODULE_REGISTER(imu);

 

/* forward declaration */

static void imu_trigger_handler(struct device *dev, struct sensor_trigger *trig);

 

/* the thread for processing imu data */

static K_THREAD_STACK_DEFINE(imu_stack, 1024);

static struct k_thread imu_thread_data;

static struct device *lsm9ds1;

enum sample_t {

        MAGNETOMETER_SAMPLE, ACCELEROMETER_SAMPLE, GRYO_SAMPLE, TEMPERATURE_SAMPLE

};

 

static int imu_mag_trig_cnt;

static int imu_accel_trig_cnt;

static int imu_gyro_trig_cnt;

static struct sensor_value accel[3];

static struct sensor_value gyro[3];

static struct sensor_value magn[3];

#if defined(CONFIG_LSM9DS1_ENABLE_TEMP)

static struct sensor_value temp[1];

static int imu_temp_trig_cnt;

#endif

 

/* a fifo to pass sensor readings from the ISR to the main imu loop */

K_FIFO_DEFINE(sample_fifo);

 

/* a memory pool and support routines to throw sensor readings into */

struct imu_sample_t {

        sys_snode_t node;               /* for the FIFO roputines */

        struct k_mem_block block;       /* for the alloc and free */

        enum sample_t type;             /* what the sensor_values are */

        struct sensor_value value[3];   /* x,y,x , or just T */

};

 

#define FIFO_ELEM_MIN_SZ        sizeof(struct imu_sample_t)

#define FIFO_ELEM_MAX_SZ        sizeof(struct imu_sample_t)

#define FIFO_ELEM_COUNT         255

#define FIFO_ELEM_ALIGN         sizeof(unsigned int)

 

K_MEM_POOL_DEFINE(sample_pool, FIFO_ELEM_MIN_SZ, FIFO_ELEM_MAX_SZ,

                  FIFO_ELEM_COUNT, FIFO_ELEM_ALIGN);

 

static inline void imu_sample_free(struct imu_sample_t *smp)

{

        k_mem_pool_free(&smp->block);

}

 

static inline void imu_sample_put(struct imu_sample_t *smp)

{

        k_fifo_put(&sample_fifo, smp);

}

 

static inline struct imu_sample_t *imu_sample_get(void)

{

        return k_fifo_get(&sample_fifo, K_FOREVER);

}

 

static inline void imu_sample_flush(void)

{

        struct imu_sample_t *smp;

 

        do {

                smp = imu_sample_get();

                if (smp) {

                        imu_sample_free(smp);

                }

        } while (smp != NULL);

}

 

static inline struct imu_sample_t *imu_sample_alloc(void)

{

        int ret;

        struct imu_sample_t *smp;

        struct k_mem_block block;

 

        ret = k_mem_pool_alloc(&sample_pool, &block,

                               sizeof(struct imu_sample_t),

                               K_NO_WAIT);

        if (ret < 0) {

                LOG_ERR("APP sample allocation failed!");

                imu_sample_flush();

 

                ret = k_mem_pool_alloc(&sample_pool, &block,

                                       sizeof(struct imu_sample_t),

                                       K_NO_WAIT);

                if (ret < 0) {

                        LOG_ERR("APP sample memory corrupted.");

                        __ASSERT_NO_MSG(0);

                        return NULL;

                }

                return NULL;

        }

 

        smp = (struct imu_sample_t *)block.data;

        smp->block = block;

 

        return smp;

}

 

static inline float out_ev(struct sensor_value *val)

{

        return (val->val1 + (float)val->val2 / 1000000.0f);

}

 

void imu_test(void)

{

        int64_t sample[3], t;

 

        if (lsm9ds1 != NULL) {

                t = k_uptime_get();     /* number of ms uptime */

                sample[0] = accel[0].val1 * 1000000 + accel[0].val2;

                sample[1] = accel[1].val1 * 1000000 + accel[1].val2;

                sample[2] = accel[2].val1 * 1000000 + accel[2].val2;

 

                printf("LSM9DS1 sensor samples:\n");

                k_sleep(K_MSEC(10));

                printf("mag_trig_cnt=%d, accel_trig_cnt=%d, gyro_trig_cnt=%d\n",

                       imu_mag_trig_cnt,

                       imu_accel_trig_cnt,

                       imu_gyro_trig_cnt);

                printf("\t accelerometer interrupt rate %.3f interrupts/second\n", ((float)imu_accel_trig_cnt / (float)t) * 1000.0f);

 

                k_sleep(K_MSEC(10));

                /* lsm9ds1 accel */

                printf("accel (%f %f %f) m/s2\n", out_ev(&accel[0]),

                       out_ev(&accel[1]),

                       out_ev(&accel[2]));

 

                k_sleep(K_MSEC(10));

                /* lsm9ds1 gyro */

                printf("gyro (%f %f %f) dps\n", out_ev(&gyro[0]),

                       out_ev(&gyro[1]),

                       out_ev(&gyro[2]));

 

                k_sleep(K_MSEC(10));

                /* lsm9ds1 external magn */

                printf("magn (%f %f %f) gauss\n", out_ev(&magn[0]),

                       out_ev(&magn[1]),

                       out_ev(&magn[2]));

#if defined(CONFIG_LSM9DS1_ENABLE_TEMP)

                k_sleep(K_MSEC(10));

                /* lsm9ds1  temperature */

                printf("temperature (%f) degrees C\n", out_ev(&temp[0]));

#endif

#ifndef TEST_ROUTINE

                crash_test(sample);

#endif

        } else {

                printf("LSM9DS1 not available\n");

        }

}

 

void imu_init(void)

{

        struct sensor_value odr_attr;

 

        /* get a handle to the sensor */

        lsm9ds1 = device_get_binding(DT_LABEL(DT_INST(0, st_lsm9ds1)));

        if (lsm9ds1 == NULL) {

                printf("Could not get a handle to the %s device\n", DT_LABEL(DT_INST(0, st_lsm9ds1)));

                return;

        } else {

                printf("imu_dev %p name %s\n", lsm9ds1, DT_LABEL(DT_INST(0, st_lsm9ds1)));

 

                printf("setting up sensor channels.\n");

                /* set magnetometer sampling frequency to 2.5 Hz */

                odr_attr.val1 = 2;

                odr_attr.val2 = 500000;

                if (sensor_attr_set(lsm9ds1, SENSOR_CHAN_MAGN_XYZ,

                                    SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {

                        printf("Cannot set sampling frequency for magnetometer.\n");

                }

                printf("mag sample rate set to 2.5Hz.\n");

 

                /* set accel sampling frequency to 59.5 Hz */

                odr_attr.val1 = 59;

                odr_attr.val2 = 500000;

                if (sensor_attr_set(lsm9ds1, SENSOR_CHAN_ACCEL_XYZ,

                                    SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {

                      printf("Cannot set sampling frequency for accelerometer (as expected).\n");

                }

                /* set gyro sampling frequency to 59.5 Hz */

                if (sensor_attr_set(lsm9ds1, SENSOR_CHAN_GYRO_XYZ,

                                    SENSOR_ATTR_SAMPLING_FREQUENCY, &odr_attr) < 0) {

                        printf("Cannot set sampling frequency for gyro.\n");

                }

                printf("imu sample rate set to 59.5Hz.\n");

 

#ifdef CONFIG_LSM9DS1_TRIGGER

                struct sensor_trigger trig;

#if defined(CONFIG_LSM9DS1_MAG_DRDY_TRIGGER)

                trig.type = SENSOR_TRIG_DATA_READY;

                trig.chan = SENSOR_CHAN_MAGN_XYZ;

 

                if (sensor_trigger_set(lsm9ds1, &trig, imu_trigger_handler) != 0) {

                        printf("Could not set sensor type and channel for mag trigger\n");

               }

                printf("mag trigger handler attached\n");

#endif

#if defined(CONFIG_LSM9DS1_IMU_DRDY_TRIGGER)

                trig.type = SENSOR_TRIG_DATA_READY;

                trig.chan = SENSOR_CHAN_ACCEL_XYZ;

                if (sensor_trigger_set(lsm9ds1, &trig, imu_trigger_handler) != 0) {

                        printf("Could not set sensor type and channel for imu trigger\n");

                }

 

                trig.type = SENSOR_TRIG_DATA_READY;

                trig.chan = SENSOR_CHAN_GYRO_XYZ;

                if (sensor_trigger_set(lsm9ds1, &trig, imu_trigger_handler) != 0) {

                        printf("Could not set sensor type and channel for imu trigger\n");

                }

                printf("imu data ready handlers attached\n");

#endif

#if defined(CONFIG_LSM9DS1_ENABLE_TEMP)

                trig.type = SENSOR_TRIG_DATA_READY;

                trig.chan = SENSOR_CHAN_DIE_TEMP;

 

                if (sensor_trigger_set(lsm9ds1, &trig, imu_trigger_handler) != 0) {

                        printf("Could not set sensor type and channel for temp trigger\n");

                }

                printf("imu temperature handler attached\n");

#endif

 

#endif

                /* start the imu main task */

                k_thread_create(&imu_thread_data, imu_stack,

                                K_THREAD_STACK_SIZEOF(imu_stack),

                                (k_thread_entry_t)imu_main,

                                NULL, NULL, NULL, K_PRIO_COOP(9), 0, K_NO_WAIT);

                printf("done setting up sensor channels.\n");

        }

}

 

#if defined(CONFIG_LSM9DS1_MAG_DRDY_TRIGGER) || defined(CONFIG_LSM9DS1_IMU_DRDY_TRIGGER)

static void imu_trigger_handler(struct device *dev,

                                struct sensor_trigger *trig)

{

        struct imu_sample_t *sample;

        int rc;

 

        /* look at the trigger type to decide if this is accel,

         * gyro, or temp data, then get it, convert to eng units

         * and store it locally

         */

        if (trig->type == SENSOR_TRIG_DATA_READY) {

                switch (trig->chan) {

#if defined(CONFIG_LSM9DS1_MAG_DRDY_TRIGGER)

                case SENSOR_CHAN_MAGN_XYZ:

                        imu_mag_trig_cnt++;

                        sample = imu_sample_alloc();

                        if (sample == NULL) {

                                printf("imu_sample_alloc() failed\n");

                                break;

                        }

                        rc = sensor_sample_fetch_chan(dev, SENSOR_CHAN_MAGN_XYZ);

                        if (rc != 0) {

                                printf("sensor_sample_fetch_chan() failed\n");

                        }

                        rc = sensor_channel_get(dev, SENSOR_CHAN_MAGN_XYZ, sample->value);

                        /* rc = sensor_channel_get(dev, SENSOR_CHAN_MAGN_XYZ, magn); */

                        if (rc != 0) {

                                printf("sensor_channel_get() failed\n");

                        }

                        sample->type = MAGNETOMETER_SAMPLE;

                        imu_sample_put(sample);

                        /* printf("magnetometer sample pushed into fifo\n"); */

                        break;

#endif

#if defined(CONFIG_LSM9DS1_IMU_DRDY_TRIGGER)

                case SENSOR_CHAN_ACCEL_XYZ:

                        imu_accel_trig_cnt++;

                        sample = imu_sample_alloc();

                        if (sample == NULL) {

                                printf("imu_sample_alloc() failed\n");

                                break;

                        }

                        rc = sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ);

                        if (rc != 0) {

                                printf("sensor_sample_fetch_chan() failed\n");

                        }

                        rc = sensor_channel_get(dev, SENSOR_CHAN_ACCEL_XYZ, sample->value);

                        /* rc = sensor_channel_get(dev, SENSOR_CHAN_ACCEL_XYZ, accel); */

                        if (rc != 0) {

                                printf("sensor_channel_get() failed\n");

                        }

                        sample->type = ACCELEROMETER_SAMPLE;

                        imu_sample_put(sample);

                        /* printf("accel sample pushed into fifo\n"); */

                        break;

                case SENSOR_CHAN_GYRO_XYZ:

                        imu_gyro_trig_cnt++;

                        sample = imu_sample_alloc();

                        if (sample == NULL) {

                                printf("imu_sample_alloc() failed\n");

                                break;

                        }

                        rc = sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ);

                        if (rc != 0) {

                                printf("sensor_sample_fetch_chan() failed\n");

                        }

                        rc = sensor_channel_get(dev, SENSOR_CHAN_GYRO_XYZ, sample->value);

                        /* rc = sensor_channel_get(dev, SENSOR_CHAN_GYRO_XYZ, gyro); */

                        if (rc != 0) {

                                printf("sensor_channel_get() failed\n");

                        }

                        sample->type = GRYO_SAMPLE;

                        imu_sample_put(sample);

                        /* printf("gyro sample pushed into fifo\n"); */

                        break;

#endif

#if defined(CONFIG_LSM9DS1_ENABLE_TEMP)

                case SENSOR_CHAN_DIE_TEMP:

                        imu_temp_trig_cnt++;

                        sample = imu_sample_alloc();

                        if (sample == NULL) {

                                printf("imu_sample_alloc() failed\n");

                                break;

                        }

                        rc = sensor_sample_fetch_chan(dev, SENSOR_CHAN_DIE_TEMP);

                        if (rc != 0) {

                                printf("sensor_sample_fetch_chan() failed\n");

                        }

                        rc = sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, sample->value);

                        /* rc = sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, temp); */

                        if (rc != 0) {

                                printf("sensor_channel_get() failed\n");

                        }

                        sample->type = TEMPERATURE_SAMPLE;

                        imu_sample_put(sample);

                        /* printf("temp sample pushed into fifo\n"); */

                        break;

#endif

                default:

                        break;

                }

                /* once we put a sample into the fifo, the kernel will wake up

                 * the main loop to process the sample */

        }

}

#endif

 

/**

*

* imu_main() - main loop for processing samples

*

**/

void imu_main(void)

{

        struct imu_sample_t *smp;

        int magn_cnt = 0, accel_cnt = 0, gyro_cnt = 0, temp_cnt = 0;

 

        if (lsm9ds1 != NULL) {

                printf("imu_main(): started\n");

                k_sleep(K_MSEC(1000));  /* wait for samples to arrive */

        /*      sensor_sample_fetch(lsm9ds1); */

                sensor_sample_fetch_chan(lsm9ds1, SENSOR_CHAN_DIE_TEMP);

                sensor_sample_fetch_chan(lsm9ds1, SENSOR_CHAN_GYRO_XYZ);

                sensor_sample_fetch_chan(lsm9ds1, SENSOR_CHAN_MAGN_XYZ);

                sensor_sample_fetch_chan(lsm9ds1, SENSOR_CHAN_ACCEL_XYZ);

        }

 

        while (1) {

                /* eat up all of the samples out of the fifo */

                if ( ((smp = imu_sample_get()) != NULL) && (lsm9ds1 != NULL) ) {

                        /* store latest sample in a place where the test routine can print it */

                        switch (smp->type) {

                        case MAGNETOMETER_SAMPLE:

                                magn_cnt++;

                                magn[0] = smp->value[0];

                                magn[1] = smp->value[1];

                                magn[2] = smp->value[2];

                                break;

                        case ACCELEROMETER_SAMPLE:

                                accel_cnt++;

                                accel[0] = smp->value[0];

                                accel[1] = smp->value[1];

                                accel[2] = smp->value[2];

#ifndef TEST_ROUTINE

                                crash_detect(&(smp->value[0]), &(smp->value[1]), &(smp->value[2]));

#endif

                                break;

                        case GRYO_SAMPLE:

                                gyro_cnt++;

                                gyro[0] = smp->value[0];

                                gyro[1] = smp->value[1];

                                gyro[2] = smp->value[2];

                                break;

#if defined(CONFIG_LSM9DS1_ENABLE_TEMP)

                        case TEMPERATURE_SAMPLE:

                                temp_cnt++;

                                temp[0] = smp->value[0];

                                break;

#endif

                        }

                        imu_sample_free(smp);

                } else {

                        /* no samples available, nap for a while.

                         * above we set the sample rate at 59.9Hz so waiting a

                         * 60th of a second is reasonable, of course since the

                         * imu_sample_get() routine waits until there is

                         * something in the fifo, this should never happen */

                        k_sleep(K_MSEC(1000 / 60));

                }

        }

}

 

 

 

 

 

 

Lawrence King

Principal Developer

+1(416)627-7302

 

From: users@... <users@...> On Behalf Of DKaplan@...
Sent: Wednesday, June 9, 2021 5:22 AM
To: users@...
Subject: [Zephyr-users] lsm6dsl full registers access #sensor #sst26

 

Shalom!
 We are building a custom prototype Nordic nRF9160 board with the lsm6dsl spi chip in parallel on the same spi channel as the MX25R6435F flash memory chip.
I am new to Zephyr and mostly have programmed without any RTOS directly, bare metal, accessing the devices.
I need to program (and read) most all of the lsm6dsl's registers including reading the lsm6dsl's fifo before it overflows.
I understand that in the lsm6dsl sample that the sensor wrapper is used along with interrupts for motion detection.
We do not need any motion detection but just to take acceleration readings for a period of a several seconds.
Since the acceleration readings are at a know frequency ad the fifo size is constant, we do not have to use an interrupt by using a FIFO threshold, but by constantly emptying the FIFO.
I have code that works well using a Silabs mico-controller.
I looked at the sensors/lsm6dsl files including lsm6dsl_spi.c which seems to have basic read and write register static functionality but I do not know how this is reflected (or mapped) to the high level sensor functions like sensor_attr_set() sensor_attr_get() sensor_sample_fetch_chan() & sensor_channel_get().
Also I do not see how to specify each chip select for devices on the same SPI bus.
I am new to the prj.conf, Kconfig, CMakeLists.txt & .overlay files.
I created an overlay file and based on what I saw added the following:

&spi3 {

    status = "okay";

    sck-pin = <13>;

    mosi-pin = <11>;

    miso-pin = <12>;

    cs-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>;

    /* ST Microelectronics LSM6DSL accel/gyro sensor */

    lsm6dsl@1 {

        compatible = "st,lsm6dsl";

        reg = <1>;

        spi-max-frequency = <1000000>;

        irq-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;

        label = "LSM6DSL_SPI";

    };

    mx25r64: mx25r6435f@0 {

        compatible = "jedec,spi-nor";

        reg = <0>;

        spi-max-frequency = <8000000>;

        label = "MX25R64";

        jedec-id = [c2 28 17];

        sfdp-bfp = [

            e5 20 f1 ff  ff ff ff 03  44 eb 08 6b  08 3b 04 bb

            ee ff ff ff  ff ff 00 ff  ff ff 00 ff  0c 20 0f 52

            10 d8 00 ff  23 72 f5 00  82 ed 04 cc  44 83 68 44

            30 b0 30 b0  f7 c4 d5 5c  00 be 29 ff  f0 d0 ff ff

        ];

        size = <67108864>;

        has-dpd;

        t-enter-dpd = <10000>;

        t-exit-dpd = <35000>;

    };

};


We also have a 24LC512 EEPROM and a SI7050 temperature chip on the same I2C line, so the answer on how to specify their individual cs may be the same.
So basically I am asking:
 1) How do I map the high end sensor functions to the lower end spi functions?
 2) How do I differentiate between their cs lines?
 
If anyone can help or has a Zephyr example with the lsm6dsl , 24LC512 or the SI7050 let me know.
Thanks
 David

Join users@lists.zephyrproject.org to automatically receive all group messages.