Skip to content

Commit c6a7851

Browse files
bikeNomaddpgeorge
authored andcommitted
zephyr/modzsensor: Add set/get sensor attributes to zsensor.
This commit adds `Sensor.attr_set()` and `Sensor.attr_get_*()` methods that are necessary to set various sensor attributes if they haven't been set statically in the device tree. This is needed, for example, because the LSM6DS3TR-C sensor on the XIAO BLE NRF52840 SENSE board will not work with `zsensor` because it doesn't have any default configuration for sampling frequency. Various `SENSOR_ATTR_*` constants from `zephyr/incude/zephyr/drivers/sensor.h` have been added as `ATTR_*` constants in the `zsensor` module. Signed-off-by: Ned Konz <[email protected]>
1 parent d42a301 commit c6a7851

File tree

4 files changed

+235
-4
lines changed

4 files changed

+235
-4
lines changed

docs/library/zephyr.zsensor.rst

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ See Zephyr documentation for sensor usage here: `Sensors
2020
Sensors are defined in the Zephyr devicetree for each board. The quantities that a given sensor can
2121
measure are called a sensor channels. Sensors can have multiple channels to represent different axes
2222
of one property or different properties a sensor can measure. See `Channels`_ below for defined sensor
23-
channels.
23+
channels. Each channel may have multiple attributes that can be changed and/or queried.
24+
See `Channel Attributes`_ below for defined sensor channel attributes.
2425

2526
Constructor
2627
~~~~~~~~~~~
@@ -59,6 +60,36 @@ Methods
5960
Returns only the integer value of the measurement sample.
6061
(Ex. value of ``(1, 500000)`` returns as ``1``)
6162

63+
.. method:: Sensor.attr_set(sensor_channel, channel_attribute, val1, [val2])
64+
65+
Set the given channel's attribute to the given value.
66+
``val1`` may be a float, in which case ``val2`` is not given, or
67+
``val1`` can be used for the value's
68+
integer part and ``val2`` for the value's fractional part in millionths.
69+
70+
Returns ``None`` if successful, or raises ``OSError``.
71+
72+
.. method:: Sensor.attr_get_float(sensor_channel, channel_attribute)
73+
74+
Returns the value of the sensor channel's attribute as a float.
75+
76+
Many sensors do not support this or any other of the ``attr_get`` methods.
77+
78+
.. method:: Sensor.attr_get_micros(sensor_channel, channel_attribute)
79+
80+
Returns the value of the sensor channel's attribute in millionths.
81+
(Ex. value of ``(1, 500000)`` returns as ``1500000``)
82+
83+
.. method:: Sensor.attr_get_millis(sensor_channel, channel_attribute)
84+
85+
Returns the value of the sensor channel's attribute in thousandths.
86+
(Ex. value of ``(1, 500000)`` returns as ``1500``)
87+
88+
.. method:: Sensor.attr_get_int(sensor_channel, channel_attribute)
89+
90+
Returns only the integer value of the channel's attribute.
91+
(Ex. value of ``(1, 500000)`` returns as ``1``)
92+
6293
Channels
6394
~~~~~~~~
6495

@@ -74,6 +105,11 @@ Channels
74105

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

108+
.. data:: ACCEL_XYZ
109+
110+
Pseudo-channel representing all three accelerometer axes.
111+
Used for :meth:`Sensor.attr_set` and the ``Sensor.attr_get_xxx()`` methods.
112+
77113
.. data:: GYRO_X
78114

79115
Angular velocity around the X axis, in radians/s.
@@ -86,6 +122,11 @@ Channels
86122

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

125+
.. data:: GYRO_XYZ
126+
127+
Pseudo-channel representing all three gyroscope axes.
128+
Used for :meth:`Sensor.attr_set` and the ``Sensor.attr_get_xxx()`` methods.
129+
89130
.. data:: MAGN_X
90131

91132
Magnetic field on the X axis, in Gauss.
@@ -121,3 +162,73 @@ Channels
121162
.. data:: ALTITUDE
122163

123164
Altitude, in meters.
165+
166+
Channel Attributes
167+
~~~~~~~~~~~~~~~~~~~
168+
169+
.. data:: ATTR_SAMPLING_FREQUENCY
170+
171+
Sensor sampling frequency, i.e. how many times a second the sensor takes a measurement.
172+
173+
.. data:: ATTR_LOWER_THRESH
174+
175+
Lower threshold for trigger.
176+
177+
.. data:: ATTR_UPPER_THRESH
178+
179+
Upper threshold for trigger.
180+
181+
.. data:: ATTR_SLOPE_TH
182+
183+
Threshold for any-motion (slope) trigger.
184+
185+
.. data:: ATTR_SLOPE_DUR
186+
187+
Duration for which the slope values needs to be outside the threshold for the trigger to fire.
188+
189+
.. data:: ATTR_HYSTERESIS
190+
191+
.. data:: ATTR_OVERSAMPLING
192+
193+
Oversampling factor.
194+
195+
.. data:: ATTR_FULL_SCALE
196+
197+
Sensor range, in SI units.
198+
199+
.. data:: ATTR_OFFSET
200+
201+
The sensor value returned will be altered by the amount indicated by offset: final_value = sensor_value + offset.
202+
203+
.. data:: ATTR_CALIB_TARGET
204+
205+
Calibration target. This will be used by the internal chip's algorithms to calibrate itself on a certain axis, or all of them.
206+
207+
.. data:: ATTR_CONFIGURATION
208+
209+
Configure the operating modes of a sensor.
210+
211+
.. data:: ATTR_CALIBRATION
212+
213+
Set a calibration value needed by a sensor.
214+
215+
.. data:: ATTR_FEATURE_MASK
216+
217+
Enable/disable sensor features.
218+
219+
.. data:: ATTR_ALERT
220+
221+
Alert threshold or alert enable/disable.
222+
223+
.. data:: ATTR_FF_DUR
224+
225+
Free-fall duration represented in milliseconds.
226+
If the sampling frequency is changed during runtime, this attribute should be set to adjust freefall duration to the new sampling frequency.
227+
228+
.. data:: ATTR_BATCH_DURATION
229+
230+
Hardware batch duration in ticks.
231+
232+
.. data:: ATTR_GAIN
233+
234+
.. data:: ATTR_RESOLUTION

docs/zephyr/quickref.rst

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ Hardware SPI is accessed via the :ref:`machine.SPI <machine.SPI>` class::
9999

100100
from machine import SPI
101101

102-
spi = SPI("spi0") # construct a spi bus with default configuration
102+
spi = SPI("spi0") # construct a SPI bus with default configuration
103103
spi.init(baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB) # set configuration
104104

105-
# equivalently, construct spi bus and set configuration at the same time
105+
# equivalently, construct the SPI bus and set configuration at the same time
106106
spi = SPI("spi0", baudrate=100000, polarity=0, phase=0, bits=8, firstbit=SPI.MSB)
107107
print(spi) # print device name and bus configuration
108108

@@ -166,7 +166,7 @@ Use the :ref:`zephyr.FlashArea <zephyr.FlashArea>` class to support filesystem::
166166
f.write('Hello world') # write to the file
167167
print(open('/flash/hello.txt').read()) # print contents of the file
168168

169-
The FlashAreas' IDs that are available are listed in the FlashArea module, as ID_*.
169+
The ``FlashAreas``' IDs that are available are listed in the FlashArea module, as ``ID_*``.
170170

171171
Sensor
172172
------
@@ -185,3 +185,34 @@ Use the :ref:`zsensor.Sensor <zsensor.Sensor>` class to access sensor data::
185185
accel.get_millis(zsensor.ACCEL_Y) # print measurement value for accelerometer Y-axis sensor channel in millionths
186186
accel.get_micro(zsensor.ACCEL_Z) # print measurement value for accelerometer Z-axis sensor channel in thousandths
187187
accel.get_int(zsensor.ACCEL_X) # print measurement integer value only for accelerometer X-axis sensor channel
188+
189+
The channel IDs that are used as arguments to the :meth:`zsensor.Sensor.get_int`,
190+
:meth:`zsensor.Sensor.get_float()`, :meth:`zsensor.Sensor.get_millis()`, and
191+
:meth:`zsensor.Sensor.get_micros()` methods are constants in the :mod:`zsensor` module.
192+
193+
You can use the :meth:`zsensor.Sensor.attr_set` method to set sensor attributes
194+
like full-scale range and update rate::
195+
196+
# Example for XIAO BLE NRF52840 SENSE
197+
from zsensor import *
198+
accel = Sensor('lsm6ds3tr_c') # name from Devicetree
199+
# Set full-scale to 2g (19.613300 m/sec^2)
200+
# units are micro-m/s^2 (given as a float)
201+
accel.attr_set(ACCEL_XYZ, ATTR_FULL_SCALE, 19.613300)
202+
# Set sampling frequency to 104 Hz (as a pair of integers)
203+
accel.attr_set(ACCEL_XYZ, ATTR_SAMPLING_FREQUENCY, 104, 0)
204+
accel.measure()
205+
accel.get_float(ACCEL_X) # -0.508 (m/s^2)
206+
accel.get_float(ACCEL_Y) # -3.62 (m/s^2)
207+
accel.get_float(ACCEL_Z) # 9.504889 (m/s^2)
208+
209+
There are also the :meth:`zsensor.Sensor.attr_get_float`, :meth:`zsensor.Sensor.attr_get_int`,
210+
:meth:`zsensor.Sensor.attr_get_millis`, and :meth:`zsensor.Sensor.attr_get_micros` methods,
211+
but many sensors do not support these::
212+
213+
full_scale = accel.attr_get_float(ATTR_FULL_SCALE)
214+
215+
The attribute IDs that are used as arguments to the :meth:`zsensor.Sensor.attr_set`,
216+
:meth:`zsensor.Sensor.attr_get_float`, :meth:`zsensor.Sensor.attr_get_int`,
217+
:meth:`zsensor.Sensor.attr_get_millis`, and :meth:`zsensor.Sensor.attr_get_micros`
218+
methods are constants in the :mod:`zsensor` module named ``ATTR_*``.

ports/zephyr/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Features supported at this time:
2222
* `machine.PWM` class for PWM control.
2323
* `machine.ADC` class for ADC control.
2424
* `socket` module for networking (IPv4/IPv6).
25+
* `zsensor` module for reading sensors.
2526
* "Frozen modules" support to allow to bundle Python modules together
2627
with firmware. Including complete applications, including with
2728
run-on-boot capability.

ports/zephyr/modzsensor.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,77 @@ static mp_obj_t sensor_get_int(mp_obj_t self_in, mp_obj_t channel_in) {
9393
}
9494
MP_DEFINE_CONST_FUN_OBJ_2(sensor_get_int_obj, sensor_get_int);
9595

96+
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) {
97+
mp_obj_sensor_t *self = MP_OBJ_TO_PTR(self_in);
98+
99+
int st = sensor_attr_get(self->dev, mp_obj_get_int(channel_in), mp_obj_get_int(attr_in), res);
100+
if (st != 0) {
101+
mp_raise_OSError(-st);
102+
}
103+
}
104+
105+
static mp_obj_t sensor_attr_get_float(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) {
106+
struct sensor_value val;
107+
sensor_attr_get_internal(self_in, channel_in, attr_in, &val);
108+
return mp_obj_new_float(val.val1 + (mp_float_t)val.val2 / 1000000);
109+
}
110+
MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_float_obj, sensor_attr_get_float);
111+
112+
static mp_obj_t sensor_attr_get_micros(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) {
113+
struct sensor_value val;
114+
sensor_attr_get_internal(self_in, channel_in, attr_in, &val);
115+
return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000000 + val.val2);
116+
}
117+
MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_micros_obj, sensor_attr_get_micros);
118+
119+
static mp_obj_t sensor_attr_get_millis(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) {
120+
struct sensor_value val;
121+
sensor_attr_get_internal(self_in, channel_in, attr_in, &val);
122+
return MP_OBJ_NEW_SMALL_INT(val.val1 * 1000 + val.val2 / 1000);
123+
}
124+
MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_millis_obj, sensor_attr_get_millis);
125+
126+
static mp_obj_t sensor_attr_get_int(mp_obj_t self_in, mp_obj_t channel_in, mp_obj_t attr_in) {
127+
struct sensor_value val;
128+
sensor_attr_get_internal(self_in, channel_in, attr_in, &val);
129+
return MP_OBJ_NEW_SMALL_INT(val.val1);
130+
}
131+
MP_DEFINE_CONST_FUN_OBJ_3(sensor_attr_get_int_obj, sensor_attr_get_int);
132+
133+
static mp_obj_t mp_sensor_attr_set(size_t n_args, const mp_obj_t *args) {
134+
mp_obj_sensor_t *self = MP_OBJ_TO_PTR(args[0]);
135+
mp_obj_t channel_in = args[1];
136+
mp_obj_t attr_in = args[2];
137+
struct sensor_value val;
138+
if (n_args == 4) {
139+
// One float argument
140+
float v = mp_obj_get_float(args[3]);
141+
val.val1 = (int32_t)v;
142+
val.val2 = (int32_t)((v - val.val1) * 1000000);
143+
} else {
144+
// Two integer arguments
145+
val.val1 = mp_obj_get_int(args[3]);
146+
val.val2 = mp_obj_get_int(args[4]);
147+
}
148+
int st = sensor_attr_set(self->dev, mp_obj_get_int(channel_in), mp_obj_get_int(attr_in), &val);
149+
if (st != 0) {
150+
mp_raise_OSError(-st);
151+
}
152+
return mp_const_none;
153+
}
154+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sensor_attr_set_obj, 4, 5, mp_sensor_attr_set);
155+
96156
static const mp_rom_map_elem_t sensor_locals_dict_table[] = {
97157
{ MP_ROM_QSTR(MP_QSTR_measure), MP_ROM_PTR(&sensor_measure_obj) },
98158
{ MP_ROM_QSTR(MP_QSTR_get_float), MP_ROM_PTR(&sensor_get_float_obj) },
99159
{ MP_ROM_QSTR(MP_QSTR_get_micros), MP_ROM_PTR(&sensor_get_micros_obj) },
100160
{ MP_ROM_QSTR(MP_QSTR_get_millis), MP_ROM_PTR(&sensor_get_millis_obj) },
101161
{ MP_ROM_QSTR(MP_QSTR_get_int), MP_ROM_PTR(&sensor_get_int_obj) },
162+
{ MP_ROM_QSTR(MP_QSTR_attr_get_float), MP_ROM_PTR(&sensor_attr_get_float_obj) },
163+
{ MP_ROM_QSTR(MP_QSTR_attr_get_micros), MP_ROM_PTR(&sensor_attr_get_micros_obj) },
164+
{ MP_ROM_QSTR(MP_QSTR_attr_get_millis), MP_ROM_PTR(&sensor_attr_get_millis_obj) },
165+
{ MP_ROM_QSTR(MP_QSTR_attr_get_int), MP_ROM_PTR(&sensor_attr_get_int_obj) },
166+
{ MP_ROM_QSTR(MP_QSTR_attr_set), MP_ROM_PTR(&sensor_attr_set_obj) },
102167
};
103168

104169
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[] = {
119184
C(ACCEL_X),
120185
C(ACCEL_Y),
121186
C(ACCEL_Z),
187+
C(ACCEL_XYZ),
122188
C(GYRO_X),
123189
C(GYRO_Y),
124190
C(GYRO_Z),
191+
C(GYRO_XYZ),
125192
C(MAGN_X),
126193
C(MAGN_Y),
127194
C(MAGN_Z),
195+
C(MAGN_XYZ),
128196
C(DIE_TEMP),
129197
C(AMBIENT_TEMP),
130198
C(PRESS),
@@ -145,6 +213,26 @@ static const mp_rom_map_elem_t mp_module_zsensor_globals_table[] = {
145213
C(GAS_RES),
146214
C(VOLTAGE),
147215
#undef C
216+
#define C(name) { MP_ROM_QSTR(MP_QSTR_ATTR_##name), MP_ROM_INT(SENSOR_ATTR_##name) }
217+
C(SAMPLING_FREQUENCY),
218+
C(LOWER_THRESH),
219+
C(UPPER_THRESH),
220+
C(SLOPE_TH),
221+
C(SLOPE_DUR),
222+
C(HYSTERESIS),
223+
C(OVERSAMPLING),
224+
C(FULL_SCALE),
225+
C(OFFSET),
226+
C(CALIB_TARGET),
227+
C(CONFIGURATION),
228+
C(CALIBRATION),
229+
C(FEATURE_MASK),
230+
C(ALERT),
231+
C(FF_DUR),
232+
C(BATCH_DURATION),
233+
C(GAIN),
234+
C(RESOLUTION),
235+
#undef C
148236
};
149237

150238
static MP_DEFINE_CONST_DICT(mp_module_zsensor_globals, mp_module_zsensor_globals_table);

0 commit comments

Comments
 (0)