From af6abd8ccfd915712220f733efd50d8b95944a68 Mon Sep 17 00:00:00 2001 From: Marco Schuler Date: Thu, 9 Oct 2025 13:41:45 +0200 Subject: [PATCH 1/3] drivers: sensor: st: Add driver for lsm6dsr This driver adds initial support for the ST lsm6dsr IMU. Supported interface are I2C and SPI. It supports polling measurement mode. Setting/modifying attributes for output data rate (ODR) and full scale range (FS) is supported too. Origin: Original Signed-off-by: Marco Schuler --- drivers/sensor/st/CMakeLists.txt | 1 + drivers/sensor/st/Kconfig | 1 + drivers/sensor/st/lsm6dsr/CMakeLists.txt | 7 + drivers/sensor/st/lsm6dsr/Kconfig | 89 +++ drivers/sensor/st/lsm6dsr/lsm6dsr.c | 649 +++++++++++++++++++++ drivers/sensor/st/lsm6dsr/lsm6dsr.h | 179 ++++++ drivers/sensor/st/lsm6dsr/lsm6dsr_i2c.c | 74 +++ drivers/sensor/st/lsm6dsr/lsm6dsr_spi.c | 144 +++++ dts/bindings/sensor/st,lsm6dsr-common.yaml | 4 + dts/bindings/sensor/st,lsm6dsr-i2c.yaml | 10 + dts/bindings/sensor/st,lsm6dsr-spi.yaml | 10 + 11 files changed, 1168 insertions(+) create mode 100644 drivers/sensor/st/lsm6dsr/CMakeLists.txt create mode 100644 drivers/sensor/st/lsm6dsr/Kconfig create mode 100644 drivers/sensor/st/lsm6dsr/lsm6dsr.c create mode 100644 drivers/sensor/st/lsm6dsr/lsm6dsr.h create mode 100644 drivers/sensor/st/lsm6dsr/lsm6dsr_i2c.c create mode 100644 drivers/sensor/st/lsm6dsr/lsm6dsr_spi.c create mode 100644 dts/bindings/sensor/st,lsm6dsr-common.yaml create mode 100644 dts/bindings/sensor/st,lsm6dsr-i2c.yaml create mode 100644 dts/bindings/sensor/st,lsm6dsr-spi.yaml diff --git a/drivers/sensor/st/CMakeLists.txt b/drivers/sensor/st/CMakeLists.txt index 979d67d96ae25..22194cf6a2aca 100644 --- a/drivers/sensor/st/CMakeLists.txt +++ b/drivers/sensor/st/CMakeLists.txt @@ -30,6 +30,7 @@ add_subdirectory_ifdef(CONFIG_LSM6DS0 lsm6ds0) add_subdirectory_ifdef(CONFIG_LSM6DSL lsm6dsl) add_subdirectory_ifdef(CONFIG_LSM6DSO lsm6dso) add_subdirectory_ifdef(CONFIG_LSM6DSO16IS lsm6dso16is) +add_subdirectory_ifdef(CONFIG_LSM6DSR lsm6dsr) add_subdirectory_ifdef(CONFIG_LSM6DSV16X lsm6dsv16x) add_subdirectory_ifdef(CONFIG_LSM9DS0_GYRO lsm9ds0_gyro) add_subdirectory_ifdef(CONFIG_LSM9DS0_MFD lsm9ds0_mfd) diff --git a/drivers/sensor/st/Kconfig b/drivers/sensor/st/Kconfig index 4daaba9d7cc87..38cf3cb67119d 100644 --- a/drivers/sensor/st/Kconfig +++ b/drivers/sensor/st/Kconfig @@ -29,6 +29,7 @@ source "drivers/sensor/st/lsm6ds0/Kconfig" source "drivers/sensor/st/lsm6dsl/Kconfig" source "drivers/sensor/st/lsm6dso/Kconfig" source "drivers/sensor/st/lsm6dso16is/Kconfig" +source "drivers/sensor/st/lsm6dsr/Kconfig" source "drivers/sensor/st/lsm6dsv16x/Kconfig" source "drivers/sensor/st/lsm9ds0_gyro/Kconfig" source "drivers/sensor/st/lsm9ds0_mfd/Kconfig" diff --git a/drivers/sensor/st/lsm6dsr/CMakeLists.txt b/drivers/sensor/st/lsm6dsr/CMakeLists.txt new file mode 100644 index 0000000000000..b9602bcd4c239 --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources(lsm6dsr.c) +zephyr_library_sources(lsm6dsr_spi.c) +zephyr_library_sources(lsm6dsr_i2c.c) diff --git a/drivers/sensor/st/lsm6dsr/Kconfig b/drivers/sensor/st/lsm6dsr/Kconfig new file mode 100644 index 0000000000000..6c019013486e8 --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/Kconfig @@ -0,0 +1,89 @@ +# LSM6DSR accelerometer and gyroscope sensor configuration +# options + +# Copyright (c) 2025 Helbling Technik AG +# SPDX-License-Identifier: Apache-2.0 + +menuconfig LSM6DSR + bool "LSM6DSR I2C/SPI accelerometer and gyroscope Chip" + default y + depends on DT_HAS_ST_LSM6DSR_ENABLED + select I2C if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSR),i2c) + select SPI if $(dt_compat_on_bus,$(DT_COMPAT_ST_LSM6DSR),spi) + help + Enable driver for LSM6DSR accelerometer and gyroscope + sensor. + +if LSM6DSR + +menu "Attributes" + +config LSM6DSR_GYRO_FS + int "Gyroscope full-scale range" + default 0 + help + Specify the default gyroscope full-scale range. + An X value for the config represents a range of +/- X degree per + second. Valid values are: + 0: Full Scale selected at runtime + 125: +/- 125dps + 250: +/- 250dps + 500: +/- 500dps + 1000: +/- 1000dps + 2000: +/- 2000dps + 4000: +/- 4000dps + +config LSM6DSR_GYRO_ODR + int "Gyroscope Output data rate frequency" + range 0 10 + default 0 + help + Specify the default accelerometer output data rate expressed in + samples per second (Hz). + 0: ODR selected at runtime + 1: 12.5Hz + 2: 26Hz + 3: 52Hz + 4: 104Hz + 5: 208Hz + 6: 416Hz + 7: 833Hz + 8: 1660Hz + 9: 3330Hz + 10: 6660Hz + +config LSM6DSR_ACCEL_FS + int "Accelerometer full-scale range" + default 0 + help + Specify the default accelerometer full-scale range. + An X value for the config represents a range of +/- X G. Valid values + are: + 0: Full Scale selected at runtime + 2: +/- 2g + 4: +/- 4g + 8: +/- 8g + 16: +/- 16g + +config LSM6DSR_ACCEL_ODR + int "Accelerometer Output data rate frequency" + range 0 11 + default 0 + help + Specify the default accelerometer output data rate expressed in + samples per second (Hz). + 0: ODR selected at runtime + 1: 12.5Hz + 2: 26Hz + 3: 52Hz + 4: 104Hz + 5: 208Hz + 6: 416Hz + 7: 833Hz + 8: 1666Hz + 9: 3332Hz + 10: 6664Hz + 11: 1.6Hz +endmenu + +endif # LSM6DSR diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr.c b/drivers/sensor/st/lsm6dsr/lsm6dsr.c new file mode 100644 index 0000000000000..5fc227d7383e4 --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr.c @@ -0,0 +1,649 @@ +/* lsm6dsr.c - Driver for LSM6DSR accelerometer, gyroscope and + * temperature sensor + */ + +/* + * Copyright (c) 2025 Helbling Technik AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_lsm6dsr + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lsm6dsr.h" + +LOG_MODULE_REGISTER(LSM6DSR, CONFIG_SENSOR_LOG_LEVEL); + +static const uint16_t lsm6dsr_odr_map[] = {0, 12, 26, 52, 104, 208, 416, 833, 1666, 3332, 6664, 1}; + +#if defined(LSM6DSR_ACCEL_ODR_RUNTIME) || defined(LSM6DSR_GYRO_ODR_RUNTIME) +static int lsm6dsr_freq_to_odr_val(uint16_t freq) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lsm6dsr_odr_map); i++) { + if (freq == lsm6dsr_odr_map[i]) { + return i; + } + } + + return -EINVAL; +} +#endif + +static int lsm6dsr_odr_to_freq_val(uint16_t odr) +{ + /* for valid index, return value from map */ + if (odr < ARRAY_SIZE(lsm6dsr_odr_map)) { + return lsm6dsr_odr_map[odr]; + } + + /* invalid index, return the fastest entry (6.66kHz) */ + BUILD_ASSERT(ARRAY_SIZE(lsm6dsr_odr_map) > 10); + return lsm6dsr_odr_map[10]; +} + +#ifdef LSM6DSR_ACCEL_FS_RUNTIME +static const uint16_t lsm6dsr_accel_fs_map[] = {2, 16, 4, 8}; +static const uint16_t lsm6dsr_accel_fs_sens[] = {1, 8, 2, 4}; + +static int lsm6dsr_accel_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lsm6dsr_accel_fs_map); i++) { + if (range == lsm6dsr_accel_fs_map[i]) { + return i; + } + } + + return -EINVAL; +} +#endif + +#ifdef LSM6DSR_GYRO_FS_RUNTIME +static const uint16_t lsm6dsr_gyro_fs_map[] = {250, 500, 1000, 2000, 125, 4000}; +static const uint16_t lsm6dsr_gyro_fs_sens[] = {2, 4, 8, 16, 1, 32}; + +/* Indexes in maps of the two specially treated bits for gyro full scale */ +#define GYRO_FULLSCALE_125 4 +#define GYRO_FULLSCALE_4000 5 + +static int lsm6dsr_gyro_range_to_fs_val(int32_t range) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(lsm6dsr_gyro_fs_map); i++) { + if (range == lsm6dsr_gyro_fs_map[i]) { + return i; + } + } + + return -EINVAL; +} +#endif + +static inline int lsm6dsr_reboot(const struct device *dev) +{ + struct lsm6dsr_data *data = dev->data; + + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL3_C, LSM6DSR_MASK_CTRL3_C_BOOT, + 1 << LSM6DSR_SHIFT_CTRL3_C_BOOT) < 0) { + return -EIO; + } + + /* Wait sensor turn-on time as per datasheet */ + k_busy_wait(USEC_PER_MSEC * 35U); + + return 0; +} + +static int lsm6dsr_accel_set_fs_raw(const struct device *dev, uint8_t fs) +{ + struct lsm6dsr_data *data = dev->data; + + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL1_XL, LSM6DSR_MASK_CTRL1_XL_FS_XL, + fs << LSM6DSR_SHIFT_CTRL1_XL_FS_XL) < 0) { + return -EIO; + } + + return 0; +} + +static int lsm6dsr_accel_set_odr_raw(const struct device *dev, uint8_t odr) +{ + struct lsm6dsr_data *data = dev->data; + + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL1_XL, LSM6DSR_MASK_CTRL1_XL_ODR_XL, + odr << LSM6DSR_SHIFT_CTRL1_XL_ODR_XL) < 0) { + return -EIO; + } + + data->accel_freq = lsm6dsr_odr_to_freq_val(odr); + + return 0; +} + +static int lsm6dsr_gyro_set_fs_raw(const struct device *dev, uint8_t fs) +{ + struct lsm6dsr_data *data = dev->data; + + switch (fs) { + case GYRO_FULLSCALE_125: { + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL2_G, + LSM6DSR_MASK_CTRL2_FS4000 | LSM6DSR_MASK_CTRL2_FS125 | + LSM6DSR_MASK_CTRL2_G_FS_G, + 1 << LSM6DSR_SHIFT_CTRL2_FS125) < 0) { + return -EIO; + } + break; + } + case GYRO_FULLSCALE_4000: { + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL2_G, + LSM6DSR_MASK_CTRL2_FS4000 | LSM6DSR_MASK_CTRL2_FS125 | + LSM6DSR_MASK_CTRL2_G_FS_G, + 1 << LSM6DSR_SHIFT_CTRL2_FS4000) < 0) { + return -EIO; + } + break; + } + default: { + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL2_G, + LSM6DSR_MASK_CTRL2_FS125 | LSM6DSR_MASK_CTRL2_G_FS_G, + fs << LSM6DSR_SHIFT_CTRL2_G_FS_G) < 0) { + return -EIO; + } + break; + } + } + + return 0; +} + +static int lsm6dsr_gyro_set_odr_raw(const struct device *dev, uint8_t odr) +{ + struct lsm6dsr_data *data = dev->data; + + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL2_G, LSM6DSR_MASK_CTRL2_G_ODR_G, + odr << LSM6DSR_SHIFT_CTRL2_G_ODR_G) < 0) { + return -EIO; + } + + data->gyro_freq = lsm6dsr_odr_to_freq_val(odr); + + return 0; +} + +#ifdef LSM6DSR_ACCEL_ODR_RUNTIME +static int lsm6dsr_accel_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lsm6dsr_freq_to_odr_val(freq); + if (odr < 0) { + return odr; + } + + if (lsm6dsr_accel_set_odr_raw(dev, odr) < 0) { + LOG_DBG("failed to set accelerometer sampling rate"); + return -EIO; + } + + return 0; +} +#endif + +#ifdef LSM6DSR_ACCEL_FS_RUNTIME +static int lsm6dsr_accel_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lsm6dsr_data *data = dev->data; + + fs = lsm6dsr_accel_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lsm6dsr_accel_set_fs_raw(dev, fs) < 0) { + LOG_DBG("failed to set accelerometer full-scale"); + return -EIO; + } + + data->accel_sensitivity = (float)(lsm6dsr_accel_fs_sens[fs] * SENSI_GRAIN_XL); + return 0; +} +#endif + +static int lsm6dsr_accel_config(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (attr) { +#ifdef LSM6DSR_ACCEL_FS_RUNTIME + case SENSOR_ATTR_FULL_SCALE: + return lsm6dsr_accel_range_set(dev, sensor_ms2_to_g(val)); +#endif +#ifdef LSM6DSR_ACCEL_ODR_RUNTIME + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsr_accel_odr_set(dev, val->val1); +#endif + default: + LOG_DBG("Accel attribute not supported."); + return -ENOTSUP; + } + + return 0; +} + +#ifdef LSM6DSR_GYRO_ODR_RUNTIME +static int lsm6dsr_gyro_odr_set(const struct device *dev, uint16_t freq) +{ + int odr; + + odr = lsm6dsr_freq_to_odr_val(freq); + if (odr < 0) { + return odr; + } + + if (lsm6dsr_gyro_set_odr_raw(dev, odr) < 0) { + LOG_DBG("failed to set gyroscope sampling rate"); + return -EIO; + } + + return 0; +} +#endif + +#ifdef LSM6DSR_GYRO_FS_RUNTIME +static int lsm6dsr_gyro_range_set(const struct device *dev, int32_t range) +{ + int fs; + struct lsm6dsr_data *data = dev->data; + + fs = lsm6dsr_gyro_range_to_fs_val(range); + if (fs < 0) { + return fs; + } + + if (lsm6dsr_gyro_set_fs_raw(dev, fs) < 0) { + LOG_DBG("failed to set gyroscope full-scale"); + return -EIO; + } + + data->gyro_sensitivity = (float)(lsm6dsr_gyro_fs_sens[fs] * SENSI_GRAIN_G); + return 0; +} +#endif + +static int lsm6dsr_gyro_config(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (attr) { +#ifdef LSM6DSR_GYRO_FS_RUNTIME + case SENSOR_ATTR_FULL_SCALE: + return lsm6dsr_gyro_range_set(dev, sensor_rad_to_degrees(val)); +#endif +#ifdef LSM6DSR_GYRO_ODR_RUNTIME + case SENSOR_ATTR_SAMPLING_FREQUENCY: + return lsm6dsr_gyro_odr_set(dev, val->val1); +#endif + default: + LOG_DBG("Gyro attribute not supported."); + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsr_attr_set(const struct device *dev, enum sensor_channel chan, + enum sensor_attribute attr, const struct sensor_value *val) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + return lsm6dsr_accel_config(dev, chan, attr, val); + case SENSOR_CHAN_GYRO_XYZ: + return lsm6dsr_gyro_config(dev, chan, attr, val); + default: + LOG_WRN("attr_set() not supported on this channel."); + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsr_sample_fetch_accel(const struct device *dev) +{ + struct lsm6dsr_data *data = dev->data; + uint8_t buf[6]; + + if (data->hw_tf->read_data(dev, LSM6DSR_REG_OUTX_L_XL, buf, sizeof(buf)) < 0) { + LOG_DBG("failed to read accel sample"); + return -EIO; + } + + data->accel_sample_x = (int16_t)((uint16_t)(buf[0]) | ((uint16_t)(buf[1]) << 8)); + data->accel_sample_y = (int16_t)((uint16_t)(buf[2]) | ((uint16_t)(buf[3]) << 8)); + data->accel_sample_z = (int16_t)((uint16_t)(buf[4]) | ((uint16_t)(buf[5]) << 8)); + + return 0; +} + +static int lsm6dsr_sample_fetch_gyro(const struct device *dev) +{ + struct lsm6dsr_data *data = dev->data; + uint8_t buf[6]; + + if (data->hw_tf->read_data(dev, LSM6DSR_REG_OUTX_L_G, buf, sizeof(buf)) < 0) { + LOG_DBG("failed to read gyro sample"); + return -EIO; + } + + data->gyro_sample_x = (int16_t)((uint16_t)(buf[0]) | ((uint16_t)(buf[1]) << 8)); + data->gyro_sample_y = (int16_t)((uint16_t)(buf[2]) | ((uint16_t)(buf[3]) << 8)); + data->gyro_sample_z = (int16_t)((uint16_t)(buf[4]) | ((uint16_t)(buf[5]) << 8)); + + return 0; +} + +static int lsm6dsr_sample_fetch(const struct device *dev, enum sensor_channel chan) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_XYZ: + lsm6dsr_sample_fetch_accel(dev); + break; + case SENSOR_CHAN_GYRO_XYZ: + lsm6dsr_sample_fetch_gyro(dev); + break; + case SENSOR_CHAN_ALL: + lsm6dsr_sample_fetch_accel(dev); + lsm6dsr_sample_fetch_gyro(dev); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static inline void lsm6dsr_accel_convert(struct sensor_value *val, int raw_val, float sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in ug/LSB */ + /* Convert to m/s^2 */ + dval = (int64_t)raw_val * sensitivity; + sensor_ug_to_ms2(dval, val); +} + +static inline int lsm6dsr_accel_get_channel(enum sensor_channel chan, struct sensor_value *val, + struct lsm6dsr_data *data, float sensitivity) +{ + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + lsm6dsr_accel_convert(val, data->accel_sample_x, sensitivity); + break; + case SENSOR_CHAN_ACCEL_Y: + lsm6dsr_accel_convert(val, data->accel_sample_y, sensitivity); + break; + case SENSOR_CHAN_ACCEL_Z: + lsm6dsr_accel_convert(val, data->accel_sample_z, sensitivity); + break; + case SENSOR_CHAN_ACCEL_XYZ: + lsm6dsr_accel_convert(val, data->accel_sample_x, sensitivity); + lsm6dsr_accel_convert(val + 1, data->accel_sample_y, sensitivity); + lsm6dsr_accel_convert(val + 2, data->accel_sample_z, sensitivity); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsr_accel_channel_get(enum sensor_channel chan, struct sensor_value *val, + struct lsm6dsr_data *data) +{ + return lsm6dsr_accel_get_channel(chan, val, data, data->accel_sensitivity); +} + +static inline void lsm6dsr_gyro_convert(struct sensor_value *val, int raw_val, float sensitivity) +{ + int64_t dval; + + /* Sensitivity is exposed in udps/LSB */ + /* So, calculate value in 10 udps unit and then to rad/s */ + dval = (int64_t)raw_val * sensitivity / 10; + sensor_10udegrees_to_rad(dval, val); +} + +static inline int lsm6dsr_gyro_get_channel(enum sensor_channel chan, struct sensor_value *val, + struct lsm6dsr_data *data, float sensitivity) +{ + switch (chan) { + case SENSOR_CHAN_GYRO_X: + lsm6dsr_gyro_convert(val, data->gyro_sample_x, sensitivity); + break; + case SENSOR_CHAN_GYRO_Y: + lsm6dsr_gyro_convert(val, data->gyro_sample_y, sensitivity); + break; + case SENSOR_CHAN_GYRO_Z: + lsm6dsr_gyro_convert(val, data->gyro_sample_z, sensitivity); + break; + case SENSOR_CHAN_GYRO_XYZ: + lsm6dsr_gyro_convert(val, data->gyro_sample_x, sensitivity); + lsm6dsr_gyro_convert(val + 1, data->gyro_sample_y, sensitivity); + lsm6dsr_gyro_convert(val + 2, data->gyro_sample_z, sensitivity); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static int lsm6dsr_gyro_channel_get(enum sensor_channel chan, struct sensor_value *val, + struct lsm6dsr_data *data) +{ + return lsm6dsr_gyro_get_channel(chan, val, data, data->gyro_sensitivity); +} + +static int lsm6dsr_channel_get(const struct device *dev, enum sensor_channel chan, + struct sensor_value *val) +{ + struct lsm6dsr_data *data = dev->data; + + switch (chan) { + case SENSOR_CHAN_ACCEL_X: + case SENSOR_CHAN_ACCEL_Y: + case SENSOR_CHAN_ACCEL_Z: + case SENSOR_CHAN_ACCEL_XYZ: + lsm6dsr_accel_channel_get(chan, val, data); + break; + case SENSOR_CHAN_GYRO_X: + case SENSOR_CHAN_GYRO_Y: + case SENSOR_CHAN_GYRO_Z: + case SENSOR_CHAN_GYRO_XYZ: + lsm6dsr_gyro_channel_get(chan, val, data); + break; + default: + return -ENOTSUP; + } + + return 0; +} + +static DEVICE_API(sensor, lsm6dsr_driver_api) = { + .attr_set = lsm6dsr_attr_set, + .sample_fetch = lsm6dsr_sample_fetch, + .channel_get = lsm6dsr_channel_get, +}; + +static int lsm6dsr_init_chip(const struct device *dev) +{ + struct lsm6dsr_data *data = dev->data; + uint8_t chip_id; + + if (lsm6dsr_reboot(dev) < 0) { + LOG_DBG("failed to reboot device"); + return -EIO; + } + + if (data->hw_tf->read_reg(dev, LSM6DSR_REG_WHO_AM_I, &chip_id) < 0) { + LOG_DBG("failed reading chip id"); + return -EIO; + } + if (chip_id != LSM6DSR_VAL_WHO_AM_I) { + LOG_DBG("invalid chip id 0x%x (expected 0x%x)", chip_id, LSM6DSR_REG_WHO_AM_I); + return -EIO; + } + + LOG_DBG("chip id 0x%x", chip_id); + + if (lsm6dsr_accel_set_fs_raw(dev, LSM6DSR_DEFAULT_ACCEL_FULLSCALE) < 0) { + LOG_DBG("failed to set accelerometer full-scale"); + return -EIO; + } + data->accel_sensitivity = LSM6DSR_DEFAULT_ACCEL_SENSITIVITY; + + if (lsm6dsr_accel_set_odr_raw(dev, CONFIG_LSM6DSR_ACCEL_ODR) < 0) { + LOG_DBG("failed to set accelerometer sampling rate"); + return -EIO; + } + + if (lsm6dsr_gyro_set_fs_raw(dev, LSM6DSR_DEFAULT_GYRO_FULLSCALE) < 0) { + LOG_DBG("failed to set gyroscope full-scale"); + return -EIO; + } + data->gyro_sensitivity = LSM6DSR_DEFAULT_GYRO_SENSITIVITY; + + if (lsm6dsr_gyro_set_odr_raw(dev, CONFIG_LSM6DSR_GYRO_ODR) < 0) { + LOG_DBG("failed to set gyroscope sampling rate"); + return -EIO; + } + + /* Configure FIFO: Bypass mode --> FIFO disabled */ + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_FIFO_CTRL4, LSM6DSR_MASK_FIFO_CTRL4_FIFO_MODE, + 0 << LSM6DSR_SHIFT_FIFO_CTRL4_FIFO_MODE) < 0) { + LOG_DBG("failed to set FIFO mode"); + return -EIO; + } + + /* Configure: + * - BDU: Disable Block data update --> continuous update + * - Bit 1: Must be set to zero for the correct operation of the device + * - IF_INC: Enable auto increment during multiple byte access (burst) + */ + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL3_C, + LSM6DSR_MASK_CTRL3_C_BDU | LSM6DSR_MASK_CTRL3_C_MUST_BE_ZERO | + LSM6DSR_MASK_CTRL3_C_IF_INC, + (1 << LSM6DSR_SHIFT_CTRL3_C_BDU) | + (0 << LSM6DSR_SHIFT_CTRL3_C_MUST_BE_ZERO) | + (1 << LSM6DSR_SHIFT_CTRL3_C_IF_INC)) < 0) { + LOG_DBG("failed to set BDU, MUST_BE_ZERO and burst"); + return -EIO; + } + + /* Configure: + * - Disable high performance operation mode for accelerometer + */ + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL6_C, LSM6DSR_MASK_CTRL6_C_XL_HM_MODE, + (1 << LSM6DSR_SHIFT_CTRL6_C_XL_HM_MODE)) < 0) { + LOG_DBG("failed to disable accelerometer high performance mode"); + return -EIO; + } + + /* Configure: + * - Disable high performance operation mode for gyro + */ + if (data->hw_tf->update_reg(dev, LSM6DSR_REG_CTRL7_G, LSM6DSR_MASK_CTRL7_G_HM_MODE, + (1 << LSM6DSR_SHIFT_CTRL7_G_HM_MODE)) < 0) { + LOG_DBG("failed to disable gyroscope high performance mode"); + return -EIO; + } + + return 0; +} + +static int lsm6dsr_init(const struct device *dev) +{ + int ret; + const struct lsm6dsr_config *const config = dev->config; + + ret = config->bus_init(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize sensor bus"); + return ret; + } + + ret = lsm6dsr_init_chip(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize chip"); + return ret; + } + + return 0; +} + +#if DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 0 +#warning "LSM6DSR driver enabled without any devices" +#endif + +/* + * Device creation macro, shared by LSM6DSR_DEFINE_SPI() and + * LSM6DSR_DEFINE_I2C(). + */ + +#define LSM6DSR_DEVICE_INIT(inst) \ + SENSOR_DEVICE_DT_INST_DEFINE(inst, lsm6dsr_init, NULL, &lsm6dsr_data_##inst, \ + &lsm6dsr_config_##inst, POST_KERNEL, \ + CONFIG_SENSOR_INIT_PRIORITY, &lsm6dsr_driver_api); + +/* + * Instantiation macros used when a device is on a SPI bus. + */ +#define LSM6DSR_CONFIG_SPI(inst) \ + { \ + .bus_init = lsm6dsr_spi_init, \ + .bus_cfg.spi = SPI_DT_SPEC_INST_GET( \ + inst, \ + SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA, 0), \ + } + +#define LSM6DSR_DEFINE_SPI(inst) \ + static struct lsm6dsr_data lsm6dsr_data_##inst; \ + static const struct lsm6dsr_config lsm6dsr_config_##inst = LSM6DSR_CONFIG_SPI(inst); \ + LSM6DSR_DEVICE_INIT(inst) + +/* + * Instantiation macros used when a device is on an I2C bus. + */ + +#define LSM6DSR_CONFIG_I2C(inst) \ + { \ + .bus_init = lsm6dsr_i2c_init, \ + .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \ + } + +#define LSM6DSR_DEFINE_I2C(inst) \ + static struct lsm6dsr_data lsm6dsr_data_##inst; \ + static const struct lsm6dsr_config lsm6dsr_config_##inst = LSM6DSR_CONFIG_I2C(inst); \ + LSM6DSR_DEVICE_INIT(inst) +/* + * Main instantiation macro. Use of COND_CODE_1() selects the right + * bus-specific macro at preprocessor time. + */ + +#define LSM6DSR_DEFINE(inst) \ + COND_CODE_1(DT_INST_ON_BUS(inst, spi), \ + (LSM6DSR_DEFINE_SPI(inst)), \ + (LSM6DSR_DEFINE_I2C(inst))) + +DT_INST_FOREACH_STATUS_OKAY(LSM6DSR_DEFINE) diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr.h b/drivers/sensor/st/lsm6dsr/lsm6dsr.h new file mode 100644 index 0000000000000..ecb9a8cc195e7 --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr.h @@ -0,0 +1,179 @@ +/* sensor_lsm6dsr.h - header file for LSM6DSR accelerometer, gyroscope and + * temperature sensor driver + */ + +/* + * Copyright (c) 2025 Helbling Technik AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_SENSOR_LSM6DSR_LSM6DSR_H_ +#define ZEPHYR_DRIVERS_SENSOR_LSM6DSR_LSM6DSR_H_ + +#include +#include +#include +#include +#include + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) +#include +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ + +#define LSM6DSR_REG_FIFO_CTRL4 0x0A +#define LSM6DSR_MASK_FIFO_CTRL4_FIFO_MODE (BIT(2) | BIT(1) | BIT(0)) +#define LSM6DSR_SHIFT_FIFO_CTRL4_FIFO_MODE 0 + +#define LSM6DSR_REG_WHO_AM_I 0x0F +#define LSM6DSR_VAL_WHO_AM_I 0x6B + +#define LSM6DSR_REG_CTRL1_XL 0x10 +#define LSM6DSR_MASK_CTRL1_XL_ODR_XL (BIT(7) | BIT(6) | BIT(5) | BIT(4)) +#define LSM6DSR_SHIFT_CTRL1_XL_ODR_XL 4 +#define LSM6DSR_MASK_CTRL1_XL_FS_XL (BIT(3) | BIT(2)) +#define LSM6DSR_SHIFT_CTRL1_XL_FS_XL 2 + +#define LSM6DSR_REG_CTRL2_G 0x11 +#define LSM6DSR_MASK_CTRL2_G_ODR_G (BIT(7) | BIT(6) | BIT(5) | BIT(4)) +#define LSM6DSR_SHIFT_CTRL2_G_ODR_G 4 +#define LSM6DSR_MASK_CTRL2_G_FS_G (BIT(3) | BIT(2)) +#define LSM6DSR_SHIFT_CTRL2_G_FS_G 2 +#define LSM6DSR_MASK_CTRL2_FS125 BIT(1) +#define LSM6DSR_SHIFT_CTRL2_FS125 1 +#define LSM6DSR_MASK_CTRL2_FS4000 BIT(0) +#define LSM6DSR_SHIFT_CTRL2_FS4000 0 + +#define LSM6DSR_REG_CTRL3_C 0x12 +#define LSM6DSR_MASK_CTRL3_C_BOOT BIT(7) +#define LSM6DSR_SHIFT_CTRL3_C_BOOT 7 +#define LSM6DSR_MASK_CTRL3_C_BDU BIT(6) +#define LSM6DSR_SHIFT_CTRL3_C_BDU 6 +#define LSM6DSR_MASK_CTRL3_C_IF_INC BIT(2) +#define LSM6DSR_SHIFT_CTRL3_C_IF_INC 2 +#define LSM6DSR_MASK_CTRL3_C_MUST_BE_ZERO BIT(1) +#define LSM6DSR_SHIFT_CTRL3_C_MUST_BE_ZERO 1 + +#define LSM6DSR_REG_CTRL6_C 0x15 +#define LSM6DSR_MASK_CTRL6_C_XL_HM_MODE BIT(4) +#define LSM6DSR_SHIFT_CTRL6_C_XL_HM_MODE 4 + +#define LSM6DSR_REG_CTRL7_G 0x16 +#define LSM6DSR_MASK_CTRL7_G_HM_MODE BIT(7) +#define LSM6DSR_SHIFT_CTRL7_G_HM_MODE 7 + +#define LSM6DSR_REG_OUTX_L_G 0x22 +#define LSM6DSR_REG_OUTX_H_G 0x23 +#define LSM6DSR_REG_OUTY_L_G 0x24 +#define LSM6DSR_REG_OUTY_H_G 0x25 +#define LSM6DSR_REG_OUTZ_L_G 0x26 +#define LSM6DSR_REG_OUTZ_H_G 0x27 +#define LSM6DSR_REG_OUTX_L_XL 0x28 +#define LSM6DSR_REG_OUTX_H_XL 0x29 +#define LSM6DSR_REG_OUTY_L_XL 0x2A +#define LSM6DSR_REG_OUTY_H_XL 0x2B +#define LSM6DSR_REG_OUTZ_L_XL 0x2C +#define LSM6DSR_REG_OUTZ_H_XL 0x2D + +/* Accel sensor sensitivity grain is 61 ug/LSB */ +#define SENSI_GRAIN_XL 61LL + +/* Gyro sensor sensitivity grain is 4375 udps/LSB */ +#define SENSI_GRAIN_G 4375LL + +#if CONFIG_LSM6DSR_ACCEL_FS == 0 +#define LSM6DSR_ACCEL_FS_RUNTIME 1 +#define LSM6DSR_DEFAULT_ACCEL_FULLSCALE 0 +#define LSM6DSR_DEFAULT_ACCEL_SENSITIVITY SENSI_GRAIN_XL +#elif CONFIG_LSM6DSR_ACCEL_FS == 2 +#define LSM6DSR_DEFAULT_ACCEL_FULLSCALE 0 +#define LSM6DSR_DEFAULT_ACCEL_SENSITIVITY SENSI_GRAIN_XL +#elif CONFIG_LSM6DSR_ACCEL_FS == 4 +#define LSM6DSR_DEFAULT_ACCEL_FULLSCALE 2 +#define LSM6DSR_DEFAULT_ACCEL_SENSITIVITY (2.0 * SENSI_GRAIN_XL) +#elif CONFIG_LSM6DSR_ACCEL_FS == 8 +#define LSM6DSR_DEFAULT_ACCEL_FULLSCALE 3 +#define LSM6DSR_DEFAULT_ACCEL_SENSITIVITY (4.0 * SENSI_GRAIN_XL) +#elif CONFIG_LSM6DSR_ACCEL_FS == 16 +#define LSM6DSR_DEFAULT_ACCEL_FULLSCALE 1 +#define LSM6DSR_DEFAULT_ACCEL_SENSITIVITY (8.0 * SENSI_GRAIN_XL) +#endif + +#if (CONFIG_LSM6DSR_ACCEL_ODR == 0) +#define LSM6DSR_ACCEL_ODR_RUNTIME 1 +#endif + +#if CONFIG_LSM6DSR_GYRO_FS == 0 +#define LSM6DSR_GYRO_FS_RUNTIME 1 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 4 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY SENSI_GRAIN_G +#elif CONFIG_LSM6DSR_GYRO_FS == 125 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 4 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY SENSI_GRAIN_G +#elif CONFIG_LSM6DSR_GYRO_FS == 250 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 0 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY (2.0 * SENSI_GRAIN_G) +#elif CONFIG_LSM6DSR_GYRO_FS == 500 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 1 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY (4.0 * SENSI_GRAIN_G) +#elif CONFIG_LSM6DSR_GYRO_FS == 1000 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 2 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY (8.0 * SENSI_GRAIN_G) +#elif CONFIG_LSM6DSR_GYRO_FS == 2000 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 3 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY (16.0 * SENSI_GRAIN_G) +#elif CONFIG_LSM6DSR_GYRO_FS == 4000 +#define LSM6DSR_DEFAULT_GYRO_FULLSCALE 5 +#define LSM6DSR_DEFAULT_GYRO_SENSITIVITY (32.0 * SENSI_GRAIN_G) +#endif + +#if (CONFIG_LSM6DSR_GYRO_ODR == 0) +#define LSM6DSR_GYRO_ODR_RUNTIME 1 +#endif + +union lsm6dsr_bus_cfg { +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + struct i2c_dt_spec i2c; +#endif + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + struct spi_dt_spec spi; +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ +}; + +struct lsm6dsr_config { + int (*bus_init)(const struct device *dev); + const union lsm6dsr_bus_cfg bus_cfg; +}; + +struct lsm6dsr_data; + +struct lsm6dsr_transfer_function { + int (*read_data)(const struct device *dev, uint8_t reg_addr, uint8_t *value, uint8_t len); + int (*write_data)(const struct device *dev, uint8_t reg_addr, uint8_t *value, uint8_t len); + int (*read_reg)(const struct device *dev, uint8_t reg_addr, uint8_t *value); + int (*update_reg)(const struct device *dev, uint8_t reg_addr, uint8_t mask, uint8_t value); +}; + +struct lsm6dsr_data { + int accel_sample_x; + int accel_sample_y; + int accel_sample_z; + float accel_sensitivity; + int gyro_sample_x; + int gyro_sample_y; + int gyro_sample_z; + float gyro_sensitivity; + const struct lsm6dsr_transfer_function *hw_tf; + uint16_t accel_freq; + uint16_t gyro_freq; +}; + +int lsm6dsr_spi_init(const struct device *dev); +int lsm6dsr_i2c_init(const struct device *dev); + +#endif /* ZEPHYR_DRIVERS_SENSOR_LSM6DSR_LSM6DSR_H_ */ diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr_i2c.c b/drivers/sensor/st/lsm6dsr/lsm6dsr_i2c.c new file mode 100644 index 0000000000000..5dee64ffb6e68 --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr_i2c.c @@ -0,0 +1,74 @@ +/* lsm6dsr_i2c.c - I2C routines for LSM6DSR driver + */ + +/* + * Copyright (c) 2018 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_lsm6dsr + +#include +#include + +#include "lsm6dsr.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) + +LOG_MODULE_DECLARE(LSM6DSR, CONFIG_SENSOR_LOG_LEVEL); + +static int lsm6dsr_i2c_read_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct lsm6dsr_config *cfg = dev->config; + + return i2c_burst_read_dt(&cfg->bus_cfg.i2c, reg_addr, value, len); +} + +static int lsm6dsr_i2c_write_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct lsm6dsr_config *cfg = dev->config; + + return i2c_burst_write_dt(&cfg->bus_cfg.i2c, reg_addr, value, len); +} + +static int lsm6dsr_i2c_read_reg(const struct device *dev, uint8_t reg_addr, + uint8_t *value) +{ + const struct lsm6dsr_config *cfg = dev->config; + + return i2c_reg_read_byte_dt(&cfg->bus_cfg.i2c, reg_addr, value); +} + +static int lsm6dsr_i2c_update_reg(const struct device *dev, uint8_t reg_addr, + uint8_t mask, uint8_t value) +{ + const struct lsm6dsr_config *cfg = dev->config; + + return i2c_reg_update_byte_dt(&cfg->bus_cfg.i2c, reg_addr, mask, value); +} + + +static const struct lsm6dsr_transfer_function lsm6dsr_i2c_transfer_fn = { + .read_data = lsm6dsr_i2c_read_data, + .write_data = lsm6dsr_i2c_write_data, + .read_reg = lsm6dsr_i2c_read_reg, + .update_reg = lsm6dsr_i2c_update_reg, +}; + +int lsm6dsr_i2c_init(const struct device *dev) +{ + struct lsm6dsr_data *data = dev->data; + const struct lsm6dsr_config *cfg = dev->config; + + data->hw_tf = &lsm6dsr_i2c_transfer_fn; + + if (!device_is_ready(cfg->bus_cfg.i2c.bus)) { + return -ENODEV; + } + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(i2c) */ diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr_spi.c b/drivers/sensor/st/lsm6dsr/lsm6dsr_spi.c new file mode 100644 index 0000000000000..bb14095cd744a --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr_spi.c @@ -0,0 +1,144 @@ +/* lsm6dsr_spi.c - SPI routines for LSM6DSR driver + */ + +/* + * Copyright (c) 2018 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_lsm6dsr + +#include +#include + +#include "lsm6dsr.h" + +#if DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) + +#define LSM6DSR_SPI_READ (1 << 7) + +LOG_MODULE_DECLARE(LSM6DSR, CONFIG_SENSOR_LOG_LEVEL); + +static int lsm6dsr_raw_read(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct lsm6dsr_config *cfg = dev->config; + uint8_t buffer_tx[2] = { reg_addr | LSM6DSR_SPI_READ, 0 }; + const struct spi_buf tx_buf = { + .buf = buffer_tx, + .len = 2, + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + const struct spi_buf rx_buf[2] = { + { + .buf = NULL, + .len = 1, + }, + { + .buf = value, + .len = len, + } + }; + const struct spi_buf_set rx = { + .buffers = rx_buf, + .count = 2 + }; + + + if (len > 64) { + return -EIO; + } + + if (spi_transceive_dt(&cfg->bus_cfg.spi, &tx, &rx)) { + return -EIO; + } + + return 0; +} + +static int lsm6dsr_raw_write(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + const struct lsm6dsr_config *cfg = dev->config; + uint8_t buffer_tx[1] = { reg_addr & ~LSM6DSR_SPI_READ }; + const struct spi_buf tx_buf[2] = { + { + .buf = buffer_tx, + .len = 1, + }, + { + .buf = value, + .len = len, + } + }; + const struct spi_buf_set tx = { + .buffers = tx_buf, + .count = 2 + }; + + + if (len > 64) { + return -EIO; + } + + if (spi_write_dt(&cfg->bus_cfg.spi, &tx)) { + return -EIO; + } + + return 0; +} + +static int lsm6dsr_spi_read_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + return lsm6dsr_raw_read(dev, reg_addr, value, len); +} + +static int lsm6dsr_spi_write_data(const struct device *dev, uint8_t reg_addr, + uint8_t *value, uint8_t len) +{ + return lsm6dsr_raw_write(dev, reg_addr, value, len); +} + +static int lsm6dsr_spi_read_reg(const struct device *dev, uint8_t reg_addr, + uint8_t *value) +{ + return lsm6dsr_raw_read(dev, reg_addr, value, 1); +} + +static int lsm6dsr_spi_update_reg(const struct device *dev, uint8_t reg_addr, + uint8_t mask, uint8_t value) +{ + uint8_t tmp_val; + + lsm6dsr_raw_read(dev, reg_addr, &tmp_val, 1); + tmp_val = (tmp_val & ~mask) | (value & mask); + + return lsm6dsr_raw_write(dev, reg_addr, &tmp_val, 1); +} + +static const struct lsm6dsr_transfer_function lsm6dsr_spi_transfer_fn = { + .read_data = lsm6dsr_spi_read_data, + .write_data = lsm6dsr_spi_write_data, + .read_reg = lsm6dsr_spi_read_reg, + .update_reg = lsm6dsr_spi_update_reg, +}; + +int lsm6dsr_spi_init(const struct device *dev) +{ + struct lsm6dsr_data *data = dev->data; + const struct lsm6dsr_config *cfg = dev->config; + + data->hw_tf = &lsm6dsr_spi_transfer_fn; + + if (!spi_is_ready_dt(&cfg->bus_cfg.spi)) { + return -ENODEV; + } + + return 0; +} +#endif /* DT_ANY_INST_ON_BUS_STATUS_OKAY(spi) */ diff --git a/dts/bindings/sensor/st,lsm6dsr-common.yaml b/dts/bindings/sensor/st,lsm6dsr-common.yaml new file mode 100644 index 0000000000000..ebc20e4de3188 --- /dev/null +++ b/dts/bindings/sensor/st,lsm6dsr-common.yaml @@ -0,0 +1,4 @@ +# Copyright (c) 2025, Helbling Technik AG +# SPDX-License-Identifier: Apache-2.0 + +include: sensor-device.yaml diff --git a/dts/bindings/sensor/st,lsm6dsr-i2c.yaml b/dts/bindings/sensor/st,lsm6dsr-i2c.yaml new file mode 100644 index 0000000000000..9533583ad9b67 --- /dev/null +++ b/dts/bindings/sensor/st,lsm6dsr-i2c.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2025, Helbling Technik AG +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LSM6DSR 6-axis accelerometer and gyrometer accessed through + I2C bus + +compatible: "st,lsm6dsr" + +include: ["i2c-device.yaml", "st,lsm6dsr-common.yaml"] diff --git a/dts/bindings/sensor/st,lsm6dsr-spi.yaml b/dts/bindings/sensor/st,lsm6dsr-spi.yaml new file mode 100644 index 0000000000000..6df9a1c90f96c --- /dev/null +++ b/dts/bindings/sensor/st,lsm6dsr-spi.yaml @@ -0,0 +1,10 @@ +# Copyright (c) 2025, Helbling Technik AG +# SPDX-License-Identifier: Apache-2.0 + +description: | + STMicroelectronics LSM6DSR 6-axis accelerometer and gyrometer accessed through + SPI bus + +compatible: "st,lsm6dsr" + +include: ["spi-device.yaml", "st,lsm6dsr-common.yaml"] From 102037577c96bf5c6ab144b571596f9de2838cd1 Mon Sep 17 00:00:00 2001 From: Marco Schuler Date: Thu, 9 Oct 2025 09:10:42 +0200 Subject: [PATCH 2/3] drivers: sensor: st: Add triggered mode for lsm6dsr Add support for triggered measurement mode. Triggers can be passed to the application either via global work queue or a dedicated task within the driver. Origin: Original Signed-off-by: Marco Schuler --- drivers/sensor/st/lsm6dsr/CMakeLists.txt | 1 + drivers/sensor/st/lsm6dsr/Kconfig | 40 +++++ drivers/sensor/st/lsm6dsr/lsm6dsr.c | 37 +++-- drivers/sensor/st/lsm6dsr/lsm6dsr.h | 41 +++++ drivers/sensor/st/lsm6dsr/lsm6dsr_trigger.c | 162 ++++++++++++++++++++ dts/bindings/sensor/st,lsm6dsr-common.yaml | 5 + 6 files changed, 276 insertions(+), 10 deletions(-) create mode 100644 drivers/sensor/st/lsm6dsr/lsm6dsr_trigger.c diff --git a/drivers/sensor/st/lsm6dsr/CMakeLists.txt b/drivers/sensor/st/lsm6dsr/CMakeLists.txt index b9602bcd4c239..8eeb05805e8f6 100644 --- a/drivers/sensor/st/lsm6dsr/CMakeLists.txt +++ b/drivers/sensor/st/lsm6dsr/CMakeLists.txt @@ -5,3 +5,4 @@ zephyr_library() zephyr_library_sources(lsm6dsr.c) zephyr_library_sources(lsm6dsr_spi.c) zephyr_library_sources(lsm6dsr_i2c.c) +zephyr_library_sources_ifdef(CONFIG_LSM6DSR_TRIGGER lsm6dsr_trigger.c) diff --git a/drivers/sensor/st/lsm6dsr/Kconfig b/drivers/sensor/st/lsm6dsr/Kconfig index 6c019013486e8..73601035b39f8 100644 --- a/drivers/sensor/st/lsm6dsr/Kconfig +++ b/drivers/sensor/st/lsm6dsr/Kconfig @@ -16,6 +16,46 @@ menuconfig LSM6DSR if LSM6DSR +choice LSM6DSR_TRIGGER_MODE + prompt "Trigger mode" + help + Specify the type of triggering to be used by the driver. + +config LSM6DSR_TRIGGER_NONE + bool "No trigger" + +config LSM6DSR_TRIGGER_GLOBAL_THREAD + bool "Use global thread" + depends on GPIO + depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSR),irq-gpios) + select LSM6DSR_TRIGGER + +config LSM6DSR_TRIGGER_OWN_THREAD + bool "Use own thread" + depends on GPIO + depends on $(dt_compat_any_has_prop,$(DT_COMPAT_ST_LSM6DSR),irq-gpios) + select LSM6DSR_TRIGGER + +endchoice + +config LSM6DSR_TRIGGER + bool + +config LSM6DSR_THREAD_PRIORITY + int "Thread priority" + depends on LSM6DSR_TRIGGER_OWN_THREAD + default 10 + help + Priority of thread used by the driver to handle interrupts. + +config LSM6DSR_THREAD_STACK_SIZE + int "Thread stack size" + depends on LSM6DSR_TRIGGER_OWN_THREAD + default 1024 + help + Stack size of thread used by the driver to handle interrupts. + + menu "Attributes" config LSM6DSR_GYRO_FS diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr.c b/drivers/sensor/st/lsm6dsr/lsm6dsr.c index 5fc227d7383e4..18ed84da00af9 100644 --- a/drivers/sensor/st/lsm6dsr/lsm6dsr.c +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr.c @@ -482,6 +482,9 @@ static int lsm6dsr_channel_get(const struct device *dev, enum sensor_channel cha static DEVICE_API(sensor, lsm6dsr_driver_api) = { .attr_set = lsm6dsr_attr_set, +#if CONFIG_LSM6DSR_TRIGGER + .trigger_set = lsm6dsr_trigger_set, +#endif .sample_fetch = lsm6dsr_sample_fetch, .channel_get = lsm6dsr_channel_get, }; @@ -589,6 +592,14 @@ static int lsm6dsr_init(const struct device *dev) return ret; } +#ifdef CONFIG_LSM6DSR_TRIGGER + ret = lsm6dsr_init_interrupt(dev); + if (ret < 0) { + LOG_ERR("Failed to initialize interrupt."); + return ret; + } +#endif + return 0; } @@ -609,13 +620,19 @@ static int lsm6dsr_init(const struct device *dev) /* * Instantiation macros used when a device is on a SPI bus. */ + +#ifdef CONFIG_LSM6DSR_TRIGGER +#define LSM6DSR_CFG_IRQ(inst) .int_gpio = GPIO_DT_SPEC_INST_GET(inst, irq_gpios), +#else +#define LSM6DSR_CFG_IRQ(inst) +#endif /* CONFIG_LSM6DSR_TRIGGER */ + #define LSM6DSR_CONFIG_SPI(inst) \ - { \ - .bus_init = lsm6dsr_spi_init, \ - .bus_cfg.spi = SPI_DT_SPEC_INST_GET( \ - inst, \ - SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA, 0), \ - } + {.bus_init = lsm6dsr_spi_init, \ + .bus_cfg.spi = SPI_DT_SPEC_INST_GET( \ + inst, SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA, 0), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ + (LSM6DSR_CFG_IRQ(inst)), ()) } #define LSM6DSR_DEFINE_SPI(inst) \ static struct lsm6dsr_data lsm6dsr_data_##inst; \ @@ -627,10 +644,10 @@ static int lsm6dsr_init(const struct device *dev) */ #define LSM6DSR_CONFIG_I2C(inst) \ - { \ - .bus_init = lsm6dsr_i2c_init, \ - .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \ - } + {.bus_init = lsm6dsr_i2c_init, \ + .bus_cfg.i2c = I2C_DT_SPEC_INST_GET(inst), \ + COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, irq_gpios), \ + (LSM6DSR_CFG_IRQ(inst)), ()) } #define LSM6DSR_DEFINE_I2C(inst) \ static struct lsm6dsr_data lsm6dsr_data_##inst; \ diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr.h b/drivers/sensor/st/lsm6dsr/lsm6dsr.h index ecb9a8cc195e7..7eeb9f931dc75 100644 --- a/drivers/sensor/st/lsm6dsr/lsm6dsr.h +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr.h @@ -32,6 +32,20 @@ #define LSM6DSR_REG_WHO_AM_I 0x0F #define LSM6DSR_VAL_WHO_AM_I 0x6B +#define LSM6DSR_REG_INT1_CTRL 0x0D +#define LSM6DSR_MASK_INT1_CTRL_FULL BIT(5) +#define LSM6DSR_SHIFT_INT1_CTRL_FULL 5 +#define LSM6DSR_MASK_INT1_CTRL_FIFO_OVR BIT(4) +#define LSM6DSR_SHIFT_INT1_CTRL_FIFO_OVR 4 +#define LSM6DSR_MASK_INT1_FTH BIT(3) +#define LSM6DSR_SHIFT_INT1_FTH 3 +#define LSM6DSR_MASK_INT1_CTRL_BOOT BIT(2) +#define LSM6DSR_SHIFT_INT1_CTRL_BOOT 2 +#define LSM6DSR_MASK_INT1_CTRL_DRDY_G BIT(1) +#define LSM6DSR_SHIFT_INT1_CTRL_DRDY_G 1 +#define LSM6DSR_MASK_INT1_CTRL_DRDY_XL BIT(0) +#define LSM6DSR_SHIFT_INT1_CTRL_DRDY_XL 0 + #define LSM6DSR_REG_CTRL1_XL 0x10 #define LSM6DSR_MASK_CTRL1_XL_ODR_XL (BIT(7) | BIT(6) | BIT(5) | BIT(4)) #define LSM6DSR_SHIFT_CTRL1_XL_ODR_XL 4 @@ -148,6 +162,9 @@ union lsm6dsr_bus_cfg { struct lsm6dsr_config { int (*bus_init)(const struct device *dev); const union lsm6dsr_bus_cfg bus_cfg; +#ifdef CONFIG_LSM6DSR_TRIGGER + struct gpio_dt_spec int_gpio; +#endif }; struct lsm6dsr_data; @@ -171,9 +188,33 @@ struct lsm6dsr_data { const struct lsm6dsr_transfer_function *hw_tf; uint16_t accel_freq; uint16_t gyro_freq; + +#ifdef CONFIG_LSM6DSR_TRIGGER + const struct device *dev; + struct gpio_callback gpio_cb; + + const struct sensor_trigger *data_ready_trigger; + sensor_trigger_handler_t data_ready_handler; + +#if defined(CONFIG_LSM6DSR_TRIGGER_OWN_THREAD) + K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_LSM6DSR_THREAD_STACK_SIZE); + struct k_thread thread; + struct k_sem gpio_sem; +#elif defined(CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD) + struct k_work work; +#endif + +#endif /* CONFIG_LSM6DSR_TRIGGER */ }; int lsm6dsr_spi_init(const struct device *dev); int lsm6dsr_i2c_init(const struct device *dev); +#ifdef CONFIG_LSM6DSR_TRIGGER +int lsm6dsr_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); + +int lsm6dsr_init_interrupt(const struct device *dev); +#endif + #endif /* ZEPHYR_DRIVERS_SENSOR_LSM6DSR_LSM6DSR_H_ */ diff --git a/drivers/sensor/st/lsm6dsr/lsm6dsr_trigger.c b/drivers/sensor/st/lsm6dsr/lsm6dsr_trigger.c new file mode 100644 index 0000000000000..857763e102959 --- /dev/null +++ b/drivers/sensor/st/lsm6dsr/lsm6dsr_trigger.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2018 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT st_lsm6dsr + +#include +#include +#include +#include +#include +#include +#include +#include "lsm6dsr.h" + +LOG_MODULE_DECLARE(LSM6DSR, CONFIG_SENSOR_LOG_LEVEL); + +static inline void setup_irq(const struct device *dev, bool enable) +{ + const struct lsm6dsr_config *config = dev->config; + + unsigned int flags = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE; + + gpio_pin_interrupt_configure_dt(&config->int_gpio, flags); +} + +static inline void handle_irq(const struct device *dev) +{ + struct lsm6dsr_data *drv_data = dev->data; + + setup_irq(dev, false); + +#if defined(CONFIG_LSM6DSR_TRIGGER_OWN_THREAD) + k_sem_give(&drv_data->gpio_sem); +#elif defined(CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD) + k_work_submit(&drv_data->work); +#endif +} + +int lsm6dsr_trigger_set(const struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) +{ + const struct lsm6dsr_config *config = dev->config; + struct lsm6dsr_data *drv_data = dev->data; + + __ASSERT_NO_MSG(trig->type == SENSOR_TRIG_DATA_READY); + + /* If irq_gpio is not configured in DT just return error */ + if (!config->int_gpio.port) { + LOG_ERR("triggers not supported"); + return -ENOTSUP; + } + + setup_irq(dev, false); + + drv_data->data_ready_handler = handler; + if (handler == NULL) { + return 0; + } + + drv_data->data_ready_trigger = trig; + + setup_irq(dev, true); + if (gpio_pin_get_dt(&config->int_gpio) > 0) { + handle_irq(dev); + } + + return 0; +} + +static void lsm6dsr_gpio_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins) +{ + struct lsm6dsr_data *drv_data = CONTAINER_OF(cb, struct lsm6dsr_data, gpio_cb); + + ARG_UNUSED(pins); + + handle_irq(drv_data->dev); +} + +static void lsm6dsr_thread_cb(const struct device *dev) +{ + struct lsm6dsr_data *drv_data = dev->data; + + if (drv_data->data_ready_handler != NULL) { + drv_data->data_ready_handler(dev, drv_data->data_ready_trigger); + } + + setup_irq(dev, true); +} + +#ifdef CONFIG_LSM6DSR_TRIGGER_OWN_THREAD +static void lsm6dsr_thread(void *p1, void *p2, void *p3) +{ + ARG_UNUSED(p2); + ARG_UNUSED(p3); + + const struct device *dev = p1; + struct lsm6dsr_data *drv_data = dev->data; + + while (1) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + lsm6dsr_thread_cb(dev); + } +} +#endif + +#ifdef CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD +static void lsm6dsr_work_cb(struct k_work *work) +{ + struct lsm6dsr_data *drv_data = CONTAINER_OF(work, struct lsm6dsr_data, work); + + lsm6dsr_thread_cb(drv_data->dev); +} +#endif + +int lsm6dsr_init_interrupt(const struct device *dev) +{ + const struct lsm6dsr_config *config = dev->config; + struct lsm6dsr_data *drv_data = dev->data; + + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("GPIO device not ready"); + return -ENODEV; + } + + gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + + gpio_init_callback(&drv_data->gpio_cb, lsm6dsr_gpio_callback, BIT(config->int_gpio.pin)); + + if (gpio_add_callback(config->int_gpio.port, &drv_data->gpio_cb) < 0) { + LOG_ERR("Could not set gpio callback."); + return -EIO; + } + + /* enable data-ready interrupt */ + if (drv_data->hw_tf->update_reg( + dev, LSM6DSR_REG_INT1_CTRL, + LSM6DSR_MASK_INT1_CTRL_DRDY_XL | LSM6DSR_MASK_INT1_CTRL_DRDY_G, + BIT(LSM6DSR_SHIFT_INT1_CTRL_DRDY_XL) | BIT(LSM6DSR_SHIFT_INT1_CTRL_DRDY_G)) < + 0) { + LOG_ERR("Could not enable data-ready interrupt."); + return -EIO; + } + + drv_data->dev = dev; + +#if defined(CONFIG_LSM6DSR_TRIGGER_OWN_THREAD) + k_sem_init(&drv_data->gpio_sem, 0, K_SEM_MAX_LIMIT); + + k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_LSM6DSR_THREAD_STACK_SIZE, + lsm6dsr_thread, (void *)dev, NULL, NULL, + K_PRIO_COOP(CONFIG_LSM6DSR_THREAD_PRIORITY), 0, K_NO_WAIT); +#elif defined(CONFIG_LSM6DSR_TRIGGER_GLOBAL_THREAD) + drv_data->work.handler = lsm6dsr_work_cb; +#endif + + setup_irq(dev, true); + + return 0; +} diff --git a/dts/bindings/sensor/st,lsm6dsr-common.yaml b/dts/bindings/sensor/st,lsm6dsr-common.yaml index ebc20e4de3188..fe930ca4d7377 100644 --- a/dts/bindings/sensor/st,lsm6dsr-common.yaml +++ b/dts/bindings/sensor/st,lsm6dsr-common.yaml @@ -2,3 +2,8 @@ # SPDX-License-Identifier: Apache-2.0 include: sensor-device.yaml + +properties: + irq-gpios: + # This signal is active high when produced by the sensor + type: phandle-array From 551a23a4a946de51d7d08efda19c19f268a2bb97 Mon Sep 17 00:00:00 2001 From: Marco Schuler Date: Wed, 8 Oct 2025 17:54:57 +0200 Subject: [PATCH 3/3] samples: sensor: Add sample for ST lsm6dsr driver This sample demonstrates the usage for ST lsm6dsr inertial measurement unit (IMU) driver. Origin: Original Signed-off-by: Marco Schuler --- samples/sensor/lsm6dsr/CMakeLists.txt | 10 +++ samples/sensor/lsm6dsr/README.rst | 62 ++++++++++++++ samples/sensor/lsm6dsr/i2c.overlay | 13 +++ samples/sensor/lsm6dsr/prj.conf | 11 +++ samples/sensor/lsm6dsr/sample.yaml | 15 ++++ samples/sensor/lsm6dsr/spi.overlay | 15 ++++ samples/sensor/lsm6dsr/src/main.c | 119 ++++++++++++++++++++++++++ 7 files changed, 245 insertions(+) create mode 100644 samples/sensor/lsm6dsr/CMakeLists.txt create mode 100644 samples/sensor/lsm6dsr/README.rst create mode 100644 samples/sensor/lsm6dsr/i2c.overlay create mode 100644 samples/sensor/lsm6dsr/prj.conf create mode 100644 samples/sensor/lsm6dsr/sample.yaml create mode 100644 samples/sensor/lsm6dsr/spi.overlay create mode 100644 samples/sensor/lsm6dsr/src/main.c diff --git a/samples/sensor/lsm6dsr/CMakeLists.txt b/samples/sensor/lsm6dsr/CMakeLists.txt new file mode 100644 index 0000000000000..387f4ce08692c --- /dev/null +++ b/samples/sensor/lsm6dsr/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Helbling Technik AG +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(lsm6dsr) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/lsm6dsr/README.rst b/samples/sensor/lsm6dsr/README.rst new file mode 100644 index 0000000000000..a3a9428d371cb --- /dev/null +++ b/samples/sensor/lsm6dsr/README.rst @@ -0,0 +1,62 @@ +.. zephyr:code-sample:: lsmd6dsr + :name: LSM6DSR IMU sensor + :relevant-api: sensor_interface + + Get accelerometer and gyroscope data from an LSM6DSR sensor (polling). + +Overview +******** + +This sample sets the LSM6DSR accelerometer and gyroscope to 104Hz and reads the +values (polling) in a loop. It displays the values for accelerometer and +gyroscope on the console. + + +Requirements +************ + +This sample uses the LSM6DSR sensor controlled using the I2C or SPI interface. +It has been tested on the nRF52840 DK board with an STEVAL-MKI194V1 attached. + +References +********** + +- LSM6DSR https://www.st.com/en/mems-and-sensors/lsm6dsr.html +- STEVAL-MKI194V1 https://www.st.com/en/evaluation-tools/steval-mki194v1.html +- nRF52840 DK https://www.nordicsemi.com/Products/Development-hardware/nRF52840-DK + +Building and Running +******************** + +This project outputs sensor data to the console. It requires an LSM6DSR +sensor attached to the nRF52840 DK. + +There are two devicetree overlays to either chose building for I2C or SPI + +- i2c.overlay +- spi.overlay + +Use DEXTRA_DTC_OVERLAY_FILE to specify which one to use. + +Building on nRF52840 board +========================== + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/lsm6dsr + :host-os: unix + :board: nRF52840 + :goals: build + :compact: + +Sample Output +============= + +.. code-block:: console + + LSM6DSR sensor samples: + + accel x:4.705485 ms/2 y:-8.873782 ms/2 z:0.023928 ms/2 + gyro x:0.006490 dps y:-0.007559 dps z:-0.002977 dps + loop:4 trig_cnt:339 + + diff --git a/samples/sensor/lsm6dsr/i2c.overlay b/samples/sensor/lsm6dsr/i2c.overlay new file mode 100644 index 0000000000000..9064309a1990e --- /dev/null +++ b/samples/sensor/lsm6dsr/i2c.overlay @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2025 Helbling Technik AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&i2c0 { + lsm6dsr: lsm6dsr@6b { + compatible = "st,lsm6dsr"; + reg = <0x6b>; + irq-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/samples/sensor/lsm6dsr/prj.conf b/samples/sensor/lsm6dsr/prj.conf new file mode 100644 index 0000000000000..3a439b3e39cb8 --- /dev/null +++ b/samples/sensor/lsm6dsr/prj.conf @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Helbling Technik AG +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_STDOUT_CONSOLE=y +CONFIG_I2C=y +CONFIG_SPI=y +CONFIG_SENSOR=y +CONFIG_CBPRINTF_FP_SUPPORT=y + +CONFIG_LSM6DSR_TRIGGER_OWN_THREAD=y diff --git a/samples/sensor/lsm6dsr/sample.yaml b/samples/sensor/lsm6dsr/sample.yaml new file mode 100644 index 0000000000000..444f26382121b --- /dev/null +++ b/samples/sensor/lsm6dsr/sample.yaml @@ -0,0 +1,15 @@ +sample: + name: LSM6DSR accelerometer and gyrometer sensor +tests: + sample.sensor.lsm6dsr: + harness: console + tags: sensors + depends_on: lsm6dsr + timeout: 15 + harness_config: + type: multi_line + ordered: true + regex: + - "accel x:[-.0-9]* ms/2 y:[-.0-9]* ms/2 z:[-.0-9]* ms/2" + - "gyro x:[-.0-9]* dps y:[-.0-9]* dps z:[-.0-9]* dps" + - "loop:[0-9]* trig_cnt:[0-9]*" diff --git a/samples/sensor/lsm6dsr/spi.overlay b/samples/sensor/lsm6dsr/spi.overlay new file mode 100644 index 0000000000000..1bbe7f95efb2d --- /dev/null +++ b/samples/sensor/lsm6dsr/spi.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Helbling Technik AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi1 { + cs-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + lsm6dsr: lsm6dsr@0 { + compatible = "st,lsm6dsr"; + reg = <0>; + irq-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + spi-max-frequency = <4000000>; + }; +}; diff --git a/samples/sensor/lsm6dsr/src/main.c b/samples/sensor/lsm6dsr/src/main.c new file mode 100644 index 0000000000000..cd5dc2db907b6 --- /dev/null +++ b/samples/sensor/lsm6dsr/src/main.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025 Helbling Technik AG + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +static int print_samples; +static int lsm6dsr_trig_cnt; + +static struct sensor_value accel_x_out, accel_y_out, accel_z_out; +static struct sensor_value gyro_x_out, gyro_y_out, gyro_z_out; + +#ifdef CONFIG_LSM6DSR_TRIGGER +static void lsm6dsr_trigger_handler(const struct device *dev, const struct sensor_trigger *trig) +{ + static struct sensor_value accel_x, accel_y, accel_z; + static struct sensor_value gyro_x, gyro_y, gyro_z; + + lsm6dsr_trig_cnt++; + + sensor_sample_fetch_chan(dev, SENSOR_CHAN_ACCEL_XYZ); + sensor_channel_get(dev, SENSOR_CHAN_ACCEL_X, &accel_x); + sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Y, &accel_y); + sensor_channel_get(dev, SENSOR_CHAN_ACCEL_Z, &accel_z); + + /* lsm6dsr gyro */ + sensor_sample_fetch_chan(dev, SENSOR_CHAN_GYRO_XYZ); + sensor_channel_get(dev, SENSOR_CHAN_GYRO_X, &gyro_x); + sensor_channel_get(dev, SENSOR_CHAN_GYRO_Y, &gyro_y); + sensor_channel_get(dev, SENSOR_CHAN_GYRO_Z, &gyro_z); + + if (print_samples) { + print_samples = 0; + + accel_x_out = accel_x; + accel_y_out = accel_y; + accel_z_out = accel_z; + + gyro_x_out = gyro_x; + gyro_y_out = gyro_y; + gyro_z_out = gyro_z; + } +} +#endif + +int main(void) +{ + int cnt = 0; + char out_str[64]; + struct sensor_value odr_attr; + const struct device *const lsm6dsr_dev = DEVICE_DT_GET_ONE(st_lsm6dsr); + + if (!device_is_ready(lsm6dsr_dev)) { + printk("sensor: device not ready.\n"); + return 0; + } + + /* set accel/gyro sampling frequency to 104 Hz */ + odr_attr.val1 = 104; + odr_attr.val2 = 0; + + if (sensor_attr_set(lsm6dsr_dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, + &odr_attr) < 0) { + printk("Cannot set sampling frequency for accelerometer.\n"); + return 0; + } + + if (sensor_attr_set(lsm6dsr_dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, + &odr_attr) < 0) { + printk("Cannot set sampling frequency for gyro.\n"); + return 0; + } + +#ifdef CONFIG_LSM6DSR_TRIGGER + struct sensor_trigger trig; + + trig.type = SENSOR_TRIG_DATA_READY; + trig.chan = SENSOR_CHAN_ACCEL_XYZ; + + if (sensor_trigger_set(lsm6dsr_dev, &trig, lsm6dsr_trigger_handler) != 0) { + printk("Could not set sensor type and channel\n"); + return 0; + } +#endif + + if (sensor_sample_fetch(lsm6dsr_dev) < 0) { + printk("Sensor sample update error\n"); + return 0; + } + + while (1) { + /* Erase previous */ + printk("\0033\014"); + printf("LSM6DSR sensor samples:\n\n"); + + /* lsm6dsr accel */ + sprintf(out_str, "accel x:%f ms/2 y:%f ms/2 z:%f ms/2", + sensor_value_to_double(&accel_x_out), sensor_value_to_double(&accel_y_out), + sensor_value_to_double(&accel_z_out)); + printk("%s\n", out_str); + + /* lsm6dsr gyro */ + sprintf(out_str, "gyro x:%f dps y:%f dps z:%f dps", + sensor_value_to_double(&gyro_x_out), sensor_value_to_double(&gyro_y_out), + sensor_value_to_double(&gyro_z_out)); + printk("%s\n", out_str); + + printk("loop:%d trig_cnt:%d\n\n", ++cnt, lsm6dsr_trig_cnt); + + print_samples = 1; + k_sleep(K_MSEC(1000)); + } +}