125 lines
5.1 KiB
ReStructuredText
125 lines
5.1 KiB
ReStructuredText
.. _sensor:
|
|
|
|
Sensor Drivers
|
|
##############
|
|
|
|
The sensor subsystem exposes an API to uniformly access sensor devices.
|
|
Common operations are: reading data and executing code when specific
|
|
conditions are met.
|
|
|
|
Basic Operation
|
|
***************
|
|
|
|
Channels
|
|
========
|
|
|
|
Fundamentally, a channel is a quantity that a sensor device can measure.
|
|
|
|
Sensors can have multiple channels, either to represent different axes of
|
|
the same physical property (e.g. acceleration); or because they can measure
|
|
different properties altogether (ambient temperature, pressure and
|
|
humidity). Complex sensors cover both cases, so a single device can expose
|
|
three acceleration channels and a temperature one.
|
|
|
|
It is imperative that all sensors that support a given channel express
|
|
results in the same unit of measurement. The following is a list of all
|
|
supported channels, along with their description and units of measurement:
|
|
|
|
.. doxygenenum:: sensor_channel
|
|
|
|
Values
|
|
======
|
|
|
|
Sensor devices return results as :c:type:`struct sensor_value`. This
|
|
representation avoids use of floating point operations on setups where they
|
|
are not supported or desired.
|
|
|
|
Most sensor values have a type of :c:macro:`SENSOR_TYPE_INT_PLUS_MICRO`.
|
|
Other possible representations are listed below. Applications are
|
|
responsible for correctly interpreting the :c:data:`type` field of a
|
|
returned value.
|
|
|
|
.. doxygenenum:: sensor_value_type
|
|
|
|
Fetching Values
|
|
===============
|
|
|
|
Getting a reading from a sensor requires two operations. First, an
|
|
application instructs the driver to fetch a sample of all its channels.
|
|
Then, individual channels may be read. In the case of channels with
|
|
multiple axes, all the axes can be read in a single operation by supplying
|
|
the corresponding :literal:`_ANY` channel type and a buffer of 3
|
|
:c:type:`struct sensor_value` objects. This approach ensures consistency
|
|
of channels between reads and efficiency of communication by issuing a
|
|
single transaction on the underlying bus.
|
|
|
|
Below is an example illustrating the usage of the BME280 sensor, which
|
|
measures ambient temperature and atmospheric pressure. Note that
|
|
:c:func:`sensor_sample_fetch` is only called once, as it reads and
|
|
compensates data for both channels.
|
|
|
|
.. literalinclude:: ../../samples/sensor/bme280/src/main.c
|
|
:language: c
|
|
:lines: 31-
|
|
:linenos:
|
|
|
|
The example assumes that the returned values have type :c:type:`struct
|
|
sensor_value`, which is the case for BME280. A real application
|
|
supporting multiple sensors should inspect the :c:data:`type` field of
|
|
the :c:data:`temp` and :c:data:`press` values and use the other fields
|
|
of the structure accordingly.
|
|
|
|
Configuration and Attributes
|
|
****************************
|
|
|
|
Setting the communication bus and address is considered the most basic
|
|
configuration for sensor devices. This setting is done at compile time, via
|
|
the configuration menu. If the sensor supports interrupts, the interrupt
|
|
lines and triggering parameters described below are also configured at
|
|
compile time.
|
|
|
|
Alongside these communication parameters, sensor chips typically expose
|
|
multiple parameters that control the accuracy and frequency of measurement.
|
|
In compliance with Zephyr's design goals, most of these values are
|
|
statically configured at compile time.
|
|
|
|
However, certain parameters could require runtime configuration, for
|
|
example, threshold values for interrupts. These values are configured via
|
|
attributes. The example in the following section showcases a sensor with an
|
|
interrupt line that is triggered when the temperature crosses a threshold.
|
|
The threshold is configured at runtime using an attribute.
|
|
|
|
Triggers
|
|
********
|
|
|
|
:dfn:`Triggers` in Zephyr refer to the interrupt lines of the sensor chips.
|
|
Many sensor chips support one or more triggers. Some examples of triggers
|
|
include: new data is ready for reading, a channel value has crossed a
|
|
threshold, or the device has sensed motion.
|
|
|
|
To configure a trigger, an application needs to supply a :c:type:`struct
|
|
sensor_trigger` and a handler function. The structure contains the trigger
|
|
type and the channel on which the trigger must be configured.
|
|
|
|
Because most sensors are connected via SPI or I2C busses, it is not possible
|
|
to communicate with them from the interrupt execution context. The
|
|
execution of the trigger handler is deferred to a fiber, so that data
|
|
fetching operations are possible. A driver can spawn its own fiber to fetch
|
|
data, thus ensuring minimum latency. Alternatively, multiple sensor drivers
|
|
can share a system-wide fiber. The shared fiber approach increases the
|
|
latency of handling interrupts but uses less memory. You can configure which
|
|
approach to follow for each driver. Most drivers can entirely disable
|
|
triggers resulting in a smaller footprint.
|
|
|
|
The following example contains a trigger fired whenever temperature crosses
|
|
the 26 degree Celsius threshold. It also samples the temperature every
|
|
second. A real application would ideally disable periodic sampling in the
|
|
interest of saving power. Since the application has direct access to the
|
|
kernel config symbols, no trigger is registered when triggering was disabled
|
|
by the driver's configuration.
|
|
|
|
.. literalinclude:: ../../samples/sensor/mcp9808/src/main.c
|
|
:language: c
|
|
:lines: 31-
|
|
:linenos:
|