diff --git a/samples/sensor/stream_fifo/CMakeLists.txt b/samples/sensor/stream_fifo/CMakeLists.txt new file mode 100644 index 000000000000000..e056c0a32bc8238 --- /dev/null +++ b/samples/sensor/stream_fifo/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_fifo) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/samples/sensor/stream_fifo/README.rst b/samples/sensor/stream_fifo/README.rst new file mode 100644 index 000000000000000..8577395b06b6609 --- /dev/null +++ b/samples/sensor/stream_fifo/README.rst @@ -0,0 +1,148 @@ +.. zephyr:code-sample:: stream_fifo + :name: Generic device FIFO streaming + :relevant-api: sensor_interface + + Get accelerometer/gyroscope/temperature FIFO data frames from a sensor using + SENSOR_TRIG_FIFO_WATERMARK as a trigger. + +Overview +******** + +This sample application demonstrates how to stream FIFO data using the `RTIO framework`_. + +The streaming is started using the sensor_stream() API and it is self-sustained by the +SENSOR_TRIG_FIFO_WATERMARK trigger. + +Currently the sample gets/prints data for the following sensor channels: + + - SENSOR_CHAN_ACCEL_XYZ + - SENSOR_CHAN_GYRO_XYZ + - SENSOR_CHAN_DIE_TEMP + +Building and Running +******************** + +This sample supports up to 10 FIFO 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 nucleo_f401re and +nucleo_h503rb in the boards directory: + +- :zephyr_file:`samples/sensor/stream_fifo/boards/nucleo_f401re.overlay` + + DT overlay file for the nucleo_f401re board. + +- :zephyr_file:`samples/sensor/stream_fifo/boards/nucleo_f401re.conf` + + Configuration file for the nucleo_f401re board. + +- :zephyr_file:`samples/sensor/stream_fifo/boards/nucleo_h503rb.overlay` + + DT overlay file for the nucleo_h503rb board. + +- :zephyr_file:`samples/sensor/stream_fifo/boards/nucleo_h503rb.conf` + + Configuration file for the nucleo_h503rb board. + +For example, build and run sample for nucleo_h503rb with: + +.. zephyr-app-commands:: + :zephyr-app: samples/sensor/stream_fifo + :board: nucleo_h503rb + :goals: build flash + :compact: + +Sample Output +============= + +The following example output is for a lsm6dsv16x IMU device with accelerometer, gyroscope +and temperature sensors. The FIFO watermark is set to 64. The board used is a nucleo_h503rb +equipped with a `x-nucleo-iks4a1`_ shield. + +.. code-block:: console + + FIFO count - 65 + XL data for lsm6dsv16x@6b 708054166675ns (0.267959, -0.162689, 9.933659) + XL data for lsm6dsv16x@6b 708087500008ns (0.258389, -0.162689, 9.919304) + XL data for lsm6dsv16x@6b 708120833341ns (0.253604, -0.167474, 9.909734) + XL data for lsm6dsv16x@6b 708154166674ns (0.258389, -0.153119, 9.933659) + XL data for lsm6dsv16x@6b 708187500007ns (0.253604, -0.157904, 9.919304) + XL data for lsm6dsv16x@6b 708220833340ns (0.258389, -0.162689, 9.943229) + XL data for lsm6dsv16x@6b 708254166673ns (0.258389, -0.157904, 9.904949) + XL data for lsm6dsv16x@6b 708287500006ns (0.253604, -0.162689, 9.952799) + GY data for lsm6dsv16x@6b 708054166675ns (0.000609, 0.000000, 0.004574) + GY data for lsm6dsv16x@6b 708087500008ns (-0.000304, 0.000304, 0.003964) + GY data for lsm6dsv16x@6b 708120833341ns (-0.000609, 0.000304, 0.004269) + GY data for lsm6dsv16x@6b 708154166674ns (0.000304, -0.000304, 0.004879) + GY data for lsm6dsv16x@6b 708187500007ns (0.001219, -0.001524, 0.004269) + GY data for lsm6dsv16x@6b 708220833340ns (-0.000914, -0.000609, 0.004879) + GY data for lsm6dsv16x@6b 708254166673ns (0.000000, -0.000304, 0.004269) + GY data for lsm6dsv16x@6b 708287500006ns (0.000609, 0.000000, 0.004574) + TP data for lsm6dsv16x@6b 708087500008ns 24.390625 °C + TP data for lsm6dsv16x@6b 708154166674ns 24.421875 °C + TP data for lsm6dsv16x@6b 708220833340ns 24.414062 °C + TP data for lsm6dsv16x@6b 708287500006ns 24.441406 °C + XL data for lsm6dsv16x@6b 708320833339ns (0.258389, -0.157904, 9.957584) + XL data for lsm6dsv16x@6b 708354166672ns (0.258389, -0.177044, 9.900164) + XL data for lsm6dsv16x@6b 708387500005ns (0.019139, 0.277529, 9.426449) + XL data for lsm6dsv16x@6b 708420833338ns (-0.052634, -0.244034, 9.866669) + XL data for lsm6dsv16x@6b 708454166671ns (0.263174, -0.172259, 9.861884) + XL data for lsm6dsv16x@6b 708487500004ns (0.277529, -0.129194, 9.890594) + XL data for lsm6dsv16x@6b 708520833337ns (0.301454, -0.138764, 9.928874) + XL data for lsm6dsv16x@6b 708554166670ns (0.258389, -0.138764, 9.971939) + GY data for lsm6dsv16x@6b 708320833339ns (0.000304, 0.000609, 0.004269) + GY data for lsm6dsv16x@6b 708354166672ns (0.001524, -0.003049, 0.004269) + GY data for lsm6dsv16x@6b 708387500005ns (-0.015554, -0.025314, 0.004879) + GY data for lsm6dsv16x@6b 708420833338ns (0.006404, 0.006099, 0.011894) + GY data for lsm6dsv16x@6b 708454166671ns (-0.004879, 0.007014, -0.001829) + GY data for lsm6dsv16x@6b 708487500004ns (0.014944, -0.023789, 0.003354) + GY data for lsm6dsv16x@6b 708520833337ns (0.008539, -0.017689, 0.006099) + GY data for lsm6dsv16x@6b 708554166670ns (0.005489, -0.004574, 0.005184) + TP data for lsm6dsv16x@6b 708354166672ns 24.339843 °C + TP data for lsm6dsv16x@6b 708420833338ns 24.375000 °C + TP data for lsm6dsv16x@6b 708487500004ns 24.421875 °C + TP data for lsm6dsv16x@6b 708554166670ns 24.398437 °C + XL data for lsm6dsv16x@6b 708587500003ns (0.272744, -0.172259, 9.861884) + XL data for lsm6dsv16x@6b 708620833336ns (0.344519, -0.267959, 10.038929) + XL data for lsm6dsv16x@6b 708654166669ns (0.339734, -0.081344, 9.967154) + XL data for lsm6dsv16x@6b 708687500002ns (0.263174, -0.124409, 9.981509) + XL data for lsm6dsv16x@6b 708720833335ns (0.296669, -0.181829, 9.948014) + XL data for lsm6dsv16x@6b 708754166668ns (0.272744, -0.114839, 9.948014) + XL data for lsm6dsv16x@6b 708787500001ns (0.296669, -0.153119, 9.995864) + XL data for lsm6dsv16x@6b 708820833334ns (0.200969, -0.248819, 9.756614) + GY data for lsm6dsv16x@6b 708587500003ns (0.004879, -0.007624, 0.005489) + GY data for lsm6dsv16x@6b 708620833336ns (-0.006709, -0.001219, 0.012504) + GY data for lsm6dsv16x@6b 708654166669ns (-0.001524, -0.004269, 0.006404) + GY data for lsm6dsv16x@6b 708687500002ns (0.000304, -0.005184, 0.007319) + GY data for lsm6dsv16x@6b 708720833335ns (0.001829, 0.000609, 0.003354) + GY data for lsm6dsv16x@6b 708754166668ns (0.005489, -0.001524, 0.004574) + GY data for lsm6dsv16x@6b 708787500001ns (0.052459, -0.010979, 0.041174) + GY data for lsm6dsv16x@6b 708820833334ns (-0.021044, -0.008234, 0.089059) + TP data for lsm6dsv16x@6b 708620833336ns 24.414062 °C + TP data for lsm6dsv16x@6b 708687500002ns 24.382812 °C + TP data for lsm6dsv16x@6b 708754166668ns 24.429687 °C + TP data for lsm6dsv16x@6b 708820833334ns 24.421875 °C + XL data for lsm6dsv16x@6b 708854166667ns (0.373229, 0.325379, 9.928874) + XL data for lsm6dsv16x@6b 708887500000ns (0.086129, 0.119624, 10.986359) + GY data for lsm6dsv16x@6b 708854166667ns (0.015249, 0.003049, 0.039954) + GY data for lsm6dsv16x@6b 708887500000ns (0.025924, 0.071674, -0.101869) + TP data for lsm6dsv16x@6b 708887500000ns 24.457031 °C + +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_fifo/boards/nucleo_f401re.conf b/samples/sensor/stream_fifo/boards/nucleo_f401re.conf new file mode 100644 index 000000000000000..877b30fd2d651d6 --- /dev/null +++ b/samples/sensor/stream_fifo/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_fifo/boards/nucleo_f401re.overlay b/samples/sensor/stream_fifo/boards/nucleo_f401re.overlay new file mode 100644 index 000000000000000..a428b585ed569a8 --- /dev/null +++ b/samples/sensor/stream_fifo/boards/nucleo_f401re.overlay @@ -0,0 +1,38 @@ +/* + * 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 = ; + gyro-odr = ; + gyro-range = ; + fifo-watermark = <64>; + accel-fifo-batch-rate = ; + gyro-fifo-batch-rate = ; + temp-fifo-batch-rate = ; + int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */ + drdy-pin = <2>; + drdy-pulsed; + }; +}; diff --git a/samples/sensor/stream_fifo/boards/nucleo_h503rb.conf b/samples/sensor/stream_fifo/boards/nucleo_h503rb.conf new file mode 100644 index 000000000000000..877b30fd2d651d6 --- /dev/null +++ b/samples/sensor/stream_fifo/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_fifo/boards/nucleo_h503rb.overlay b/samples/sensor/stream_fifo/boards/nucleo_h503rb.overlay new file mode 100644 index 000000000000000..a428b585ed569a8 --- /dev/null +++ b/samples/sensor/stream_fifo/boards/nucleo_h503rb.overlay @@ -0,0 +1,38 @@ +/* + * 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 = ; + gyro-odr = ; + gyro-range = ; + fifo-watermark = <64>; + accel-fifo-batch-rate = ; + gyro-fifo-batch-rate = ; + temp-fifo-batch-rate = ; + int2-gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>; /* D4 (PB5) */ + drdy-pin = <2>; + drdy-pulsed; + }; +}; diff --git a/samples/sensor/stream_fifo/prj.conf b/samples/sensor/stream_fifo/prj.conf new file mode 100644 index 000000000000000..b638fffcb383425 --- /dev/null +++ b/samples/sensor/stream_fifo/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_fifo/sample.yaml b/samples/sensor/stream_fifo/sample.yaml new file mode 100644 index 000000000000000..26eb835c7fce3a9 --- /dev/null +++ b/samples/sensor/stream_fifo/sample.yaml @@ -0,0 +1,7 @@ +sample: + name: Stream FIFO sample +tests: + sample.sensor.stream_fifo: + harness: console + tags: sensors + filter: dt_alias_exists("stream0") diff --git a/samples/sensor/stream_fifo/src/main.c b/samples/sensor/stream_fifo/src/main.c new file mode 100644 index 000000000000000..dbe5c662e4c721a --- /dev/null +++ b/samples/sensor/stream_fifo/src/main.c @@ -0,0 +1,215 @@ +/* + * 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_FIFO_FULL, SENSOR_STREAM_DATA_NOP }, \ + { SENSOR_TRIG_FIFO_WATERMARK, 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 *)); + +static int print_accels_stream(const struct device *dev, struct rtio_iodev *iodev) +{ + int rc = 0; + uint8_t accel_buf[128] = { 0 }; + struct sensor_three_axis_data *accel_data = (struct sensor_three_axis_data *)accel_buf; + uint8_t gyro_buf[128] = { 0 }; + struct sensor_three_axis_data *gyro_data = (struct sensor_three_axis_data *)gyro_buf; + uint8_t temp_buf[64] = { 0 }; + struct sensor_q31_data *temp_data = (struct sensor_q31_data *)temp_buf; + const struct sensor_decoder_api *decoder; + struct rtio_cqe *cqe; + uint8_t *buf; + uint32_t buf_len; + struct rtio_sqe *handles[NUM_SENSORS]; + + /* 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 when data comes from a FIFO */ + uint32_t accel_fit = 0, gyro_fit = 0; + uint32_t temp_fit = 0; + + + /* Number of sensor data frames */ + uint16_t xl_count, gy_count, tp_count, frame_count; + + rc = decoder->get_frame_count(buf, + (struct sensor_chan_spec) { SENSOR_CHAN_ACCEL_XYZ, 0 }, &xl_count); + rc += decoder->get_frame_count(buf, + (struct sensor_chan_spec) { SENSOR_CHAN_GYRO_XYZ, 0 }, &gy_count); + rc += decoder->get_frame_count(buf, + (struct sensor_chan_spec) { SENSOR_CHAN_DIE_TEMP, 0 }, &tp_count); + + if (rc != 0) { + printk("sensor_get_frame failed %d\n", rc); + return rc; + } + + frame_count = xl_count + gy_count + tp_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); + } + + /* Decode all available sensor FIFO frames */ + printk("FIFO count - %d\n", frame_count); + + int i = 0; + + while (i < frame_count) { + int8_t c = 0; + + /* decode and print Accelerometer FIFO frames */ + c = decoder->decode(buf, + (struct sensor_chan_spec) { SENSOR_CHAN_ACCEL_XYZ, 0 }, + &accel_fit, 8, accel_data); + + for (int k = 0; k < c; k++) { + printk("XL data for %s %lluns (%" PRIq(6) ", %" PRIq(6) + ", %" PRIq(6) ")\n", dev->name, + PRIsensor_three_axis_data_arg(*accel_data, k)); + } + i += c; + + /* decode and print Gyroscope FIFO frames */ + c = decoder->decode(buf, + (struct sensor_chan_spec) { SENSOR_CHAN_GYRO_XYZ, 0 }, + &gyro_fit, 8, gyro_data); + + for (int k = 0; k < c; k++) { + printk("GY data for %s %lluns (%" PRIq(6) ", %" PRIq(6) + ", %" PRIq(6) ")\n", dev->name, + PRIsensor_three_axis_data_arg(*gyro_data, k)); + } + i += c; + + /* decode and print Temperature FIFO frames */ + c = decoder->decode(buf, + (struct sensor_chan_spec) { SENSOR_CHAN_DIE_TEMP, 0 }, + &temp_fit, 4, temp_data); + + for (int k = 0; k < c; k++) { + printk("TP data for %s %lluns %s%d.%d °C\n", dev->name, + PRIsensor_q31_data_arg(*temp_data, k)); + } + i += c; + + } + + 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); + } + + ret = sensor_attr_get(dev, SENSOR_CHAN_GYRO_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr); + + /* Check if gyro is off */ + if (ret != 0 || (odr.val1 == 0 && odr.val2 == 0)) { + printk("%s WRN : gyroscope 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; +}