Skip to content

Commit 78164eb

Browse files
committed
added range, rate, and mode
1 parent fd22004 commit 78164eb

File tree

1 file changed

+135
-3
lines changed

1 file changed

+135
-3
lines changed

adafruit_lsm303_accel.py

Lines changed: 135 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
from adafruit_register.i2c_struct import UnaryStruct
5656
from adafruit_register.i2c_bit import RWBit
5757
from adafruit_register.i2c_bits import RWBits
58+
from adafruit_register.i2c_struct_array import StructArray
5859

5960

6061
__version__ = "0.0.0-auto.0"
@@ -101,8 +102,35 @@
101102
_REG_ACCEL_WHO_AM_I = const(0x0F)
102103

103104
# Conversion constants
104-
_LSM303ACCEL_MG_LSB = 16704.0
105+
_LSM303ACCEL_MG_LSB = 16704.0 # magic!
105106
_GRAVITY_STANDARD = 9.80665 # Earth's gravity in m/s^2
107+
_SMOLLER_GRAVITY = 0.00980665
108+
109+
class Rate:
110+
RATE_SHUTDOWN = const(0)
111+
RATE_1_HZ = const(1)
112+
RATE_10_HZ = const(2)
113+
RATE_25_HZ = const(3)
114+
RATE_50_HZ = const(4)
115+
RATE_100_HZ = const(5)
116+
RATE_200_HZ = const(6)
117+
RATE_400_HZ = const(7)
118+
RATE_1620_HZ = const(8)
119+
RATE_1344_HZ = const(9)
120+
121+
class Mode:
122+
"""Options for `mode`"""
123+
MODE_NORMAL = const(0)
124+
MODE_HIGH_RESOLUTION = const(1)
125+
MODE_LOW_POWER = const(2)
126+
127+
class Range:
128+
"""Options for `range`"""
129+
RANGE_2G = const(0)
130+
RANGE_4G = const(1)
131+
RANGE_8G = const(2)
132+
RANGE_16G = const(3)
133+
106134
# pylint: enable=bad-whitespace
107135

108136
class LSM303_Accel:
@@ -122,13 +150,25 @@ class LSM303_Accel:
122150
_act_duration = UnaryStruct(_REG_ACCEL_ACT_DUR_A, "B")
123151

124152
_data_rate = RWBits(4, _REG_ACCEL_CTRL_REG1_A, 4, 1)
153+
_enable_xyz = RWBits(3, _REG_ACCEL_CTRL_REG1_A, 0, 1)
154+
_raw_accel_data = StructArray(_REG_ACCEL_OUT_X_L_A, "<h", 3)
155+
156+
_low_power = RWBit(_REG_ACCEL_CTRL_REG1_A, 3, 1)
157+
_high_resolution = RWBit(_REG_ACCEL_CTRL_REG4_A, 3, 1)
158+
159+
160+
_range = RWBits(2, _REG_ACCEL_CTRL_REG4_A, 4, 1)
125161

126162
_BUFFER = bytearray(6)
127163

128164
def __init__(self, i2c):
129165
self._accel_device = I2CDevice(i2c, _ADDRESS_ACCEL)
130166
self.i2c_device = self._accel_device
131-
self._write_u8(self._accel_device, _REG_ACCEL_CTRL_REG1_A, 0x27) # Enable the accelerometer
167+
#self._write_u8(self._accel_device, _REG_ACCEL_CTRL_REG1_A, 0x27) # Enable the accelerometer
168+
self._data_rate = 2
169+
self._enable_xyz = 0b111
170+
self._cached_mode = 0
171+
self._cached_range = 0
132172

133173
@property
134174
def raw_acceleration(self):
@@ -143,9 +183,101 @@ def acceleration(self):
143183
"""The processed accelerometer sensor values.
144184
A 3-tuple of X, Y, Z axis values in meters per second squared that are signed floats.
145185
"""
186+
146187
raw_accel_data = self.raw_acceleration
147-
return tuple([n / _LSM303ACCEL_MG_LSB * _GRAVITY_STANDARD for n in raw_accel_data])
148188

