1.. _sensor_api:
2
3Sensors
4#######
5
6The sensor subsystem exposes an API to uniformly access sensor devices.
7Common operations are: reading data and executing code when specific
8conditions are met.
9
10Basic Operation
11***************
12
13Channels
14========
15
16Fundamentally, a channel is a quantity that a sensor device can measure.
17
18Sensors can have multiple channels, either to represent different axes of
19the same physical property (e.g. acceleration); or because they can measure
20different properties altogether (ambient temperature, pressure and
21humidity).  Complex sensors cover both cases, so a single device can expose
22three acceleration channels and a temperature one.
23
24It is imperative that all sensors that support a given channel express
25results in the same unit of measurement. Consult the
26:ref:`sensor_api_reference` for all supported channels, along with their
27description and units of measurement:
28
29Values
30======
31
32Sensor stable APIs return results as :c:struct:`sensor_value`.  This
33representation avoids use of floating point values as they may not be
34supported on certain setups.
35
36A newer experimental (may change) API that can interpret raw sensor data is
37available in parallel. This new API exposes raw encoded sensor data to the
38application and provides a separate decoder to convert the data to a Q31 format
39which is compatible with the Zephyr :ref:`zdsp_api`. The values represented are
40in the range of (-1.0, 1.0) and require a shift operation in order to scale
41them to their SI unit values. See :ref:`Async Read` for more information.
42
43Fetching Values
44===============
45
46Getting a reading from a sensor requires two operations.  First, an
47application instructs the driver to fetch a sample of all its channels.
48Then, individual channels may be read.  In the case of channels with
49multiple axes, they can be read in a single operation by supplying
50the corresponding :literal:`_XYZ` channel type and a buffer of 3
51:c:struct:`sensor_value` objects.  This approach ensures consistency
52of channels between reads and efficiency of communication by issuing a
53single transaction on the underlying bus.
54
55Below is an example illustrating the usage of the BME280 sensor, which
56measures ambient temperature and atmospheric pressure.  Note that
57:c:func:`sensor_sample_fetch` is only called once, as it reads and
58compensates data for both channels.
59
60.. literalinclude:: ../../../samples/sensor/bme280/src/main.c
61   :language: c
62   :lines: 12-
63   :linenos:
64
65.. _Async Read:
66
67Async Read
68==========
69
70To enable the async APIs, use :kconfig:option:`CONFIG_SENSOR_ASYNC_API`.
71
72Reading the sensors leverages the :ref:`rtio_api` subsystem. Applications
73gain control of the data processing thread and even memory management. In order
74to get started with reading the sensors, an IODev must be created via the
75:c:macro:`SENSOR_DT_READ_IODEV`. Next, an RTIO context must be created. It is
76strongly suggested that this context is created with a memory pool via
77:c:macro:`RTIO_DEFINE_WITH_MEMPOOL`.
78
79.. code-block:: C
80
81   #include <zephyr/device.h>
82   #include <zephyr/drivers/sensor.h>
83   #include <zephyr/rtio/rtio.h>
84
85   static const struct device *lid_accel = DEVICE_DT_GET(DT_ALIAS(lid_accel));
86   SENSOR_DT_READ_IODEV(lid_accel_iodev, DT_ALIAS(lid_accel), SENSOR_CHAN_ACCEL_XYZ);
87
88   RTIO_DEFINE_WITH_MEMPOOL(sensors_rtio,
89                            4,  /* submission queue size */
90                            4,  /* completion queue size */
91                            16, /* number of memory blocks */
92                            32, /* size of each memory block */
93                            4   /* memory alignment */
94                            );
95
96To trigger a read, the application simply needs to call :c:func:`sensor_read`
97and pass the relevant IODev and RTIO context. Getting the result is done like
98any other RTIO operation, by waiting on a completion queue event (CQE). In
99order to help reduce some boilerplate code, the helper function
100:c:func:`sensor_processing_with_callback` is provided. When called, the
101function will block until a CQE becomes available from the provided RTIO
102context. The appropriate buffers are extracted and the callback is called.
103Once the callback is done, the memory is reclaimed by the memorypool. This
104looks like:
105
106.. code-block:: C
107
108   static void sensor_processing_callback(int result, uint8_t *buf,
109                                          uint32_t buf_len, void *userdata) {
110     // Process the data...
111   }
112
113   static void sensor_processing_thread(void *, void *, void *) {
114     while (true) {
115       sensor_processing_with_callback(&sensors_rtio, sensor_processing_callback);
116     }
117   }
118   K_THREAD_DEFINE(sensor_processing_tid, 1024, sensor_processing_thread,
119                   NULL, NULL, NULL, 0, 0, 0);
120
121.. note::
122   Helper functions to create custom length IODev nodes and ones that don't
123   have static bindings will be added soon.
124
125Processing the Data
126===================
127
128Once data collection completes and the processing callback was called,
129processing the data is done via the :c:struct:`sensor_decoder_api`. The API
130provides a means for applications to control *when* to process the data and how
131many resources to dedicate to the processing. The API is entirely self
132contained and requires no system calls (even when
133:kconfig:option:`CONFIG_USERSPACE` is enabled).
134
135.. code-block:: C
136
137   static struct sensor_decoder_api *lid_accel_decoder = SENSOR_DECODER_DT_GET(DT_ALIAS(lid_accel));
138
139   static void sensor_processing_callback(int result, uint8_t *buf,
140                                          uint32_t buf_len, void *userdata) {
141     uint64_t timestamp;
142     sensor_frame_iterator_t fit = {0};
143     sensor_channel_iterator_t cit = {0};
144     enum sensor_channel channels[3];
145     q31_t values[3];
146     int8_t shift[3];
147
148     lid_accel_decoder->get_timestamp(buf, &timestamp);
149     lid_accel_decoder->decode(buf, &fit, &cit, channels, values, 3);
150
151     /* Values are now in q31_t format, we're going to convert them to micro-units */
152
153     /* First, we need to know by how much to shift the values */
154     lid_accel_decoder->get_shift(buf, channels[0], &shift[0]);
155     lid_accel_decoder->get_shift(buf, channels[1], &shift[1]);
156     lid_accel_decoder->get_shift(buf, channels[2], &shift[2]);
157
158     /* Shift the values to get the SI units */
159     int64_t scaled_values[] = {
160       (int64_t)values[0] << shift[0],
161       (int64_t)values[1] << shift[1],
162       (int64_t)values[2] << shift[2],
163     };
164
165     /*
166      * FIELD_GET(GENMASK64(63, 31), scaled_values[]) - will give the integer value
167      * FIELD_GET(GENMASK64(30, 0), scaled_values[]) / INT32_MAX - is the decimal value
168      */
169   }
170
171Configuration and Attributes
172****************************
173
174Setting the communication bus and address is considered the most basic
175configuration for sensor devices.  This setting is done at compile time, via
176the configuration menu.  If the sensor supports interrupts, the interrupt
177lines and triggering parameters described below are also configured at
178compile time.
179
180Alongside these communication parameters, sensor chips typically expose
181multiple parameters that control the accuracy and frequency of measurement.
182In compliance with Zephyr's design goals, most of these values are
183statically configured at compile time.
184
185However, certain parameters could require runtime configuration, for
186example, threshold values for interrupts.  These values are configured via
187attributes.  The example in the following section showcases a sensor with an
188interrupt line that is triggered when the temperature crosses a threshold.
189The threshold is configured at runtime using an attribute.
190
191Triggers
192********
193
194:dfn:`Triggers` in Zephyr refer to the interrupt lines of the sensor chips.
195Many sensor chips support one or more triggers. Some examples of triggers
196include: new data is ready for reading, a channel value has crossed a
197threshold, or the device has sensed motion.
198
199To configure a trigger, an application needs to supply a
200:c:struct:`sensor_trigger` and a handler function.  The structure contains the
201trigger type and the channel on which the trigger must be configured.
202
203Because most sensors are connected via SPI or I2C buses, it is not possible
204to communicate with them from the interrupt execution context.  The
205execution of the trigger handler is deferred to a thread, so that data
206fetching operations are possible.  A driver can spawn its own thread to fetch
207data, thus ensuring minimum latency. Alternatively, multiple sensor drivers
208can share a system-wide thread. The shared thread approach increases the
209latency of handling interrupts but uses less memory. You can configure which
210approach to follow for each driver. Most drivers can entirely disable
211triggers resulting in a smaller footprint.
212
213The following example contains a trigger fired whenever temperature crosses
214the 26 degree Celsius threshold. It also samples the temperature every
215second. A real application would ideally disable periodic sampling in the
216interest of saving power. Since the application has direct access to the
217kernel config symbols, no trigger is registered when triggering was disabled
218by the driver's configuration.
219
220.. literalinclude:: ../../../samples/sensor/mcp9808/src/main.c
221   :language: c
222   :lines: 12-
223   :linenos:
224
225.. _sensor_api_reference:
226
227API Reference
228**************
229
230.. doxygengroup:: sensor_interface
231.. doxygengroup:: sensor_emulator_backend
232