Sensors

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. Consult the API Reference for all supported channels, along with their description and units of measurement:

Values

Sensor stable APIs return results as sensor_value. This representation avoids use of floating point values as they may not be supported on certain setups.

A newer experimental (may change) API that can interpret raw sensor data is available in parallel. This new API exposes raw encoded sensor data to the application and provides a separate decoder to convert the data to a Q31 format which is compatible with the Zephyr Digital Signal Processing (DSP). The values represented are in the range of (-1.0, 1.0) and require a shift operation in order to scale them to their SI unit values. See Async Read for more information.

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, they can be read in a single operation by supplying the corresponding _XYZ channel type and a buffer of 3 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 sensor_sample_fetch() is only called once, as it reads and compensates data for both channels.

 1
 2/*
 3 * Get a device structure from a devicetree node with compatible
 4 * "bosch,bme280". (If there are multiple, just pick one.)
 5 */
 6static const struct device *get_bme280_device(void)
 7{
 8	const struct device *const dev = DEVICE_DT_GET_ANY(bosch_bme280);
 9
10	if (dev == NULL) {
11		/* No such node, or the node does not have status "okay". */
12		printk("\nError: no device found.\n");
13		return NULL;
14	}
15
16	if (!device_is_ready(dev)) {
17		printk("\nError: Device \"%s\" is not ready; "
18		       "check the driver initialization logs for errors.\n",
19		       dev->name);
20		return NULL;
21	}
22
23	printk("Found device \"%s\", getting sensor data\n", dev->name);
24	return dev;
25}
26
27int main(void)
28{
29	const struct device *dev = get_bme280_device();
30
31	if (dev == NULL) {
32		return 0;
33	}
34
35	while (1) {
36		struct sensor_value temp, press, humidity;
37
38		sensor_sample_fetch(dev);
39		sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
40		sensor_channel_get(dev, SENSOR_CHAN_PRESS, &press);
41		sensor_channel_get(dev, SENSOR_CHAN_HUMIDITY, &humidity);
42
43		printk("temp: %d.%06d; press: %d.%06d; humidity: %d.%06d\n",
44		      temp.val1, temp.val2, press.val1, press.val2,
45		      humidity.val1, humidity.val2);
46
47		k_sleep(K_MSEC(1000));
48	}
49	return 0;
50}

Async Read

To enable the async APIs, use CONFIG_SENSOR_ASYNC_API.

Reading the sensors leverages the Real Time I/O (RTIO) subsystem. Applications gain control of the data processing thread and even memory management. In order to get started with reading the sensors, an IODev must be created via the SENSOR_DT_READ_IODEV. Next, an RTIO context must be created. It is strongly suggested that this context is created with a memory pool via RTIO_DEFINE_WITH_MEMPOOL.

#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/rtio/rtio.h>

static const struct device *lid_accel = DEVICE_DT_GET(DT_ALIAS(lid_accel));
SENSOR_DT_READ_IODEV(lid_accel_iodev, DT_ALIAS(lid_accel), SENSOR_CHAN_ACCEL_XYZ);

RTIO_DEFINE_WITH_MEMPOOL(sensors_rtio,
                         4,  /* submission queue size */
                         4,  /* completion queue size */
                         16, /* number of memory blocks */
                         32, /* size of each memory block */
                         4   /* memory alignment */
                         );

To trigger a read, the application simply needs to call sensor_read() and pass the relevant IODev and RTIO context. Getting the result is done like any other RTIO operation, by waiting on a completion queue event (CQE). In order to help reduce some boilerplate code, the helper function sensor_processing_with_callback() is provided. When called, the function will block until a CQE becomes available from the provided RTIO context. The appropriate buffers are extracted and the callback is called. Once the callback is done, the memory is reclaimed by the memorypool. This looks like:

static void sensor_processing_callback(int result, uint8_t *buf,
                                       uint32_t buf_len, void *userdata) {
  // Process the data...
}

static void sensor_processing_thread(void *, void *, void *) {
  while (true) {
    sensor_processing_with_callback(&sensors_rtio, sensor_processing_callback);
  }
}
K_THREAD_DEFINE(sensor_processing_tid, 1024, sensor_processing_thread,
                NULL, NULL, NULL, 0, 0, 0);

Note

Helper functions to create custom length IODev nodes and ones that don’t have static bindings will be added soon.

Processing the Data

Once data collection completes and the processing callback was called, processing the data is done via the sensor_decoder_api. The API provides a means for applications to control when to process the data and how many resources to dedicate to the processing. The API is entirely self contained and requires no system calls (even when CONFIG_USERSPACE is enabled).

static struct sensor_decoder_api *lid_accel_decoder = SENSOR_DECODER_DT_GET(DT_ALIAS(lid_accel));

