Skip to content

Commit 281eb76

Browse files
committed
lis3dh: add Update and Acceleration calls
This adjusts the API to the one proposed in #345, which I think is much better than direct ReadAcceleration etc calls. I have also updated the code that converts raw acceleration values to normalized values. The new code should be faster (didn't measure) and avoids floating point math.
1 parent 75b3499 commit 281eb76

File tree

1 file changed

+69
-14
lines changed

1 file changed

+69
-14
lines changed

lis3dh/lis3dh.go

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type Device struct {
1313
bus drivers.I2C
1414
Address uint16
1515
r Range
16+
accel [6]byte // stored acceleration data (from the Update call)
1617
}
1718

1819
// Driver configuration, used for the Configure call. All fields are optional.
@@ -119,20 +120,9 @@ func (d *Device) ReadRange() (r Range, err error) {
119120
// and the sensor is not moving the returned value will be around 1000000 or
120121
// -1000000.
121122
func (d *Device) ReadAcceleration() (int32, int32, int32, error) {
122-
x, y, z := d.ReadRawAcceleration()
123-
divider := float32(1)
124-
switch d.r {
125-
case RANGE_16_G:
126-
divider = 1365
127-
case RANGE_8_G:
128-
divider = 4096
129-
case RANGE_4_G:
130-
divider = 8190
131-
case RANGE_2_G:
132-
divider = 16380
133-
}
134-
135-
return int32(float32(x) / divider * 1000000), int32(float32(y) / divider * 1000000), int32(float32(z) / divider * 1000000), nil
123+
rawX, rawY, rawZ := d.ReadRawAcceleration()
124+
x, y, z := normalizeRange(rawX, rawY, rawZ, d.r)
125+
return x, y, z, nil
136126
}
137127

138128
// ReadRawAcceleration returns the raw x, y and z axis from the LIS3DH
@@ -148,3 +138,68 @@ func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
148138

149139
return
150140
}
141+
142+
// Update the sensor values of the 'which' parameter. Only acceleration is
143+
// supported at the moment.
144+
func (d *Device) Update(which drivers.Measurement) error {
145+
if which&drivers.Acceleration != 0 {
146+
// Read raw acceleration values and store them in the driver.
147+
err := legacy.WriteRegister(d.bus, uint8(d.Address), REG_OUT_X_L|0x80, nil)
148+
if err != nil {
149+
return err
150+
}
151+
err = d.bus.Tx(d.Address, nil, d.accel[:])
152+
if err != nil {
153+
return err
154+
}
155+
}
156+
return nil
157+
}
158+
159+
// Acceleration returns the last read acceleration in µg (micro-gravity).
160+
// When one of the axes is pointing straight to Earth and the sensor is not
161+
// moving the returned value will be around 1000000 or -1000000.
162+
func (d *Device) Acceleration() (x, y, z int32) {
163+
// Extract the raw 16-bit values.
164+
rawX := int16((uint16(d.accel[1]) << 8) | uint16(d.accel[0]))
165+
rawY := int16((uint16(d.accel[3]) << 8) | uint16(d.accel[2]))
166+
rawZ := int16((uint16(d.accel[5]) << 8) | uint16(d.accel[4]))
167+
168+
// Normalize these values, to be in µg (micro-gravity).
169+
return normalizeRange(rawX, rawY, rawZ, d.r)
170+
}
171+
172+
// Convert raw 16-bit values to normalized 32-bit values while avoiding floats
173+
// and divisions.
174+
func normalizeRange(rawX, rawY, rawZ int16, r Range) (x, y, z int32) {
175+
// We're going to convert the 16-bit raw values to values in the range
176+
// -1000_000..1000_000. For now we're going to assume a range of 16G, we'll
177+
// adjust that range later.
178+
// The formula is derived as follows, and carefully selected to avoid
179+
// overflow and integer divisions (the division will be optimized to a
180+
// bitshift):
181+
// x = x * 1000_000 / 2048
182+
// x = x * (1000_000/64) / (2048/64)
183+
// x = x * 15625 / 32
184+
x = int32(rawX) * 15625 / 32
185+
y = int32(rawY) * 15625 / 32
186+
z = int32(rawZ) * 15625 / 32
187+
188+
// Now we need to normalize the three values, since we assumed 16G before.
189+
shift := uint32(0)
190+
switch r {
191+
case RANGE_16_G:
192+
shift = 0
193+
case RANGE_8_G:
194+
shift = 1
195+
case RANGE_4_G:
196+
shift = 2
197+
case RANGE_2_G:
198+
shift = 3
199+
}
200+
x >>= shift
201+
y >>= shift
202+
z >>= shift
203+
204+
return
205+
}

0 commit comments

Comments
 (0)