diff options
| -rw-r--r-- | docs/library/zephyr.zsensor.rst | 113 | ||||
| -rw-r--r-- | docs/zephyr/quickref.rst | 37 | ||||
| -rw-r--r-- | ports/zephyr/README.md | 1 | ||||
| -rw-r--r-- | ports/zephyr/modzsensor.c | 88 |
4 files changed, 235 insertions, 4 deletions
diff --git a/docs/library/zephyr.zsensor.rst b/docs/library/zephyr.zsensor.rst index 4eadc926d..2a666bb82 100644 --- a/docs/library/zephyr.zsensor.rst +++ b/docs/library/zephyr.zsensor.rst @@ -20,7 +20,8 @@ See Zephyr documentation for sensor usage here: `Sensors Sensors are defined in the Zephyr devicetree for each board. The quantities that a given sensor can measure are called a sensor channels. Sensors can have multiple channels to represent different axes of one property or different properties a sensor can measure. See `Channels`_ below for defined sensor -channels. +channels. Each channel may have multiple attributes that can be changed and/or queried. +See `Channel Attributes`_ below for defined sensor channel attributes. Constructor ~~~~~~~~~~~ @@ -59,6 +60,36 @@ Methods Returns only the integer value of the measurement sample. (Ex. value of ``(1, 500000)`` returns as ``1``) +.. method:: Sensor.attr_set(sensor_channel, channel_attribute, val1, [val2]) + + Set the given channel's attribute to the given value. + ``val1`` may be a float, in which case ``val2`` is not given, or + ``val1`` can be used for the value's + integer part and ``val2`` for the value's fractional part in millionths. + + Returns ``None`` if successful, or raises ``OSError``. + +.. method:: Sensor.attr_get_float(sensor_channel, channel_attribute) + + Returns the value of the sensor channel's attribute as a float. + + Many sensors do not support this or any other of the ``attr_get`` methods. + +.. method:: Sensor.attr_get_micros(sensor_channel, channel_attribute) + + Returns the value of the sensor channel's attribute in millionths. + (Ex. value of ``(1, 500000)`` returns as ``1500000``) + +.. method:: Sensor.attr_get_millis(sensor_channel, channel_attribute) + + Returns the value of the sensor channel's attribute in thousandths. + (Ex. value of ``(1, 500000)`` returns as ``1500``) + +.. method:: Sensor.attr_get_int(sensor_channel, channel_attribute) + + Returns only the integer value of the channel's attribute. + (Ex. value of ``(1, 500000)`` returns as ``1``) + Channels ~~~~~~~~ @@ -74,6 +105,11 @@ Channels Acceleration on the Z axis, in m/s^2. +.. data:: ACCEL_XYZ + + Pseudo-channel representing all three accelerometer axes. + Used for :meth:`Sensor.attr_set` and the ``Sensor.attr_get_xxx()`` methods. + .. data:: GYRO_X Angular velocity around the X axis, in radians/s. @@ -86,6 +122,11 @@ Channels Angular velocity around the Z axis, in radians/s. +.. data:: GYRO_XYZ + + Pseudo-channel representing all three gyroscope axes. + Used for :meth:`Sensor.attr_set` and the ``Sensor.attr_get_xxx()`` methods. + .. data:: MAGN_X Magnetic field on the X axis, in Gauss. @@ -121,3 +162,73 @@ Channels .. data:: ALTITUDE Altitude, in meters. + +Channel Attributes +~~~~~~~~~~~~~~~~~~~ + +.. data:: ATTR_SAMPLING_FREQUENCY + + Sensor sampling frequency, i.e. how many times a second the sensor takes a measurement. + +.. data:: ATTR_LOWER_THRESH + + Lower threshold for trigger. + +.. data:: ATTR_UPPER_THRESH + + Upper threshold for trigger. + +.. data:: ATTR_SLOPE_TH + + Threshold for any-motion (slope) trigger. + +.. data:: ATTR_SLOPE_DUR + + Duration for which the slope values needs to be outside the threshold for the trigger to fire. + +.. data:: ATTR_HYSTERESIS + +.. data:: ATTR_OVERSAMPLING + + Oversampling factor. + +.. data:: ATTR_FULL_SCALE + + Sensor range, in SI units. + +.. data:: ATTR_OFFSET + + The sensor value returned will be altered by the amount indicated by offset: final_value = sensor_value + offset. + +.. data:: 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. + +.. data:: ATTR_CONFIGURATION + + Configure the operating modes of a sensor. + +.. data:: ATTR_CALIBRATION + + Set a calibration value needed by a sensor. + +.. data:: ATTR_FEATURE_MASK + + Enable/disable sensor features. + +.. data:: ATTR_ALERT + + Alert threshold or alert enable/disable. + +.. data:: 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. + +.. data:: ATTR_BATCH_DURATION + + Hardware batch duration in ticks. + +.. data:: ATTR_GAIN + +.. data:: ATTR_RESOLUTION diff --git a/docs/zephyr/quickref.rst b/docs/zephyr/quickref.rst index 64054bf99..6025092a0 100644 --- a/docs/zephyr/quickref.rst +++ b/docs/zephyr/quickref.rst @@ -99,10 +99,10 @@ Hardware SPI is accessed via the :ref:`machine.SPI <machine.SPI>` class:: from machine import SPI - spi = SPI("spi0") # construct a spi bus with default configuration + spi = SPI("spi0") # construct a SPI bus with default configuration spi.init(baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB) # set configuration - # equivalently, construct spi bus and set configuration at the same time + # equivalently, construct the SPI bus and set configuration at the same time spi = SPI("spi0", baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB) print(spi) # print device name and bus configuration @@ -166,7 +166,7 @@ Use the :ref:`zephyr.FlashArea <zephyr.FlashArea>` class to support filesystem:: f.write('Hello world') # write to the file print(open('/flash/hello.txt').read()) # print contents of the file -The FlashAreas' IDs that are available are listed in the FlashArea module, as ID_*. +The ``FlashAreas``' IDs that are available are listed in the FlashArea module, as ``ID_*``. Sensor ------ @@ -185,3 +185,34 @@ Use the :ref:`zsensor.Sensor <zsensor.Sensor>` class to access sensor data:: accel.get_millis(zsensor.ACCEL_Y) # print measurement value for accelerometer Y-axis sensor channel in millionths accel.get_micro(zsensor.ACCEL_Z) # print measurement value for accelerometer Z-axis sensor channel in thousandths accel.get_int(zsensor.ACCEL_X) # print measurement integer value only for accelerometer X-axis sensor channel + +The channel IDs that are used as arguments to the :meth:`zsensor.Sensor.get_int`, +:meth:`zsensor.Sensor.get_float()`, :meth:`zsensor.Sensor.get_millis()`, and +:meth:`zsensor.Sensor.get_micros()` methods are constants in the :mod:`zsensor` module. + +You can use the :meth:`zsensor.Sensor.attr_set` method to set sensor attributes +like full-scale range and update rate:: + + # Example for XIAO BLE NRF52840 SENSE + from zsensor import * + accel = Sensor('lsm6ds3tr_c') # name from Devicetree + # Set full-scale to 2g (19.613300 m/sec^2) + # units are micro-m/s^2 (given as a float) + accel.attr_set(ACCEL_XYZ, ATTR_FULL_SCALE, 19.613300) + # Set sampling frequency to 104 Hz (as a pair of integers) + accel.attr_set(ACCEL_XYZ, ATTR_SAMPLING_FREQUENCY, 104, 0) + accel.measure() + accel.get_float(ACCEL_X) # -0.508 (m/s^2) + accel.get_float(ACCEL_Y) # -3.62 (m/s^2) + accel.get_float(ACCEL_Z) # 9.504889 (m/s^2) + +There are also the :meth:`zsensor.Sensor.attr_get_float`, :meth:`zsensor.Sensor.attr_get_int`, +:meth:`zsensor.Sensor.attr_get_millis`, and :meth:`zsensor.Sensor.attr_get_micros` methods, +but many sensors do not support these:: + + full_scale = accel.attr_get_float(ATTR_FULL_SCALE) + +The attribute IDs that are used as arguments to the :meth:`zsensor.Sensor.attr_set`, +:meth:`zsensor.Sensor.attr_get_float`, :meth:`zsensor.Sensor.attr_get_int`, +:meth:`zsensor.Sensor.attr_get_millis`, and :meth:`zsensor.Sensor.attr_get_micros` +methods are constants in the :mod:`zsensor` module named ``ATTR_*``. diff --git a/ports/zephyr/README.md b/ports/zephyr/README.md index 0f6b16d39..480ff5705 100644 --- a/ports/zephyr/README.md +++ b/ports/zephyr/README.md @@ -22,6 +22,7 @@ Features supported at this time: * `machine.PWM` class for PWM control. * `machine.ADC` class for ADC control. * `socket` module for networking (IPv4/IPv6). +* `zsensor` module for reading sensors. * "Frozen modules" support to allow to bundle Python modules together with firmware. Including complete applications, including with run-on-boot capability. diff --git a/ports/zephyr/modzsensor.c b/ports/zephyr/modzsensor.c index 51b7b2dbf..c3a8b6d55 100644 --- a/ports/zephyr/modzsensor.c +++ b/ports/zephyr/modzsensor.c @@ -93,12 +93,77 @@ static mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) { } MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int); +static void sensor_attr_get_internal(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in, struct sensor_value *res) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in); + + int st = sensor_attr_get(self->dev, mp_obj_get_int(channel_in), mp_obj_get_int(attr_in), res); + if (st != 0) { + mp_raise_OSError(-st); + } +} + +static mp_obj_t sensor_attr_get_float(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) { + struct sensor_value val; + sensor_attr_get_internal(self_in, channel_in, attr_in, &val); + return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000); +} +MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_float_obj, sensor_attr_get_float); + +static mp_obj_t sensor_attr_get_micros(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) { + struct sensor_value val; + sensor_attr_get_internal(self_in, channel_in, attr_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2); +} +MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_micros_obj, sensor_attr_get_micros); + +static mp_obj_t sensor_attr_get_millis(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) { + struct sensor_value val; + sensor_attr_get_internal(self_in, channel_in, attr_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000); +} +MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_millis_obj, sensor_attr_get_millis); + +static mp_obj_t sensor_attr_get_int(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) { + struct sensor_value val; + sensor_attr_get_internal(self_in, channel_in, attr_in, &val); + return MP_OBJ_NEW_SMALL_INT(val.val1); +} +MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_int_obj, sensor_attr_get_int); + +static mp_obj_t mp_sensor_attr_set(size_t n_args, const mp_obj_t *args) { + mp_obj_sensor_t *self = MP_OBJ_TO_PTR(args[0]); + mp_obj_t channel_in = args[1]; + mp_obj_t attr_in = args[2]; + struct sensor_value val; + if (n_args == 4) { + // One float argument + float v = mp_obj_get_float(args[3]); + val.val1 = (int32_t)v; + val.val2 = (int32_t)((v - val.val1) * 1000000); + } else { + // Two integer arguments + val.val1 = mp_obj_get_int(args[3]); + val.val2 = mp_obj_get_int(args[4]); + } + int st = sensor_attr_set(self->dev, mp_obj_get_int(channel_in), mp_obj_get_int(attr_in), &val); + if (st != 0) { + mp_raise_OSError(-st); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sensor_attr_set_obj, 4, 5, mp_sensor_attr_set); + static const mp_rom_map_elem_t sensor_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) }, { MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) }, { MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) }, { MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) }, { MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) }, + { MP_ROM_QSTR(MP_QSTR_attr_get_float), MP_ROM_PTR(&sensor_attr_get_float_obj) }, + { MP_ROM_QSTR(MP_QSTR_attr_get_micros), MP_ROM_PTR(&sensor_attr_get_micros_obj) }, + { MP_ROM_QSTR(MP_QSTR_attr_get_millis), MP_ROM_PTR(&sensor_attr_get_millis_obj) }, + { MP_ROM_QSTR(MP_QSTR_attr_get_int), MP_ROM_PTR(&sensor_attr_get_int_obj) }, + { MP_ROM_QSTR(MP_QSTR_attr_set), MP_ROM_PTR(&sensor_attr_set_obj) }, }; static MP_DEFINE_CONST_DICT(sensor_locals_dict, sensor_locals_dict_table); @@ -119,12 +184,15 @@ static const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { C(ACCEL_X), C(ACCEL_Y), C(ACCEL_Z), + C(ACCEL_XYZ), C(GYRO_X), C(GYRO_Y), C(GYRO_Z), + C(GYRO_XYZ), C(MAGN_X), C(MAGN_Y), C(MAGN_Z), + C(MAGN_XYZ), C(DIE_TEMP), C(AMBIENT_TEMP), C(PRESS), @@ -145,6 +213,26 @@ static const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = { C(GAS_RES), C(VOLTAGE), #undef C +#define C(name) { MP_ROM_QSTR(MP_QSTR_ATTR_##name), MP_ROM_INT(SENSOR_ATTR_##name) } + C(SAMPLING_FREQUENCY), + C(LOWER_THRESH), + C(UPPER_THRESH), + C(SLOPE_TH), + C(SLOPE_DUR), + C(HYSTERESIS), + C(OVERSAMPLING), + C(FULL_SCALE), + C(OFFSET), + C(CALIB_TARGET), + C(CONFIGURATION), + C(CALIBRATION), + C(FEATURE_MASK), + C(ALERT), + C(FF_DUR), + C(BATCH_DURATION), + C(GAIN), + C(RESOLUTION), +#undef C }; static MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table); |