static void sensor_processing_callback(int result, uint8_t *buf,
                                       uint32_t buf_len, void *userdata) {
  uint64_t timestamp;
  sensor_frame_iterator_t fit = {0};
  sensor_channel_iterator_t cit = {0};
  enum sensor_channel channels[3];
  q31_t values[3];
  int8_t shift[3];

  lid_accel_decoder->get_timestamp(buf, &timestamp);
  lid_accel_decoder->decode(buf, &fit, &cit, channels, values, 3);

  /* Values are now in q31_t format, we're going to convert them to micro-units */

  /* First, we need to know by how much to shift the values */
  lid_accel_decoder->get_shift(buf, channels[0], &shift[0]);
  lid_accel_decoder->get_shift(buf, channels[1], &shift[1]);
  lid_accel_decoder->get_shift(buf, channels[2], &shift[2]);

  /* Shift the values to get the SI units */
  int64_t scaled_values[] = {
    (int64_t)values[0] << shift[0],
    (int64_t)values[1] << shift[1],
    (int64_t)values[2] << shift[2],
  };

  /*
   * FIELD_GET(GENMASK64(63, 31), scaled_values[]) - will give the integer value
   * FIELD_GET(GENMASK64(30, 0), scaled_values[]) / INT32_MAX - is the decimal value
   */
}

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

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 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 buses, it is not possible to communicate with them from the interrupt execution context. The execution of the trigger handler is deferred to a thread, so that data fetching operations are possible. A driver can spawn its own thread to fetch data, thus ensuring minimum latency. Alternatively, multiple sensor drivers can share a system-wide thread. The shared thread 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.

  1
  2#define UCEL_PER_CEL 1000000
  3#define UCEL_PER_MCEL 1000
  4#define TEMP_INITIAL_CEL 25
  5#define TEMP_WINDOW_HALF_UCEL 500000
  6
  7static const char *now_str(void)
  8{
  9	static char buf[16]; /* ...HH:MM:SS.MMM */
 10	uint32_t now = k_uptime_get_32();
 11	unsigned int ms = now % MSEC_PER_SEC;
 12	unsigned int s;
 13	unsigned int min;
 14	unsigned int h;
 15
 16	now /= MSEC_PER_SEC;
 17	s = now % 60U;
 18	now /= 60U;
 19	min = now % 60U;
 20	now /= 60U;
 21	h = now;
 22
 23	snprintf(buf, sizeof(buf), "%u:%02u:%02u.%03u",
 24		 h, min, s, ms);
 25	return buf;
 26}
 27
 28#ifdef CONFIG_MCP9808_TRIGGER
 29
 30static struct sensor_trigger sensor_trig;
 31
 32static int set_window(const struct device *dev,
 33		      const struct sensor_value *temp)
 34{
 35	const int temp_ucel = temp->val1 * UCEL_PER_CEL + temp->val2;
 36	const int low_ucel = temp_ucel - TEMP_WINDOW_HALF_UCEL;
 37	const int high_ucel = temp_ucel + TEMP_WINDOW_HALF_UCEL;
 38	struct sensor_value val = {
 39		.val1 = low_ucel / UCEL_PER_CEL,
 40		.val2 = low_ucel % UCEL_PER_CEL,
 41	};
 42	int rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
 43				 SENSOR_ATTR_LOWER_THRESH, &val);
 44	if (rc == 0) {
 45		val.val1 = high_ucel / UCEL_PER_CEL,
 46		val.val2 = high_ucel % UCEL_PER_CEL,
 47		rc = sensor_attr_set(dev, SENSOR_CHAN_AMBIENT_TEMP,
 48				     SENSOR_ATTR_UPPER_THRESH, &val);
 49	}
 50
 51	if (rc == 0) {
 52		printf("Alert on temp outside [%d, %d] milli-Celsius\n",
 53		       low_ucel / UCEL_PER_MCEL,
 54		       high_ucel / UCEL_PER_MCEL);
 55	}
 56
 57	return rc;
 58}
 59
 60static inline int set_window_ucel(const struct device *dev,
 61				  int temp_ucel)
 62{
 63	struct sensor_value val = {
 64		.val1 = temp_ucel / UCEL_PER_CEL,
 65		.val2 = temp_ucel % UCEL_PER_CEL,
 66	};
 67
 68	return set_window(dev, &val);
 69}
 70
 71static void trigger_handler(const struct device *dev,
 72			    const struct sensor_trigger *trig)
 73{
 74	struct sensor_value temp;
 75	static size_t cnt;
 76	int rc;
 77
 78	++cnt;
 79	rc = sensor_sample_fetch(dev);
 80	if (rc != 0) {
 81		printf("sensor_sample_fetch error: %d\n", rc);
 82		return;
 83	}
 84	rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
 85	if (rc != 0) {
 86		printf("sensor_channel_get error: %d\n", rc);
 87		return;
 88	}
 89
 90	printf("trigger fired %u, temp %g deg C\n", cnt,
 91	       sensor_value_to_double(&temp));
 92	set_window(dev, &temp);
 93}
 94#endif
 95
 96int main(void)
 97{
 98	const struct device *const dev = DEVICE_DT_GET_ANY(microchip_mcp9808);
 99	int rc;
100
101	if (dev == NULL) {
102		printf("Device not found.\n");
103		return 0;
104	}
105	if (!device_is_ready(dev)) {
106		printf("Device %s is not ready.\n", dev->name);
107		return 0;
108	}
109
110#ifdef CONFIG_MCP9808_TRIGGER
111	rc = set_window_ucel(dev, TEMP_INITIAL_CEL * UCEL_PER_CEL);
112	if (rc == 0) {
113		sensor_trig.type = SENSOR_TRIG_THRESHOLD;
114		sensor_trig.chan = SENSOR_CHAN_AMBIENT_TEMP;
115		rc = sensor_trigger_set(dev, &sensor_trig, trigger_handler);
116	}
117
118	if (rc != 0) {
119		printf("Trigger set failed: %d\n", rc);
120		return 0;
121	}
122	printk("Trigger set got %d\n", rc);
123#endif
124
125	while (1) {
126		struct sensor_value temp;
127
128		rc = sensor_sample_fetch(dev);
129		if (rc != 0) {
130			printf("sensor_sample_fetch error: %d\n", rc);
131			break;
132		}
133
134		rc = sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
135		if (rc != 0) {
136			printf("sensor_channel_get error: %d\n", rc);
137			break;
138		}
139
140		printf("%s: %g C\n", now_str(),
141		       sensor_value_to_double(&temp));
142
143		k_sleep(K_SECONDS(2));
144	}
145	return 0;
146}

API Reference

group sensor_interface

Sensor Interface.

Since

1.2

Version

1.0.0

Defines

