9
9
CircuitPython module for the VL6180X distance sensor. See
10
10
examples/simpletest.py for a demo of the usage.
11
11
12
- * Author(s): Tony DiCola
12
+ * Author(s): Tony DiCola, Jonas Schatz
13
13
14
14
Implementation Notes
15
15
--------------------
26
26
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
27
27
"""
28
28
import struct
29
+ import time
30
+
29
31
from micropython import const
30
32
31
33
from adafruit_bus_device import i2c_device
32
34
33
35
try :
34
- import typing # pylint: disable=unused-import
36
+ from typing import Optional , List
35
37
from busio import I2C
36
38
except ImportError :
37
39
pass
40
42
__version__ = "0.0.0-auto.0"
41
43
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_VL6180X.git"
42
44
43
-
44
- # Internal constants:
45
- _VL6180X_DEFAULT_I2C_ADDR = const (0x29 )
45
+ # Registers
46
46
_VL6180X_REG_IDENTIFICATION_MODEL_ID = const (0x000 )
47
+
48
+ _VL6180X_REG_SYSTEM_HISTORY_CTRL = const (0x012 )
47
49
_VL6180X_REG_SYSTEM_INTERRUPT_CONFIG = const (0x014 )
48
50
_VL6180X_REG_SYSTEM_INTERRUPT_CLEAR = const (0x015 )
49
51
_VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET = const (0x016 )
52
+
50
53
_VL6180X_REG_SYSRANGE_START = const (0x018 )
54
+ _VL6180X_REG_SYSRANGE_INTERMEASUREMENT_PERIOD = const (0x01B )
55
+ _VL6180X_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET = const (0x024 )
56
+
51
57
_VL6180X_REG_SYSALS_START = const (0x038 )
52
58
_VL6180X_REG_SYSALS_ANALOGUE_GAIN = const (0x03F )
53
59
_VL6180X_REG_SYSALS_INTEGRATION_PERIOD_HI = const (0x040 )
54
60
_VL6180X_REG_SYSALS_INTEGRATION_PERIOD_LO = const (0x041 )
55
- _VL6180X_REG_RESULT_ALS_VAL = const (0x050 )
56
- _VL6180X_REG_RESULT_RANGE_VAL = const (0x062 )
61
+
57
62
_VL6180X_REG_RESULT_RANGE_STATUS = const (0x04D )
58
63
_VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO = const (0x04F )
59
- _VL6180X_REG_SYSRANGE_PART_TO_PART_RANGE_OFFSET = const (0x024 )
64
+ _VL6180X_REG_RESULT_ALS_VAL = const (0x050 )
65
+ _VL6180X_REG_RESULT_HISTORY_BUFFER_0 = const (0x052 )
66
+ _VL6180X_REG_RESULT_RANGE_VAL = const (0x062 )
67
+
68
+ # Internal constants:
69
+ _VL6180X_DEFAULT_I2C_ADDR = const (0x29 )
60
70
61
71
# User-facing constants:
62
72
ALS_GAIN_1 = const (0x06 )
82
92
83
93
84
94
class VL6180X :
85
- """Create an instance of the VL6180X distance sensor. You must pass in
95
+ """Create an instance of the VL6180X distance sensor. You must pass in
86
96
the following parameters:
87
97
88
98
:param i2c: An instance of the I2C bus connected to the sensor.
@@ -103,22 +113,85 @@ def __init__(
103
113
self ._write_8 (_VL6180X_REG_SYSTEM_FRESH_OUT_OF_RESET , 0x00 )
104
114
self .offset = offset
105
115
116
+ # Reset a sensor that crashed while in continuous mode
117
+ if self .continuous_mode_enabled :
118
+ self .stop_range_continuous ()
119
+ time .sleep (0.1 )
120
+
121
+ # Activate history buffer for range measurement
122
+ self ._write_8 (_VL6180X_REG_SYSTEM_HISTORY_CTRL , 0x01 )
123
+
106
124
@property
107
125
def range (self ) -> int :
108
126
"""Read the range of an object in front of sensor and return it in mm."""
109
- # wait for device to be ready for range measurement
110
- while not self ._read_8 (_VL6180X_REG_RESULT_RANGE_STATUS ) & 0x01 :
111
- pass
112
- # Start a range measurement
113
- self ._write_8 (_VL6180X_REG_SYSRANGE_START , 0x01 )
114
- # Poll until bit 2 is set
115
- while not self ._read_8 (_VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO ) & 0x04 :
116
- pass
117
- # read range in mm
118
- range_ = self ._read_8 (_VL6180X_REG_RESULT_RANGE_VAL )
119
- # clear interrupt
120
- self ._write_8 (_VL6180X_REG_SYSTEM_INTERRUPT_CLEAR , 0x07 )
121
- return range_
127
+ if self .continuous_mode_enabled :
128
+ return self ._read_range_continuous ()
129
+ return self ._read_range_single ()
130
+
131
+ @property
132
+ def range_from_history (self ) -> Optional [int ]:
133
+ """Read the latest range data from history
134
+ To do so, you don't have to wait for a complete measurement."""
135
+
136
+ if not self .range_history_enabled :
137
+ return None
138
+
139
+ return self ._read_8 (_VL6180X_REG_RESULT_HISTORY_BUFFER_0 )
140
+
141
+ @property
142
+ def ranges_from_history (self ) -> Optional [List [int ]]:
143
+ """ Read the last 16 range measurements from history """
144
+
145
+ if not self .range_history_enabled :
146
+ return None
147
+
148
+ return [
149
+ self ._read_8 (_VL6180X_REG_RESULT_HISTORY_BUFFER_0 + age )
150
+ for age in range (16 )
151
+ ]
152
+
153
+ @property
154
+ def range_history_enabled (self ) -> bool :
155
+ """ Checks if history buffer stores range data """
156
+
157
+ history_ctrl : int = self ._read_8 (_VL6180X_REG_SYSTEM_HISTORY_CTRL )
158
+
159
+ if history_ctrl & 0x0 :
160
+ print ("History buffering not enabled" )
161
+ return False
162
+
163
+ if (history_ctrl > 1 ) & 0x1 :
164
+ print ("History buffer stores ALS data, not range" )
165
+ return False
166
+
167
+ return True
168
+
169
+ def start_range_continuous (self , period : int = 100 ) -> None :
170
+ """Start continuous range mode
171
+ :param period: Time delay between measurements in ms
172
+ """
173
+ # Set range between measurements
174
+ period_reg : int = 0
175
+ if period > 10 :
176
+ if period < 2250 :
177
+ period_reg = (period // 10 ) - 1
178
+ else :
179
+ period_reg = 254
180
+ self ._write_8 (_VL6180X_REG_SYSRANGE_INTERMEASUREMENT_PERIOD , period_reg )
181
+
182
+ # Start continuous range measurement
183
+ self ._write_8 (_VL6180X_REG_SYSRANGE_START , 0x03 )
184
+
185
+ def stop_range_continuous (self ) -> None :
186
+ """Stop continuous range mode. It is advised to wait for about 0.3s
187
+ afterwards to avoid issues with the interrupt flags"""
188
+ if self .continuous_mode_enabled :
189
+ self ._write_8 (_VL6180X_REG_SYSRANGE_START , 0x01 )
190
+
191
+ @property
192
+ def continuous_mode_enabled (self ) -> bool :
193
+ """ Checks if continuous mode is enabled """
194
+ return self ._read_8 (_VL6180X_REG_SYSRANGE_START ) > 1 & 0x1
122
195
123
196
@property
124
197
def offset (self ) -> int :
@@ -132,6 +205,28 @@ def offset(self, offset: int) -> None:
132
205
)
133
206
self ._offset = offset
134
207
208
+ def _read_range_single (self ) -> int :
209
+ """ Read the range when in single-shot mode"""
210
+ while not self ._read_8 (_VL6180X_REG_RESULT_RANGE_STATUS ) & 0x01 :
211
+ pass
212
+ self ._write_8 (_VL6180X_REG_SYSRANGE_START , 0x01 )
213
+ return self ._read_range_continuous ()
214
+
215
+ def _read_range_continuous (self ) -> int :
216
+ """ Read the range when in continuous mode"""
217
+
218
+ # Poll until bit 2 is set
219
+ while not self ._read_8 (_VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO ) & 0x04 :
220
+ pass
221
+
222
+ # read range in mm
223
+ range_ = self ._read_8 (_VL6180X_REG_RESULT_RANGE_VAL )
224
+
225
+ # clear interrupt
226
+ self ._write_8 (_VL6180X_REG_SYSTEM_INTERRUPT_CLEAR , 0x07 )
227
+
228
+ return range_
229
+
135
230
def read_lux (self , gain : int ) -> float :
136
231
"""Read the lux (light value) from the sensor and return it. Must
137
232
specify the gain value to use for the lux reading:
0 commit comments