From 44a67ea40390c67423a96d64eef906c34d66f1ba Mon Sep 17 00:00:00 2001 From: Armando Visconti Date: Wed, 9 Apr 2025 11:29:48 +0200 Subject: [PATCH] samples/sensor: Add sample to read RTIO stream using drdy Add sample to read from up to 10 streaming devices, using the sensor_stream() API and the RTIO framework: https://docs.zephyrproject.org/latest/services/rtio/index.html The devices has to be aliased as streamN (0 <= N <= 9) in DT, and will be instantiated using SENSOR_DT_STREAM_IODEV() macro. Currently the sample gets/prints data on SENSOR_TRIG_DATA_READY trigger basis for the following sensor channels: - SENSOR_CHAN_ACCEL_XYZ Signed-off-by: Armando Visconti --- samples/sensor/stream_drdy/CMakeLists.txt | 10 ++ samples/sensor/stream_drdy/README.rst | 113 ++++++++++++ .../stream_drdy/boards/nucleo_f401re.conf | 6 + .../stream_drdy/boards/nucleo_f401re.overlay | 32 ++++ .../stream_drdy/boards/nucleo_h503rb.conf | 6 + .../stream_drdy/boards/nucleo_h503rb.overlay | 32 ++++ .../boards/sensortile_box_pro.conf | 6 + .../boards/sensortile_box_pro.overlay | 27 +++ samples/sensor/stream_drdy/prj.conf | 7 + samples/sensor/stream_drdy/sample.yaml | 12 ++ samples/sensor/stream_drdy/src/main.c | 164 ++++++++++++++++++ 11 files changed, 415 insertions(+) create mode 100644 samples/sensor/stream_drdy/CMakeLists.txt create mode 100644 samples/sensor/stream_drdy/README.rst create mode 100644 samples/sensor/stream_drdy/boards/nucleo_f401re.conf create mode 100644 samples/sensor/stream_drdy/boards/nucleo_f401re.overlay create mode 100644 samples/sensor/stream_drdy/boards/nucleo_h503rb.conf create mode 100644 samples/sensor/stream_drdy/boards/nucleo_h503rb.overlay create mode 100644 samples/sensor/stream_drdy/boards/sensortile_box_pro.conf create mode 100644 samples/sensor/stream_drdy/boards/sensortile_box_pro.overlay create mode 100644 samples/sensor/stream_drdy/prj.conf create mode 100644 samples/sensor/stream_drdy/sample.yaml create mode 100644 samples/sensor/stream_drdy/src/main.c diff --git a/samples/sensor/stream_drdy/CMakeLists.txt b/samples/sensor/stream_drdy/CMakeLists.txt new file mode 100644 index 00000000000..9cfea4ac1e8 --- /dev/null +++ b/samples/sensor/stream_drdy/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(stream_drdy) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/stream_drdy/README.rst b/samples/sensor/stream_drdy/README.rst new file mode 100644 index 00000000000..776f763c20a --- /dev/null +++ b/samples/sensor/stream_drdy/README.rst @@ -0,0 +1,113 @@ +.. zephyr:code-sample:: stream_drdy + :name: Generic device sample streaming using Data Ready trigger + :relevant-api: sensor_interface + + Get accelerometer data frames from a sensor using SENSOR_TRIG_DATA_READY. + +Overview +******** + +This sample application demonstrates how to stream accel data using the +:ref:`RTIO framework ` based :ref:`Read and Decode method `. + +The streaming is started using the sensor_stream() API and it is self-sustained by the +SENSOR_TRIG_DATA_READY trigger. + +Currently the sample gets/prints data only for the accel sensor channel: + + - SENSOR_CHAN_ACCEL_XYZ + +Building and Running +******************** + +This sample supports up to 10 streaming devices. Each device needs +to be aliased as ``streamN`` where ``N`` goes from ``0`` to ``9``. For example: + +.. code-block:: devicetree + + / { + aliases { + stream0 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + }; + }; + +Example devicetree overlays and configurations are already available for sensortile_box_pro, +nucleo_f401re and nucleo_h503rb in the boards directory: + +- :zephyr_file:`samples/sensor/stream_drdy/boards/sensortile_box_pro.overlay` + + DT overlay file for the sensortile_box_pro board. + +- :zephyr_file:`samples/sensor/stream_drdy/boards/sensortile_box_pro.conf` + + Configuration file for the sensortile_box_pro board. + +- :zephyr_file:`samples/sensor/stream_drdy/boards/nucleo_f401re.overlay` + + DT overlay file for the nucleo_f401re board. + +- :zephyr_file:`samples/sensor/stream_drdy/boards/nucleo_f401re.conf` + + Configuration file for the nucleo_f401re board. + +- :zephyr_file:`samples/sensor/stream_drdy/boards/nucleo_h503rb.overlay` + + DT overlay file for the nucleo_h503rb board. + +- :zephyr_file:`samples/sensor/stream_drdy/boards/nucleo_h503rb.conf` + + Configuration file for the nucleo_h503rb board. + +For example, build and run sample for sensortile_box_pro with: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/stream_drdy + :board: sensortile_box_pro + :goals: build flash + :compact: + +Sample Output +============= + +The following example output is for a lsm6dsv16x IMU device with accelerometer sensor. +The board used is a sensortile_box_pro. + +.. code-block:: console + +XL data for lsm6dsv16x@0 7320515312ns (-0.387584, 0.224894, 9.766184) +XL data for lsm6dsv16x@0 7321538600ns (-0.363659, 0.282314, 9.948014) +XL data for lsm6dsv16x@0 7322561362ns (-0.301454, 0.172259, 9.775754) +XL data for lsm6dsv16x@0 7323584881ns (-0.210539, 0.153119, 9.857099) +XL data for lsm6dsv16x@0 7324608368ns (-0.287099, 0.167474, 9.852314) +XL data for lsm6dsv16x@0 7325631281ns (-0.306239, 0.181829, 9.847529) +XL data for lsm6dsv16x@0 7326654425ns (-0.272744, 0.167474, 9.842744) +XL data for lsm6dsv16x@0 7327677993ns (-0.296669, 0.224894, 9.981509) +XL data for lsm6dsv16x@0 7328701506ns (-0.282314, 0.210539, 9.828389) +XL data for lsm6dsv16x@0 7329724306ns (-0.244034, 0.153119, 9.866669) +XL data for lsm6dsv16x@0 7330747556ns (-0.234464, 0.119624, 9.780539) +XL data for lsm6dsv16x@0 7331771000ns (-0.239249, 0.148334, 9.933659) +XL data for lsm6dsv16x@0 7332794575ns (-0.220109, 0.119624, 9.833174) +XL data for lsm6dsv16x@0 7333817437ns (-0.205754, 0.119624, 9.823604) +XL data for lsm6dsv16x@0 7334840643ns (-0.205754, 0.148334, 9.866669) +XL data for lsm6dsv16x@0 7335864162ns (-0.186614, 0.129194, 9.861884) +XL data for lsm6dsv16x@0 7336887593ns (-0.196184, 0.110054, 9.804464) +XL data for lsm6dsv16x@0 7337910356ns (-0.181829, 0.133979, 9.938444) +XL data for lsm6dsv16x@0 7338933650ns (-0.215324, 0.081344, 9.536504) +XL data for lsm6dsv16x@0 7339957075ns (-0.157904, 0.119624, 9.995864) +XL data for lsm6dsv16x@0 7340980675ns (-0.205754, 0.110054, 9.809249) +XL data for lsm6dsv16x@0 7342003487ns (-0.177044, 0.143549, 9.971939) +XL data for lsm6dsv16x@0 7343026593ns (-0.172259, 0.100484, 9.794894) +XL data for lsm6dsv16x@0 7344050168ns (-0.177044, 0.124409, 9.881024) +XL data for lsm6dsv16x@0 7345073643ns (-0.191399, 0.124409, 9.986294) +XL data for lsm6dsv16x@0 7346096587ns (-0.191399, 0.105269, 9.790109) + +References +========== + +.. target-notes:: + +.. _RTIO framework: + https://docs.zephyrproject.org/latest/services/rtio/index.html + +.. _x-nucleo-iks4a1: + http://www.st.com/en/ecosystems/x-nucleo-iks4a1.html diff --git a/samples/sensor/stream_drdy/boards/nucleo_f401re.conf b/samples/sensor/stream_drdy/boards/nucleo_f401re.conf new file mode 100644 index 00000000000..877b30fd2d6 --- /dev/null +++ b/samples/sensor/stream_drdy/boards/nucleo_f401re.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2C_RTIO=y +CONFIG_LSM6DSV16X_STREAM=y +CONFIG_LSM6DSV16X_ENABLE_TEMP=y diff --git a/samples/sensor/stream_drdy/boards/nucleo_f401re.overlay b/samples/sensor/stream_drdy/boards/nucleo_f401re.overlay new file mode 100644 index 00000000000..0ae04ca70ce --- /dev/null +++ b/samples/sensor/stream_drdy/boards/nucleo_f401re.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + +/* + * Nucleo F401RE board + shield iks4a1 + * + * This devicetree overlay file will be automatically picked by the Zephyr + * build system when building the sample for the nucleo_f401re board. + */ + +/ { + aliases { + stream0 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + }; +}; + +&arduino_i2c { + lsm6dsv16x_6b_x_nucleo_iks4a1: lsm6dsv16x@6b { + compatible = "st,lsm6dsv16x"; + reg = <0x6b>; + accel-odr = ; + accel-range = ; + int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */ + drdy-pin = <2>; + drdy-pulsed; + }; +}; diff --git a/samples/sensor/stream_drdy/boards/nucleo_h503rb.conf b/samples/sensor/stream_drdy/boards/nucleo_h503rb.conf new file mode 100644 index 00000000000..877b30fd2d6 --- /dev/null +++ b/samples/sensor/stream_drdy/boards/nucleo_h503rb.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_I2C_RTIO=y +CONFIG_LSM6DSV16X_STREAM=y +CONFIG_LSM6DSV16X_ENABLE_TEMP=y diff --git a/samples/sensor/stream_drdy/boards/nucleo_h503rb.overlay b/samples/sensor/stream_drdy/boards/nucleo_h503rb.overlay new file mode 100644 index 00000000000..0ae04ca70ce --- /dev/null +++ b/samples/sensor/stream_drdy/boards/nucleo_h503rb.overlay @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + +/* + * Nucleo F401RE board + shield iks4a1 + * + * This devicetree overlay file will be automatically picked by the Zephyr + * build system when building the sample for the nucleo_f401re board. + */ + +/ { + aliases { + stream0 = &lsm6dsv16x_6b_x_nucleo_iks4a1; + }; +}; + +&arduino_i2c { + lsm6dsv16x_6b_x_nucleo_iks4a1: lsm6dsv16x@6b { + compatible = "st,lsm6dsv16x"; + reg = <0x6b>; + accel-odr = ; + accel-range = ; + int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */ + drdy-pin = <2>; + drdy-pulsed; + }; +}; diff --git a/samples/sensor/stream_drdy/boards/sensortile_box_pro.conf b/samples/sensor/stream_drdy/boards/sensortile_box_pro.conf new file mode 100644 index 00000000000..c0b1e377b34 --- /dev/null +++ b/samples/sensor/stream_drdy/boards/sensortile_box_pro.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2025 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SPI_RTIO=y +CONFIG_LSM6DSV16X_STREAM=y +CONFIG_LSM6DSV16X_ENABLE_TEMP=y diff --git a/samples/sensor/stream_drdy/boards/sensortile_box_pro.overlay b/samples/sensor/stream_drdy/boards/sensortile_box_pro.overlay new file mode 100644 index 00000000000..2235a257112 --- /dev/null +++ b/samples/sensor/stream_drdy/boards/sensortile_box_pro.overlay @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include + + +/* + * This devicetree overlay file will be automatically picked by the Zephyr + * build system when building the sample for the sensortile_box_pro board. + */ + +/ { + aliases { + stream0 = &lsm6dsv16x_0; + }; +}; + +&spi2 { + lsm6dsv16x_0: lsm6dsv16x@0 { + compatible = "st,lsm6dsv16x"; + + accel-odr = ; + accel-range = ; + }; +}; diff --git a/samples/sensor/stream_drdy/prj.conf b/samples/sensor/stream_drdy/prj.conf new file mode 100644 index 00000000000..b638fffcb38 --- /dev/null +++ b/samples/sensor/stream_drdy/prj.conf @@ -0,0 +1,7 @@ +# Copyright (c) 2024 STMicroelectronics +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_STDOUT_CONSOLE=y +CONFIG_SENSOR=y +CONFIG_SENSOR_ASYNC_API=y +CONFIG_CBPRINTF_FP_SUPPORT=y diff --git a/samples/sensor/stream_drdy/sample.yaml b/samples/sensor/stream_drdy/sample.yaml new file mode 100644 index 00000000000..9e5c79ba825 --- /dev/null +++ b/samples/sensor/stream_drdy/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: Stream sample on Data Ready trigger +tests: + sample.sensor.stream_drdy: + harness: console + tags: sensors + filter: dt_alias_exists("stream0") + harness_config: + type: one_line + regex: + - "^\\s*[0-9A-Za-z_,+-.]*@[0-9A-Fa-f]* \\[m\/s\\^2\\]: \ + \\(\\s*-?[0-9\\.]*,\\s*-?[0-9\\.]*,\\s*-?[0-9\\.]*\\)$" diff --git a/samples/sensor/stream_drdy/src/main.c b/samples/sensor/stream_drdy/src/main.c new file mode 100644 index 00000000000..d46048981f5 --- /dev/null +++ b/samples/sensor/stream_drdy/src/main.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2024 STMicroelectronics + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define STREAMDEV_ALIAS(i) DT_ALIAS(_CONCAT(stream, i)) +#define STREAMDEV_DEVICE(i, _) \ + IF_ENABLED(DT_NODE_EXISTS(STREAMDEV_ALIAS(i)), (DEVICE_DT_GET(STREAMDEV_ALIAS(i)),)) +#define NUM_SENSORS 1 + +/* support up to 10 sensors */ +static const struct device *const sensors[] = { LISTIFY(10, STREAMDEV_DEVICE, ()) }; + +#define STREAM_IODEV_SYM(id) CONCAT(accel_iodev, id) +#define STREAM_IODEV_PTR(id, _) &STREAM_IODEV_SYM(id) + +#define STREAM_TRIGGERS \ + { SENSOR_TRIG_DATA_READY, SENSOR_STREAM_DATA_INCLUDE } + +#define STREAM_DEFINE_IODEV(id, _) \ + SENSOR_DT_STREAM_IODEV( \ + STREAM_IODEV_SYM(id), \ + STREAMDEV_ALIAS(id), \ + STREAM_TRIGGERS); + +LISTIFY(NUM_SENSORS, STREAM_DEFINE_IODEV, (;)); + +struct rtio_iodev *iodevs[NUM_SENSORS] = { LISTIFY(NUM_SENSORS, STREAM_IODEV_PTR, (,)) }; + +RTIO_DEFINE_WITH_MEMPOOL(stream_ctx, NUM_SENSORS, NUM_SENSORS, + NUM_SENSORS * 20, 256, sizeof(void *)); + +struct sensor_chan_spec accel_chan = { SENSOR_CHAN_ACCEL_XYZ, 0 }; + +static uint8_t accel_buf[128] = { 0 }; + +static int print_accels_stream(const struct device *dev, struct rtio_iodev *iodev) +{ + int rc = 0; + const struct sensor_decoder_api *decoder; + struct rtio_cqe *cqe; + uint8_t *buf; + uint32_t buf_len; + struct rtio_sqe *handles[NUM_SENSORS]; + struct sensor_three_axis_data *accel_data = (struct sensor_three_axis_data *)accel_buf; + + /* Start the streams */ + for (int i = 0; i < NUM_SENSORS; i++) { + printk("sensor_stream\n"); + sensor_stream(iodevs[i], &stream_ctx, NULL, &handles[i]); + } + + while (1) { + cqe = rtio_cqe_consume_block(&stream_ctx); + + if (cqe->result != 0) { + printk("async read failed %d\n", cqe->result); + return cqe->result; + } + + rc = rtio_cqe_get_mempool_buffer(&stream_ctx, cqe, &buf, &buf_len); + + if (rc != 0) { + printk("get mempool buffer failed %d\n", rc); + return rc; + } + + const struct device *sensor = dev; + + rtio_cqe_release(&stream_ctx, cqe); + + rc = sensor_get_decoder(sensor, &decoder); + + if (rc != 0) { + printk("sensor_get_decoder failed %d\n", rc); + return rc; + } + + /* Frame iterator values */ + uint32_t accel_fit = 0; + + /* Number of sensor data frames */ + uint16_t xl_count, frame_count; + + rc = decoder->get_frame_count(buf, accel_chan, &xl_count); + + if (rc != 0) { + printk("sensor_get_frame failed %d\n", rc); + return rc; + } + + frame_count = xl_count; + + /* If a tap has occurred lets print it out */ + if (decoder->has_trigger(buf, SENSOR_TRIG_TAP)) { + printk("Tap! Sensor %s\n", dev->name); + } + + + int8_t c = 0; + + /* decode and print Accelerometer frames */ + c = decoder->decode(buf, accel_chan, &accel_fit, 1, accel_data); + + printk("XL data for %s %lluns (%" PRIq(6) ", %" PRIq(6) + ", %" PRIq(6) ")\n", dev->name, + PRIsensor_three_axis_data_arg(*accel_data, 0)); + + rtio_release_buffer(&stream_ctx, buf, buf_len); + } + + return rc; +} + +static int check_sensor_is_off(const struct device *dev) +{ + int ret; + struct sensor_value odr; + + ret = sensor_attr_get(dev, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr); + + /* Check if accel is off */ + if (ret != 0 || (odr.val1 == 0 && odr.val2 == 0)) { + printk("%s WRN : accelerometer device is off\n", dev->name); + } + + return 0; +} + +int main(void) +{ + int ret; + + for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { + if (!device_is_ready(sensors[i])) { + printk("sensor: device %s not ready.\n", sensors[i]->name); + return 0; + } + check_sensor_is_off(sensors[i]); + } + + while (1) { + for (size_t i = 0; i < ARRAY_SIZE(sensors); i++) { + ret = print_accels_stream(sensors[i], iodevs[i]); + + if (ret < 0) { + return 0; + } + } + k_msleep(1000); + } + return 0; +}