SENSOR_DECODE_CONTEXT_INIT(decoder_, buffer_, channel_type_, channel_index_)

Initialize a sensor_decode_context.

SENSOR_STREAM_TRIGGER_PREP(_trigger, _opt)
SENSOR_DT_READ_IODEV(name, dt_node, ...)

Define a reading instance of a sensor.

Use this macro to generate a rtio_iodev for reading specific channels. Example:

 (.c)
SENSOR_DT_READ_IODEV(icm42688_accelgyro, DT_NODELABEL(icm42688),
    { SENSOR_CHAN_ACCEL_XYZ, 0 },
    { SENSOR_CHAN_GYRO_XYZ, 0 });

int main(void) {
  sensor_read(&icm42688_accelgyro, &rtio);
}
SENSOR_DT_STREAM_IODEV(name, dt_node, ...)

Define a stream instance of a sensor.

Use this macro to generate a rtio_iodev for starting a stream that’s triggered by specific interrupts. Example:

 (.c)
SENSOR_DT_STREAM_IODEV(imu_stream, DT_ALIAS(imu),
    {SENSOR_TRIG_FIFO_WATERMARK, SENSOR_STREAM_DATA_INCLUDE},
    {SENSOR_TRIG_FIFO_FULL, SENSOR_STREAM_DATA_NOP});

int main(void) {
  struct rtio_sqe *handle;
  sensor_stream(&imu_stream, &rtio, NULL, &handle);
  k_msleep(1000);
  rtio_sqe_cancel(handle);
}
SENSOR_CHANNEL_3_AXIS(chan)

checks if a given channel is a 3-axis channel

Parameters:
  • chan[in] The channel to check

Return values:
SENSOR_G

The value of gravitational constant in micro m/s^2.

SENSOR_PI

The value of constant PI in micros.

SENSOR_INFO_DEFINE(name, ...)
SENSOR_INFO_DT_DEFINE(node_id)
SENSOR_DEVICE_DT_DEFINE(node_id, init_fn, pm_device, data_ptr, cfg_ptr, level, prio, api_ptr, ...)

Like DEVICE_DT_DEFINE() with sensor specifics.

Defines a device which implements the sensor API. May define an element in the sensor info iterable section used to enumerate all sensor devices.

Parameters:
  • node_id – The devicetree node identifier.

  • init_fn – Name of the init function of the driver.

  • pm_device – PM device resources reference (NULL if device does not use PM).

  • data_ptr – Pointer to the device’s private data.

  • cfg_ptr – The address to the structure containing the configuration information for this instance of the driver.

  • level – The initialization level. See SYS_INIT() for details.

  • prio – Priority within the selected initialization level. See SYS_INIT() for details.

  • api_ptr – Provides an initial pointer to the API function struct used by the driver. Can be NULL.

SENSOR_DEVICE_DT_INST_DEFINE(inst, ...)

Like SENSOR_DEVICE_DT_DEFINE() for an instance of a DT_DRV_COMPAT compatible.

Parameters:

Typedefs

typedef void (*sensor_trigger_handler_t)(const struct device *dev, const struct sensor_trigger *trigger)

Callback API upon firing of a trigger.

Param dev:

Pointer to the sensor device

Param trigger:

The trigger

typedef int (*sensor_attr_set_t)(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val)

Callback API upon setting a sensor’s attributes.

See sensor_attr_set() for argument description

typedef int (*sensor_attr_get_t)(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, struct sensor_value *val)

Callback API upon getting a sensor’s attributes.

See sensor_attr_get() for argument description

typedef int (*sensor_trigger_set_t)(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler)

Callback API for setting a sensor’s trigger and handler.

See sensor_trigger_set() for argument description

typedef int (*sensor_sample_fetch_t)(const struct device *dev, enum sensor_channel chan)

Callback API for fetching data from a sensor.

See sensor_sample_fetch() for argument description

typedef int (*sensor_channel_get_t)(const struct device *dev, enum sensor_channel chan, struct sensor_value *val)

Callback API for getting a reading from a sensor.

See sensor_channel_get() for argument description

typedef int (*sensor_get_decoder_t)(const struct device *dev, const struct sensor_decoder_api **api)

Get the decoder associate with the given device.

See also

sensor_get_decoder for more details

typedef int (*sensor_submit_t)(const struct device *sensor, struct rtio_iodev_sqe *sqe)
typedef void (*sensor_processing_callback_t)(int result, uint8_t *buf, uint32_t buf_len, void *userdata)

Callback function used with the helper processing function.

Param result:

[in] The result code of the read (0 being success)

Param buf:

[in] The data buffer holding the sensor data

Param buf_len:

[in] The length (in bytes) of the buf

Param userdata:

[in] The optional userdata passed to sensor_read()

Enums

enum sensor_channel

Sensor channels.

Values:

enumerator SENSOR_CHAN_ACCEL_X

Acceleration on the X axis, in m/s^2.

enumerator SENSOR_CHAN_ACCEL_Y

Acceleration on the Y axis, in m/s^2.

enumerator SENSOR_CHAN_ACCEL_Z

Acceleration on the Z axis, in m/s^2.

enumerator SENSOR_CHAN_ACCEL_XYZ

Acceleration on the X, Y and Z axes.

enumerator SENSOR_CHAN_GYRO_X

Angular velocity around the X axis, in radians/s.

enumerator SENSOR_CHAN_GYRO_Y

Angular velocity around the Y axis, in radians/s.

enumerator SENSOR_CHAN_GYRO_Z

Angular velocity around the Z axis, in radians/s.

enumerator SENSOR_CHAN_GYRO_XYZ

Angular velocity around the X, Y and Z axes.

enumerator SENSOR_CHAN_MAGN_X

Magnetic field on the X axis, in Gauss.

enumerator SENSOR_CHAN_MAGN_Y