189+
x = self._scale_data(raw_accel_data[0])
190+
y = self._scale_data(raw_accel_data[1])
191+
z = self._scale_data(raw_accel_data[2])
192+
193+
return (x, y, z)
194+
195+
def _scale_data(self, raw_measurement):
196+
lsb, shift = self._lsb_shift()
197+
198+
return(raw_measurement >> shift) * lsb * _SMOLLER_GRAVITY
199+
200+
def _lsb_shift(self):
201+
# the bit depth of the data depends on the mode, and the lsb value
202+
# depends on the mode and range
203+
lsb = -1 # the default, normal mode @ 2G
204+
205+
if self._cached_mode is Mode.MODE_HIGH_RESOLUTION: # 12-bit
206+
shift = 4
207+
if self._cached_range is Range.RANGE_2G:
208+
lsb = 0.98
209+
elif self._cached_range is Range.RANGE_4G:
210+
lsb = 1.95
211+
elif self._cached_range is Range.RANGE_8G:
212+
lsb = 3.9
213+
elif self._cached_range is Range.RANGE_16G:
214+
lsb = 11.72
215+
elif self._cached_mode is Mode.MODE_NORMAL: # 10-bit
216+
shift = 6
217+
if self._cached_range is Range.RANGE_2G:
218+
lsb = 3.9
219+
elif self._cached_range is Range.RANGE_4G:
220+
lsb = 7.82
221+
elif self._cached_range is Range.RANGE_8G:
222+
lsb = 15.63
223+
elif self._cached_range is Range.RANGE_16G:
224+
lsb = 46.9
225+
226+
227+
elif self._cached_mode is Mode.MODE_LOW_POWER: # 8-bit
228+
shift = 8
229+
if self._cached_range is Range.RANGE_2G:
230+
lsb = 15.63
231+
elif self._cached_range is Range.RANGE_4G:
232+
lsb = 31.26
233+
elif self._cached_range is Range.RANGE_8G:
234+
lsb = 62.52
235+
elif self._cached_range is Range.RANGE_16G:
236+
lsb = 187.58
237+
238+
if lsb is -1:
239+
raise AttributeError("'impossible' range or mode detected: range: %d mode: %d"%
240+
(self._cached_range, self._cached_mode))
241+
return (lsb, shift)
242+
243+
@property
244+
def data_rate(self):
245+
"""Select the rate at which the sensor takes measurements. Must be a `Rate`"""
246+
return self._data_rate
247+
248+
@data_rate.setter
249+
def data_rate(self, value):
250+
if value < 0 or value > 9:
251+
raise AttributeError("data_rate must be a `Rate`")
252+
253+
self._data_rate = value
254+
255+
@property
256+
def range(self):
257+
"""Adjusts the range of values that the sensor can measure, from +- 2G to +-16G
258+
Note that larger ranges will be less accurate. Must be a `Range`"""
259+
return self._cached_range
260+
261+
@range.setter
262+
def range(self, value):
263+
if value < 0 or value >3:
264+
raise AttributeError("range must be a `Range`")
265+
self._range = value
266+
self._cached_range = value
267+
268+
@property
269+
def mode(self):
270+
"""Sets the power mode of the sensor. The mode must be a `Mode`. Note that the
271+
mode and range will both affect the accuracy of the sensor"""
272+
return self._cached_mode
273+
274+
@mode.setter
275+
def mode(self, value):
276+
if value < 0 or value > 2:
277+
raise AttributeError("mode must be a `Mode`")
278+
self._high_resolution = value & 0b01
279+
self._low_power = (value & 0b10) >>1
280+
self._cached_mode = value
149281

150282
def _read_u8(self, device, address):
151283
with device as i2c:

0 commit comments

Comments
 (0)