1- package mpu6050
1+ // Package mpu6050 provides a driver for the MPU6050 accelerometer and gyroscope
2+ // made by InvenSense.
3+ //
4+ // Datasheets:
5+ // https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf
6+ // https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
7+ package mpu6050 // import "tinygo.org/x/drivers/mpu6050"
28
39import (
410 "encoding/binary"
511 "errors"
12+ "fmt"
613
714 "tinygo.org/x/drivers"
815)
916
1017const DefaultAddress = 0x68
1118
19+ // RangeAccel defines the range of the accelerometer.
20+ // Allowed values are 2, 4, 8 and 16 with the unit g (gravity).
21+ type RangeAccel uint8
22+
23+ // RangeGyro defines the range of the gyroscope.
24+ // Allowed values are 250, 500, 1000 and 2000 with the unit °/s (degree per second).
25+ type RangeGyro uint8
26+
1227type Config struct {
1328 // Use ACCEL_RANGE_2 through ACCEL_RANGE_16.
14- AccRange byte
29+ AccelRange RangeAccel
1530 // Use GYRO_RANGE_250 through GYRO_RANGE_2000
16- GyroRange byte
31+ GyroRange RangeGyro
1732 sampleRatio byte // TODO(soypat): expose these as configurable.
1833 clkSel byte
1934}
@@ -23,9 +38,12 @@ type Device struct {
2338 conn drivers.I2C
2439 aRange int32 //Gyroscope FSR acording to SetAccelRange input
2540 gRange int32 //Gyroscope FSR acording to SetGyroRange input
26- // RawData contains the accelerometer, gyroscope and temperature RawData read
27- // in the last call via the Update method.
28- RawData [14 ]byte
41+ // data contains the accelerometer, gyroscope and temperature data read
42+ // in the last call via the Update method. The data is stored as seven 16bit unsigned
43+ // integers in big endian format:
44+ //
45+ // | ax | ay | az | temp | gx | gy | gz |
46+ data [14 ]byte
2947 address byte
3048}
3149
@@ -44,67 +62,74 @@ func New(bus drivers.I2C, addr uint16) *Device {
4462// and wakes up the peripheral.
4563func (p * Device ) Configure (data Config ) (err error ) {
4664 if err = p .Sleep (false ); err != nil {
47- return errors .New ("set sleep: " + err .Error ())
65+ // We have a special error case for what is probably the first write
66+ // to the device.
67+ return fmt .Errorf ("during attempt to wake: %w" , err )
4868 }
49- if err = p .SetClockSource (data .clkSel ); err != nil {
50- return errors . New ( "set clksrc: " + err . Error ())
69+ if err = p .setClockSource (data .clkSel ); err != nil {
70+ return err
5171 }
52- if err = p .SetSampleRate (data .sampleRatio ); err != nil {
53- return errors . New ( "set sampleratio: " + err . Error ())
72+ if err = p .setSampleRate (data .sampleRatio ); err != nil {
73+ return err
5474 }
55- if err = p .SetRangeGyro (data .GyroRange ); err != nil {
56- return errors . New ( "set gyrorange: " + err . Error ())
75+ if err = p .setRangeGyro (data .GyroRange ); err != nil {
76+ return err
5777 }
58- if err = p .SetRangeAccel (data .AccRange ); err != nil {
59- return errors . New ( "set accelrange: " + err . Error ())
78+ if err = p .setRangeAccel (data .AccelRange ); err != nil {
79+ return err
6080 }
6181 return nil
6282}
6383
84+ func (d Device ) Connected () bool {
85+ data := []byte {0 }
86+ d .read (_WHO_AM_I , data )
87+ return data [0 ] == 0x68
88+ }
89+
6490// Update fetches the latest data from the MPU6050
6591func (p * Device ) Update () (err error ) {
66- if err = p .read (_ACCEL_XOUT_H , p .RawData [:]); err != nil {
92+ if err = p .read (_ACCEL_XOUT_H , p .data [:]); err != nil {
6793 return err
6894 }
6995 return nil
7096}
7197
7298// Acceleration returns last read acceleration in µg (micro-gravity).
73- // When one of the axes is pointing straight to Earth
74- // and the sensor is not moving the returned value will be around 1000000 or
75- // -1000000.
99+ // When one of the axes is pointing straight to Earth and the sensor is not
100+ // moving the returned value will be around 1000000 or -1000000.
76101func (d * Device ) Acceleration () (ax , ay , az int32 ) {
77102 const accelOffset = 0
78- ax = int32 (convertWord (d .RawData [accelOffset + 0 :])) * 15625 / 512 * d .aRange
79- ay = int32 (convertWord (d .RawData [accelOffset + 2 :])) * 15625 / 512 * d .aRange
80- az = int32 (convertWord (d .RawData [accelOffset + 4 :])) * 15625 / 512 * d .aRange
103+ ax = int32 (convertWord (d .data [accelOffset + 0 :])) * 15625 / 512 * d .aRange
104+ ay = int32 (convertWord (d .data [accelOffset + 2 :])) * 15625 / 512 * d .aRange
105+ az = int32 (convertWord (d .data [accelOffset + 4 :])) * 15625 / 512 * d .aRange
81106 return ax , ay , az
82107}
83108
84- // Rotations reads the current rotation from the device and returns it in
109+ // AngularVelocity reads the current angular velocity from the device and returns it in
85110// µ°/rad (micro-radians/sec). This means that if you were to do a complete
86111// rotation along one axis and while doing so integrate all values over time,
87112// you would get a value close to 6.3 radians (360 degrees).
88113func (d * Device ) AngularVelocity () (gx , gy , gz int32 ) {
89114 const angvelOffset = 8
90- _ = d .RawData [angvelOffset + 5 ] // This line fails to compile if RawData is too short.
91- gx = int32 (convertWord (d .RawData [angvelOffset + 0 :])) * 4363 / 8192 * d .gRange
92- gy = int32 (convertWord (d .RawData [angvelOffset + 2 :])) * 4363 / 8192 * d .gRange
93- gz = int32 (convertWord (d .RawData [angvelOffset + 4 :])) * 4363 / 8192 * d .gRange
115+ _ = d .data [angvelOffset + 5 ] // This line fails to compile if RawData is too short.
116+ gx = int32 (convertWord (d .data [angvelOffset + 0 :])) * 4363 / 8192 * d .gRange
117+ gy = int32 (convertWord (d .data [angvelOffset + 2 :])) * 4363 / 8192 * d .gRange
118+ gz = int32 (convertWord (d .data [angvelOffset + 4 :])) * 4363 / 8192 * d .gRange
94119 return gx , gy , gz
95120}
96121
97122// Temperature returns the temperature of the device in milli-centigrade.
98123func (d * Device ) Temperature () (Celsius int32 ) {
99124 const tempOffset = 6
100- return 1506 * int32 (convertWord (d .RawData [tempOffset :]))/ 512 + 37 * 1000
125+ return 1506 * int32 (convertWord (d .data [tempOffset :]))/ 512 + 37 * 1000
101126}
102127
103128func convertWord (buf []byte ) int16 {
104129 return int16 (binary .BigEndian .Uint16 (buf ))
105130}
106131
107- // SetSampleRate sets the sample rate for the FIFO,
132+ // setSampleRate sets the sample rate for the FIFO,
108133// register ouput and DMP. The sample rate is determined
109134// by:
110135//
@@ -114,7 +139,7 @@ func convertWord(buf []byte) int16 {
114139// disabled and 1kHz otherwise. The maximum sample rate
115140// for the accelerometer is 1kHz, if a higher sample rate
116141// is chosen, the same accelerometer sample will be output.
117- func (p * Device ) SetSampleRate (srDiv byte ) (err error ) {
142+ func (p * Device ) setSampleRate (srDiv byte ) (err error ) {
118143 // setSampleRate
119144 var sr [1 ]byte
120145 sr [0 ] = srDiv
@@ -124,108 +149,78 @@ func (p *Device) SetSampleRate(srDiv byte) (err error) {
124149 return nil
125150}
126151
127- // SetClockSource configures the source of the clock
152+ // setClockSource configures the source of the clock
128153// for the peripheral.
129- func (p * Device ) SetClockSource (clkSel byte ) (err error ) {
130- // setClockSource
131- var pwrMgt [1 ]byte
132-
133- if err = p .read (_PWR_MGMT_1 , pwrMgt [:]); err != nil {
134- return err
135- }
136- pwrMgt [0 ] = (pwrMgt [0 ] & (^ _CLK_SEL_MASK )) | clkSel // Escribo solo el campo de clk_sel
137- if err = p .write8 (_PWR_MGMT_1 , pwrMgt [0 ]); err != nil {
138- return err
139- }
140- return nil
154+ func (p * Device ) setClockSource (clkSel byte ) (err error ) {
155+ return p .writeMasked (_PWR_MGMT_1 , _CLK_SEL_MASK , clkSel )
141156}
142157
143- // SetRangeGyro configures the full scale range of the gyroscope.
158+ // setRangeGyro configures the full scale range of the gyroscope.
144159// It has four possible values +- 250°/s, 500°/s, 1000°/s, 2000°/s.
145- // The function takes values of gyroRange from 0-3 where 0 means the
146- // lowest FSR (250°/s) and 3 is the highest FSR (2000°/s).
147- func (p * Device ) SetRangeGyro (gyroRange byte ) (err error ) {
160+ func (p * Device ) setRangeGyro (gyroRange RangeGyro ) (err error ) {
148161 switch gyroRange {
149- case GYRO_RANGE_250 :
162+ case RangeGyro250 :
150163 p .gRange = 250
151- case GYRO_RANGE_500 :
164+ case RangeGyro500 :
152165 p .gRange = 500
153- case GYRO_RANGE_1000 :
166+ case RangeGyro1000 :
154167 p .gRange = 1000
155- case GYRO_RANGE_2000 :
168+ case RangeGyro2000 :
156169 p .gRange = 2000
157170 default :
158171 return errors .New ("invalid gyroscope FSR input" )
159172 }
160- // setFullScaleGyroRange
161- var gConfig [1 ]byte
162-
163- if err = p .read (_GYRO_CONFIG , gConfig [:]); err != nil {
164- return err
165- }
166- gConfig [0 ] = (gConfig [0 ] & (^ _G_FS_SEL )) | (gyroRange << _G_FS_SHIFT ) // Escribo solo el campo de FS_sel
167-
168- if err = p .write8 (_GYRO_CONFIG , gConfig [0 ]); err != nil {
169- return err
170- }
171- return nil
173+ return p .writeMasked (_GYRO_CONFIG , _G_FS_SEL , uint8 (gyroRange )<< _G_FS_SHIFT )
172174}
173175
174- // SetRangeAccel configures the full scale range of the accelerometer.
176+ // setRangeAccel configures the full scale range of the accelerometer.
175177// It has four possible values +- 2g, 4g, 8g, 16g.
176178// The function takes values of accRange from 0-3 where 0 means the
177179// lowest FSR (2g) and 3 is the highest FSR (16g)
178- func (p * Device ) SetRangeAccel (accRange byte ) (err error ) {
180+ func (p * Device ) setRangeAccel (accRange RangeAccel ) (err error ) {
179181 switch accRange {
180- case ACCEL_RANGE_2 :
182+ case RangeAccel2 :
181183 p .aRange = 2
182- case ACCEL_RANGE_4 :
184+ case RangeAccel4 :
183185 p .aRange = 4
184- case ACCEL_RANGE_8 :
186+ case RangeAccel8 :
185187 p .aRange = 8
186- case ACCEL_RANGE_16 :
188+ case RangeAccel16 :
187189 p .aRange = 16
188190 default :
189191 return errors .New ("invalid accelerometer FSR input" )
190192 }
191-
192- var aConfig [1 ]byte
193- if err = p .read (_ACCEL_CONFIG , aConfig [:]); err != nil {
194- return err
195- }
196- aConfig [0 ] = (aConfig [0 ] & (^ _AFS_SEL )) | (accRange << _AFS_SHIFT )
197-
198- if err = p .write8 (_ACCEL_CONFIG , aConfig [0 ]); err != nil {
199- return err
200- }
201- return nil
193+ return p .writeMasked (_ACCEL_CONFIG , _AFS_SEL , uint8 (accRange )<< _AFS_SHIFT )
202194}
203195
204196// Sleep sets the sleep bit on the power managment 1 field.
205197// When the recieved bool is true, it sets the bit to 1 thus putting
206198// the peripheral in sleep mode.
207199// When false is recieved the bit is set to 0 and the peripheral wakes up.
208200func (p * Device ) Sleep (sleepEnabled bool ) (err error ) {
209- // setSleepBit
210- var pwrMgt [1 ]byte
211- if err = p .read (_PWR_MGMT_1 , pwrMgt [:]); err != nil {
201+ return p .writeMasked (_PWR_MGMT_1 , _SLEEP_MASK , b2u8 (sleepEnabled )<< _SLEEP_SHIFT )
202+ }
203+
204+ func (d * Device ) writeMasked (reg byte , mask byte , value byte ) error {
205+ var b [1 ]byte
206+ if err := d .read (reg , b [:]); err != nil {
212207 return err
213208 }
214- if sleepEnabled {
215- pwrMgt [ 0 ] = ( pwrMgt [0 ] & ( ^ _SLEEP_MASK )) | ( 1 << _SLEEP_SHIFT ) // Overwrite only Sleep
216- } else {
217- pwrMgt [ 0 ] = ( pwrMgt [ 0 ] & ( ^ _SLEEP_MASK ))
218- }
219- if err = p . write8 ( _PWR_MGMT_1 , pwrMgt [ 0 ]); err != nil {
220- return err
209+ b [ 0 ] = ( b [ 0 ] &^ mask ) | value & mask
210+ return d . write8 ( reg , b [0 ])
211+ }
212+
213+ func b2u8 ( b bool ) byte {
214+ if b {
215+ return 1
221216 }
222- return nil
217+ return 0
223218}
224219
225220func DefaultConfig () Config {
226221 return Config {
227- AccRange : ACCEL_RANGE_16 ,
228- GyroRange : GYRO_RANGE_2000 ,
222+ AccelRange : RangeAccel16 ,
223+ GyroRange : RangeGyro2000 ,
229224 sampleRatio : 0 , // TODO add const values.
230225 clkSel : 0 ,
231226 }
0 commit comments