Magnetic field on the Y axis, in Gauss.

enumerator SENSOR_CHAN_MAGN_Z

Magnetic field on the Z axis, in Gauss.

enumerator SENSOR_CHAN_MAGN_XYZ

Magnetic field on the X, Y and Z axes.

enumerator SENSOR_CHAN_DIE_TEMP

Device die temperature in degrees Celsius.

enumerator SENSOR_CHAN_AMBIENT_TEMP

Ambient temperature in degrees Celsius.

enumerator SENSOR_CHAN_PRESS

Pressure in kilopascal.

enumerator SENSOR_CHAN_PROX

Proximity.

Adimensional. A value of 1 indicates that an object is close.

enumerator SENSOR_CHAN_HUMIDITY

Humidity, in percent.

enumerator SENSOR_CHAN_LIGHT

Illuminance in visible spectrum, in lux.

enumerator SENSOR_CHAN_IR

Illuminance in infra-red spectrum, in lux.

enumerator SENSOR_CHAN_RED

Illuminance in red spectrum, in lux.

enumerator SENSOR_CHAN_GREEN

Illuminance in green spectrum, in lux.

enumerator SENSOR_CHAN_BLUE

Illuminance in blue spectrum, in lux.

enumerator SENSOR_CHAN_ALTITUDE

Altitude, in meters.

enumerator SENSOR_CHAN_PM_1_0

1.0 micro-meters Particulate Matter, in ug/m^3

enumerator SENSOR_CHAN_PM_2_5

2.5 micro-meters Particulate Matter, in ug/m^3

enumerator SENSOR_CHAN_PM_10

10 micro-meters Particulate Matter, in ug/m^3

enumerator SENSOR_CHAN_DISTANCE

Distance.

From sensor to target, in meters

enumerator SENSOR_CHAN_CO2

CO2 level, in parts per million (ppm)

enumerator SENSOR_CHAN_O2

O2 level, in parts per million (ppm)

enumerator SENSOR_CHAN_VOC

VOC level, in parts per billion (ppb)

enumerator SENSOR_CHAN_GAS_RES

Gas sensor resistance in ohms.

enumerator SENSOR_CHAN_VOLTAGE

Voltage, in volts.

enumerator SENSOR_CHAN_VSHUNT

Current Shunt Voltage in milli-volts.

enumerator SENSOR_CHAN_CURRENT

Current, in amps.

enumerator SENSOR_CHAN_POWER

Power in watts.

enumerator SENSOR_CHAN_RESISTANCE

Resistance , in Ohm.

enumerator SENSOR_CHAN_ROTATION

Angular rotation, in degrees.

enumerator SENSOR_CHAN_POS_DX

Position change on the X axis, in points.

enumerator SENSOR_CHAN_POS_DY

Position change on the Y axis, in points.

enumerator SENSOR_CHAN_POS_DZ

Position change on the Z axis, in points.

enumerator SENSOR_CHAN_RPM

Revolutions per minute, in RPM.

enumerator SENSOR_CHAN_GAUGE_VOLTAGE

Voltage, in volts.

enumerator SENSOR_CHAN_GAUGE_AVG_CURRENT

Average current, in amps.

enumerator SENSOR_CHAN_GAUGE_STDBY_CURRENT

Standby current, in amps.

enumerator SENSOR_CHAN_GAUGE_MAX_LOAD_CURRENT

Max load current, in amps.

enumerator SENSOR_CHAN_GAUGE_TEMP

Gauge temperature

enumerator SENSOR_CHAN_GAUGE_STATE_OF_CHARGE

State of charge measurement in %.

enumerator SENSOR_CHAN_GAUGE_FULL_CHARGE_CAPACITY

Full Charge Capacity in mAh.

enumerator SENSOR_CHAN_GAUGE_REMAINING_CHARGE_CAPACITY

Remaining Charge Capacity in mAh.

enumerator SENSOR_CHAN_GAUGE_NOM_AVAIL_CAPACITY

Nominal Available Capacity in mAh.

enumerator SENSOR_CHAN_GAUGE_FULL_AVAIL_CAPACITY

Full Available Capacity in mAh.

enumerator SENSOR_CHAN_GAUGE_AVG_POWER

Average power in mW.

enumerator SENSOR_CHAN_GAUGE_STATE_OF_HEALTH

State of health measurement in %.

enumerator SENSOR_CHAN_GAUGE_TIME_TO_EMPTY

Time to empty in minutes.

enumerator SENSOR_CHAN_GAUGE_TIME_TO_FULL

Time to full in minutes.

enumerator SENSOR_CHAN_GAUGE_CYCLE_COUNT

Cycle count (total number of charge/discharge cycles)

enumerator SENSOR_CHAN_GAUGE_DESIGN_VOLTAGE

Design voltage of cell in V (max voltage)

enumerator SENSOR_CHAN_GAUGE_DESIRED_VOLTAGE

Desired voltage of cell in V (nominal voltage)

enumerator SENSOR_CHAN_GAUGE_DESIRED_CHARGING_CURRENT

Desired charging current in mA.

enumerator SENSOR_CHAN_ALL

All channels.

enumerator SENSOR_CHAN_COMMON_COUNT

Number of all common sensor channels.

enumerator SENSOR_CHAN_PRIV_START = SENSOR_CHAN_COMMON_COUNT

This and higher values are sensor specific.

Refer to the sensor header file.

enumerator SENSOR_CHAN_MAX = INT16_MAX

Maximum value describing a sensor channel type.

enum sensor_trigger_type

Sensor trigger types.

Values:

enumerator SENSOR_TRIG_TIMER

Timer-based trigger, useful when the sensor does not have an interrupt line.

enumerator SENSOR_TRIG_DATA_READY

Trigger fires whenever new data is ready.

