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