@@ -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.
121122func (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