enumerator SENSOR_TRIG_DELTA

Trigger fires when the selected channel varies significantly.

This includes any-motion detection when the channel is acceleration or gyro. If detection is based on slope between successive channel readings, the slope threshold is configured via the SENSOR_ATTR_SLOPE_TH and SENSOR_ATTR_SLOPE_DUR attributes.

enumerator SENSOR_TRIG_NEAR_FAR

Trigger fires when a near/far event is detected.

enumerator SENSOR_TRIG_THRESHOLD

Trigger fires when channel reading transitions configured thresholds.

The thresholds are configured via the SENSOR_ATTR_LOWER_THRESH, SENSOR_ATTR_UPPER_THRESH, and SENSOR_ATTR_HYSTERESIS attributes.

enumerator SENSOR_TRIG_TAP

Trigger fires when a single tap is detected.

enumerator SENSOR_TRIG_DOUBLE_TAP

Trigger fires when a double tap is detected.

enumerator SENSOR_TRIG_FREEFALL

Trigger fires when a free fall is detected.

enumerator SENSOR_TRIG_MOTION

Trigger fires when motion is detected.

enumerator SENSOR_TRIG_STATIONARY

Trigger fires when no motion has been detected for a while.

enumerator SENSOR_TRIG_FIFO_WATERMARK

Trigger fires when the FIFO watermark has been reached.

enumerator SENSOR_TRIG_FIFO_FULL

Trigger fires when the FIFO becomes full.

enumerator SENSOR_TRIG_COMMON_COUNT

Number of all common sensor triggers.

enumerator SENSOR_TRIG_PRIV_START = SENSOR_TRIG_COMMON_COUNT

This and higher values are sensor specific.

Refer to the sensor header file.

enumerator SENSOR_TRIG_MAX = INT16_MAX

Maximum value describing a sensor trigger type.

enum sensor_attribute

Sensor attribute types.

Values:

enumerator SENSOR_ATTR_SAMPLING_FREQUENCY

Sensor sampling frequency, i.e.

how many times a second the sensor takes a measurement.

enumerator SENSOR_ATTR_LOWER_THRESH

Lower threshold for trigger.

enumerator SENSOR_ATTR_UPPER_THRESH

Upper threshold for trigger.

enumerator SENSOR_ATTR_SLOPE_TH

Threshold for any-motion (slope) trigger.

enumerator SENSOR_ATTR_SLOPE_DUR

Duration for which the slope values needs to be outside the threshold for the trigger to fire.

enumerator SENSOR_ATTR_HYSTERESIS
enumerator SENSOR_ATTR_OVERSAMPLING

Oversampling factor.

enumerator SENSOR_ATTR_FULL_SCALE

Sensor range, in SI units.

enumerator SENSOR_ATTR_OFFSET

The sensor value returned will be altered by the amount indicated by offset: final_value = sensor_value + offset.

enumerator SENSOR_ATTR_CALIB_TARGET

Calibration target.

This will be used by the internal chip’s algorithms to calibrate itself on a certain axis, or all of them.

enumerator SENSOR_ATTR_CONFIGURATION

Configure the operating modes of a sensor.

enumerator SENSOR_ATTR_CALIBRATION

Set a calibration value needed by a sensor.

enumerator SENSOR_ATTR_FEATURE_MASK

Enable/disable sensor features.

enumerator SENSOR_ATTR_ALERT

Alert threshold or alert enable/disable.

enumerator SENSOR_ATTR_FF_DUR

Free-fall duration represented in milliseconds.

If the sampling frequency is changed during runtime, this attribute should be set to adjust freefall duration to the new sampling frequency.

enumerator SENSOR_ATTR_BATCH_DURATION

Hardware batch duration in ticks.

enumerator SENSOR_ATTR_COMMON_COUNT

Number of all common sensor attributes.

enumerator SENSOR_ATTR_PRIV_START = SENSOR_ATTR_COMMON_COUNT

This and higher values are sensor specific.

Refer to the sensor header file.

enumerator SENSOR_ATTR_MAX = INT16_MAX

Maximum value describing a sensor attribute type.

enum sensor_stream_data_opt

Options for what to do with the associated data when a trigger is consumed.

Values:

enumerator SENSOR_STREAM_DATA_INCLUDE = 0

Include whatever data is associated with the trigger.

enumerator SENSOR_STREAM_DATA_NOP = 1

Do nothing with the associated trigger data, it may be consumed later.

enumerator SENSOR_STREAM_DATA_DROP = 2

Flush/clear whatever data is associated with the trigger.

Functions

static inline bool sensor_chan_spec_eq(struct sensor_chan_spec chan_spec0, struct sensor_chan_spec chan_spec1)

Check if channel specs are equivalent.

Parameters:
  • chan_spec0 – First chan spec

  • chan_spec1 – Second chan spec

Return values:
  • true – If equivalent

  • false – If not equivalent

static inline int sensor_decode(struct sensor_decode_context *ctx, void *out, uint16_t max_count)

Decode N frames using a sensor_decode_context.

Parameters:
  • ctx[inout] The context to use for decoding

  • out[out] The output buffer

  • max_count[in] Maximum number of frames to decode

Returns:

The decode result from sensor_decoder_api’s decode function

int sensor_natively_supported_channel_size_info(struct sensor_chan_spec channel, size_t *base_size, size_t *frame_size)
int sensor_attr_set(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, const struct sensor_value *val)

Set an attribute for a sensor.

Parameters:
  • dev – Pointer to the sensor device

  • chan – The channel the attribute belongs to, if any. Some attributes may only be set for all channels of a device, depending on device capabilities.

  • attr – The attribute to set

  • val – The value to set the attribute to

Returns:

0 if successful, negative errno code if failure.

