Skip to content

Commit ff56002

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 a9c4d31 commit ff56002

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.
@@ -120,20 +121,9 @@ func (d *Device) ReadRange() (r Range, err error) {
120121
// and the sensor is not moving the returned value will be around 1000000 or
121122
// -1000000.
122123
func (d *Device) ReadAcceleration() (int32, int32, int32, error) {
123-
x, y, z := d.ReadRawAcceleration()
124-
divider := float32(1)
125-
switch d.r {
126-
case RANGE_16_G:
127-
divider = 1365
128-
case RANGE_8_G:
129-
divider = 4096
130-
case RANGE_4_G:
131-
divider = 8190
132-
case RANGE_2_G:
133-
divider = 16380
134-
}
135-
136-
return int32(float32(x) / divider * 1000000), int32(float32(y) / divider * 1000000), int32(float32(z) / divider * 1000000), nil
124+
rawX, rawY, rawZ := d.ReadRawAcceleration()
125+
x, y, z := normalizeRange(rawX, rawY, rawZ, d.r)
126+
return x, y, z, nil
137127
}
138128

139129
// ReadRawAcceleration returns the raw x, y and z axis from the LIS3DH
@@ -149,3 +139,68 @@ func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) {
149139

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

0 commit comments

Comments
 (0)