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 <armando.visconti@st.com>
This commit is contained in:
Armando Visconti 2025-04-09 11:29:48 +02:00 committed by Benjamin Cabé
parent afe0abea42
commit 44a67ea403
11 changed files with 415 additions and 0 deletions

View File

@ -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})

View File

@ -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 <rtio>` based :ref:`Read and Decode method <sensor-read-and-decode>`.
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

View File

@ -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

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/sensor/lsm6dsv16x.h>
/*
* 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 = <LSM6DSV16X_DT_ODR_AT_120Hz>;
accel-range = <LSM6DSV16X_DT_FS_16G>;
int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */
drdy-pin = <2>;
drdy-pulsed;
};
};

View File

@ -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

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2024 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/sensor/lsm6dsv16x.h>
/*
* 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 = <LSM6DSV16X_DT_ODR_AT_120Hz>;
accel-range = <LSM6DSV16X_DT_FS_16G>;
int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */
drdy-pin = <2>;
drdy-pulsed;
};
};

View File

@ -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

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2025 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/sensor/lsm6dsv16x.h>
/*
* 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 = <LSM6DSV16X_DT_ODR_AT_960Hz>;
accel-range = <LSM6DSV16X_DT_FS_16G>;
};
};

View File

@ -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

View File

@ -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\\.]*\\)$"

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2024 STMicroelectronics
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/util_macro.h>
#include <zephyr/kernel.h>
#include <zephyr/rtio/rtio.h>
#include <zephyr/drivers/sensor.h>
#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;
}