int sensor_attr_get(const struct device *dev, enum sensor_channel chan, enum sensor_attribute attr, struct sensor_value *val)

Get an attribute for a sensor.

Parameters:
  • dev – Pointer to the sensor device

  • chan – The channel the attribute belongs to, if any. Some attributes may only be set for all channels of a device, depending on device capabilities.

  • attr – The attribute to get

  • val – Pointer to where to store the attribute

Returns:

0 if successful, negative errno code if failure.

static inline int sensor_trigger_set(const struct device *dev, const struct sensor_trigger *trig, sensor_trigger_handler_t handler)

Activate a sensor’s trigger and set the trigger handler.

The handler will be called from a thread, so I2C or SPI operations are safe. However, the thread’s stack is limited and defined by the driver. It is currently up to the caller to ensure that the handler does not overflow the stack.

The user-allocated trigger will be stored by the driver as a pointer, rather than a copy, and passed back to the handler. This enables the handler to use CONTAINER_OF to retrieve a context pointer when the trigger is embedded in a larger struct and requires that the trigger is not allocated on the stack.

Function properties (list may not be complete)

supervisor

Parameters:
  • dev – Pointer to the sensor device

  • trig – The trigger to activate

  • handler – The function that should be called when the trigger fires

Returns:

0 if successful, negative errno code if failure.

int sensor_sample_fetch(const struct device *dev)

Fetch a sample from the sensor and store it in an internal driver buffer.

Read all of a sensor’s active channels and, if necessary, perform any additional operations necessary to make the values useful. The user may then get individual channel values by calling sensor_channel_get.

The function blocks until the fetch operation is complete.

Since the function communicates with the sensor device, it is unsafe to call it in an ISR if the device is connected via I2C or SPI.

Parameters:
  • dev – Pointer to the sensor device

Returns:

0 if successful, negative errno code if failure.

int sensor_sample_fetch_chan(const struct device *dev, enum sensor_channel type)

Fetch a sample from the sensor and store it in an internal driver buffer.

Read and compute compensation for one type of sensor data (magnetometer, accelerometer, etc). The user may then get individual channel values by calling sensor_channel_get.

This is mostly implemented by multi function devices enabling reading at different sampling rates.

The function blocks until the fetch operation is complete.

Since the function communicates with the sensor device, it is unsafe to call it in an ISR if the device is connected via I2C or SPI.

Parameters:
  • dev – Pointer to the sensor device

  • type – The channel that needs updated

Returns:

0 if successful, negative errno code if failure.

int sensor_channel_get(const struct device *dev, enum sensor_channel chan, struct sensor_value *val)

Get a reading from a sensor device.

Return a useful value for a particular channel, from the driver’s internal data. Before calling this function, a sample must be obtained by calling sensor_sample_fetch or sensor_sample_fetch_chan. It is guaranteed that two subsequent calls of this function for the same channels will yield the same value, if sensor_sample_fetch or sensor_sample_fetch_chan has not been called in the meantime.

For vectorial data samples you can request all axes in just one call by passing the specific channel with _XYZ suffix. The sample will be returned at val[0], val[1] and val[2] (X, Y and Z in that order).

Parameters:
  • dev – Pointer to the sensor device

  • chan – The channel to read

  • val – Where to store the value

Returns:

0 if successful, negative errno code if failure.

int sensor_get_decoder(const struct device *dev, const struct sensor_decoder_api **decoder)

Get the sensor’s decoder API.

Parameters:
  • dev[in] The sensor device

  • decoder[in] Pointer to the decoder which will be set upon success

Returns:

0 on success

Returns:

< 0 on error

int sensor_reconfigure_read_iodev(struct rtio_iodev *iodev, const struct device *sensor, const struct sensor_chan_spec *channels, size_t num_channels)

Reconfigure a reading iodev.

Allows a reconfiguration of the iodev associated with reading a sample from a sensor.

Important: If the iodev is currently servicing a read operation, the data will likely be invalid. Please be sure the flush or wait for all pending operations to complete before using the data after a configuration change.

It is also important that the data field of the iodev is a sensor_read_config.

Parameters:
  • iodev[in] The iodev to reconfigure

  • sensor[in] The sensor to read from

  • channels[in] One or more channels to read

  • num_channels[in] The number of channels in channels

Returns:

0 on success

Returns:

< 0 on error

static inline int sensor_stream(struct rtio_iodev *iodev, struct rtio *ctx, void *userdata, struct rtio_sqe **handle)
static inline int sensor_read(struct rtio_iodev *iodev, struct rtio *ctx, void *userdata)

Read data from a sensor.

Using cfg, read one snapshot of data from the device by using the provided RTIO context ctx. This call will generate a rtio_sqe that will leverage the RTIO’s internal mempool when the time comes to service the read.

Parameters:
  • iodev[in] The iodev created by SENSOR_DT_READ_IODEV

  • ctx[in] The RTIO context to service the read

  • userdata[in] Optional userdata that will be available when the read is complete

Returns:

0 on success

Returns:

< 0 on error

void sensor_processing_with_callback(struct rtio *ctx, sensor_processing_callback_t cb)

Helper function for common processing of sensor data.

This function can be called in a blocking manner after sensor_read() or in a standalone thread dedicated to processing. It will wait for a cqe from the RTIO context, once received, it will decode the userdata and call the cb. Once the cb returns, the buffer will be released back into ctx's mempool if available.

Parameters:
  • ctx[in] The RTIO context to wait on

  • cb[in] Callback to call when data is ready for processing

static inline int32_t sensor_ms2_to_g(const struct sensor_value *ms2)

Helper function to convert acceleration from m/s^2 to Gs.

Parameters:
  • ms2 – A pointer to a sensor_value struct holding the acceleration, in m/s^2.

Returns:

The converted value, in Gs.

static inline void sensor_g_to_ms2(int32_t g, struct sensor_value *ms2)

Helper function to convert acceleration from Gs to m/s^2.

Parameters:
  • g – The G value to be converted.

  • ms2 – A pointer to a sensor_value struct, where the result is stored.

static inline int32_t sensor_ms2_to_ug(const struct sensor_value *ms2)

Helper function to convert acceleration from m/s^2 to micro Gs.

Parameters:
  • ms2 – A pointer to a sensor_value struct holding the acceleration, in m/s^2.

Returns:

The converted value, in micro Gs.

static inline void sensor_ug_to_ms2(int32_t ug, struct sensor_value *ms2)

Helper function to convert acceleration from micro Gs to m/s^2.

Parameters:
  • ug – The micro G value to be converted.

  • ms2 – A pointer to a sensor_value struct, where the result is stored.

static inline int32_t sensor_rad_to_degrees(const struct sensor_value *rad)

Helper function for converting radians to degrees.

Parameters:
  • rad – A pointer to a sensor_value struct, holding the value in radians.

Returns:

The converted value, in degrees.

static inline void sensor_degrees_to_rad(int32_t d, struct sensor_value *rad)

Helper function for converting degrees to radians.

Parameters:
  • d – The value (in degrees) to be converted.

  • rad – A pointer to a sensor_value struct, where the result is stored.

static inline int32_t sensor_rad_to_10udegrees(const struct sensor_value *rad)

Helper function for converting radians to 10 micro degrees.

When the unit is 1 micro degree, the range that the int32_t can represent is +/-2147.483 degrees. In order to increase this range, here we use 10 micro degrees as the unit.

Parameters:
  • rad – A pointer to a sensor_value struct, holding the value in radians.

Returns:

The converted value, in 10 micro degrees.

static inline void sensor_10udegrees_to_rad(int32_t d, struct sensor_value *rad)

Helper function for converting 10 micro degrees to radians.

Parameters:
  • d – The value (in 10 micro degrees) to be converted.

  • rad – A pointer to a sensor_value struct, where the result is stored.

static inline double sensor_value_to_double(const struct sensor_value *val)

Helper function for converting struct sensor_value to double.

Parameters:
Returns:

The converted value.

static inline float sensor_value_to_float(const struct sensor_value *val)

Helper function for converting struct sensor_value to float.

Parameters:
Returns:

The converted value.

static inline int sensor_value_from_double(struct sensor_value *val, double inp)

Helper function for converting double to struct sensor_value.

Parameters:
  • val – A pointer to a sensor_value struct.

  • inp – The converted value.

Returns:

0 if successful, negative errno code if failure.

static inline int sensor_value_from_float(struct sensor_value *val, float inp)

Helper function for converting float to struct sensor_value.

Parameters:
  • val – A pointer to a sensor_value struct.

  • inp – The converted value.

Returns:

0 if successful, negative errno code if failure.

static inline int64_t sensor_value_to_milli(const struct sensor_value *val)

Helper function for converting struct sensor_value to integer milli units.

Parameters:
Returns:

The converted value.

static inline int64_t sensor_value_to_micro(const struct sensor_value *val)

Helper function for converting struct sensor_value to integer micro units.

Parameters:
Returns:

The converted value.

static inline int sensor_value_from_milli(struct sensor_value *val, int64_t milli)

Helper function for converting integer milli units to struct sensor_value.

Parameters:
  • val – A pointer to a sensor_value struct.

  • milli – The converted value.

Returns:

0 if successful, negative errno code if failure.

static inline int sensor_value_from_micro(struct sensor_value *val, int64_t micro)

Helper function for converting integer micro units to struct sensor_value.

Parameters:
  • val – A pointer to a sensor_value struct.

  • micro – The converted value.

Returns:

0 if successful, negative errno code if failure.

struct sensor_value
#include <sensor.h>

Representation of a sensor readout value.

The value is represented as having an integer and a fractional part, and can be obtained using the formula val1 + val2 * 10^(-6). Negative values also adhere to the above formula, but may need special attention. Here are some examples of the value representation:

 0.5: val1 =  0, val2 =  500000
-0.5: val1 =  0, val2 = -500000
-1.0: val1 = -1, val2 =  0
-1.5: val1 = -1, val2 = -500000

Public Members

int32_t val1

Integer part of the value.

int32_t val2

Fractional part of the value (in one-millionth parts).

struct sensor_trigger
#include <sensor.h>

Sensor trigger spec.

Public Members

enum sensor_trigger_type type

Trigger type.

enum sensor_channel chan

Channel the trigger is set on.

struct sensor_chan_spec
#include <sensor.h>

Sensor Channel Specification.

A sensor channel specification is a unique identifier per sensor device describing a measurement channel.

Note

Typically passed by value as the size of a sensor_chan_spec is a single word.

Public Members

uint16_t chan_type

A sensor channel type.

uint16_t chan_idx

A sensor channel index.

struct sensor_decoder_api
#include <sensor.h>

Decodes a single raw data buffer.

Data buffers are provided on the RTIO context that’s supplied to sensor_read.

Public Members

int (*get_frame_count)(const uint8_t *buffer, struct sensor_chan_spec channel, uint16_t *frame_count)

Get the number of frames in the current buffer.

Param buffer:

[in] The buffer provided on the RTIO context.

Param channel:

[in] The channel to get the count for

Param frame_count:

[out] The number of frames on the buffer (at least 1)

Return:

0 on success

Return:

-ENOTSUP if the channel/channel_idx aren’t found

int (*get_size_info)(struct sensor_chan_spec channel, size_t *base_size, size_t *frame_size)

Get the size required to decode a given channel.

When decoding a single frame, use base_size. For every additional frame, add another frame_size. As an example, to decode 3 frames use: ‘base_size + 2 * frame_size’.

Param channel:

[in] The channel to query

Param base_size:

[out] The size of decoding the first frame

Param frame_size:

[out] The additional size of every additional frame

Return:

0 on success

Return:

-ENOTSUP if the channel is not supported

int (*decode)(const uint8_t *buffer, struct sensor_chan_spec channel, uint32_t *fit, uint16_t max_count, void *data_out)

Decode up to max_count samples from the buffer.

Decode samples of channel sensor_channel across multiple frames. If there exist multiple instances of the same channel, channel_index is used to differentiate them. As an example, assume a sensor provides 2 distance measurements:

// Decode the first channel instance of 'distance'
decoder->decode(buffer, SENSOR_CHAN_DISTANCE, 0, &fit, 5, out);
...

// Decode the second channel instance of 'distance'
decoder->decode(buffer, SENSOR_CHAN_DISTANCE, 1, &fit, 5, out);
Param buffer:

[in] The buffer provided on the RTIO context

Param channel:

[in] The channel to decode

Param fit:

[inout] The current frame iterator

Param max_count:

[in] The maximum number of channels to decode.

Param data_out:

[out] The decoded data

Return:

0 no more samples to decode

Return:

>0 the number of decoded frames

Return:

<0 on error

bool (*has_trigger)(const uint8_t *buffer, enum sensor_trigger_type trigger)

Check if the given trigger type is present.

Param buffer:

[in] The buffer provided on the RTIO context

Param trigger:

[in] The trigger type in question

Return:

Whether the trigger is present in the buffer

struct sensor_decode_context
#include <sensor.h>

Used for iterating over the data frames via the sensor_decoder_api.

Example usage:

(.c)
   struct sensor_decode_context ctx = SENSOR_DECODE_CONTEXT_INIT(
       decoder, buffer, SENSOR_CHAN_ACCEL_XYZ, 0);

   while (true) {
     struct sensor_three_axis_data accel_out_data;

     num_decoded_channels = sensor_decode(ctx, &accel_out_data, 1);

     if (num_decoded_channels <= 0) {
       printk("Done decoding buffer\n");
       break;
     }

     printk("Decoded (%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", accel_out_data.readings[0].x,
         accel_out_data.readings[0].y, accel_out_data.readings[0].z);
   }
struct sensor_stream_trigger
#include <sensor.h>
struct sensor_read_config
#include <sensor.h>
struct sensor_driver_api
#include <sensor.h>
struct sensor_data_generic_header
#include <sensor.h>
group sensor_emulator_backend

Sensor emulator backend API.

Functions

static inline bool emul_sensor_backend_is_supported(const struct emul *target)

Check if a given sensor emulator supports the backend API.

Parameters:
  • target – Pointer to emulator instance to query

Returns:

True if supported, false if unsupported or if target is NULL.

static inline int emul_sensor_backend_set_channel(const struct emul *target, struct sensor_chan_spec ch, const q31_t *value, int8_t shift)

Set an expected value for a given channel on a given sensor emulator.

Parameters:
  • target – Pointer to emulator instance to operate on

  • ch – Sensor channel to set expected value for

  • value – Expected value in fixed-point format using standard SI unit for sensor type

  • shift – Shift value (scaling factor) applied to value

Returns:

0 if successful

Returns:

-ENOTSUP if no backend API or if channel not supported by emul

Returns:

-ERANGE if provided value is not in the sensor’s supported range

static inline int emul_sensor_backend_get_sample_range(const struct emul *target, struct sensor_chan_spec ch, q31_t *lower, q31_t *upper, q31_t *epsilon, int8_t *shift)

Query an emulator for a channel’s supported sample value range and tolerance.

Parameters:
  • target – Pointer to emulator instance to operate on

  • ch – The channel to request info for. If ch is unsupported, return -ENOTSUP

  • lower[out] Minimum supported sample value in SI units, fixed-point format

  • upper[out] Maximum supported sample value in SI units, fixed-point format

  • epsilon[out] Tolerance to use comparing expected and actual values to account for rounding and sensor precision issues. This can usually be set to the minimum sample value step size. Uses SI units and fixed-point format.

  • shift[out] The shift value (scaling factor) associated with lower, upper, and epsilon.

Returns:

0 if successful

Returns:

-ENOTSUP if no backend API or if channel not supported by emul

static inline int emul_sensor_backend_set_attribute(const struct emul *target, struct sensor_chan_spec ch, enum sensor_attribute attribute, const void *value)

Set the emulator’s attribute values.

Parameters:
  • target[in] Pointer to emulator instance to operate on

  • ch[in] The channel to request info for. If ch is unsupported, return -ENOTSUP

  • attribute[in] The attribute to set

  • value[in] the value to use (cast according to the channel/attribute pair)

Returns:

0 is successful

Returns:

< 0 on error

static inline int emul_sensor_backend_get_attribute_metadata(const struct emul *target, struct sensor_chan_spec ch, enum sensor_attribute attribute, q31_t *min, q31_t *max, q31_t *increment, int8_t *shift)

Get metadata about an attribute.

Information provided by this function includes the minimum/maximum values of the attribute as well as the increment (value per LSB) which can be used as an epsilon when comparing results.

Parameters:
  • target[in] Pointer to emulator instance to operate on

  • ch[in] The channel to request info for. If ch is unsupported, return ‘-ENOTSUP’

  • attribute[in] The attribute to request info for. If attribute is unsupported, return ‘-ENOTSUP’

  • min[out] The minimum value the attribute can be set to

  • max[out] The maximum value the attribute can be set to

  • increment[out] The value that the attribute increses by for every LSB

  • shift[out] The shift for min, max, and increment

Returns:

0 on SUCCESS

Returns:

< 0 on error