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"
@@ -9,11 +15,24 @@ import (
915
1016const DefaultAddress = 0x68
1117
18+ // RangeAccel defines the range of the accelerometer.
19+ // Allowed values are 2, 4, 8 and 16 with the unit g (gravity).
20+ type RangeAccel uint8
21+
22+ // RangeGyro defines the range of the gyroscope.
23+ // Allowed values are 250, 500, 1000 and 2000 with the unit °/s (degree per second).
24+ type RangeGyro uint8
25+
26+ var (
27+ errInvalidRangeAccel = errors .New ("mpu6050: invalid range for accelerometer" )
28+ errInvalidRangeGyro = errors .New ("mpu6050: invalid range for gyroscope" )
29+ )
30+
1231type Config struct {
1332 // Use ACCEL_RANGE_2 through ACCEL_RANGE_16.
14- AccRange byte
33+ AccelRange RangeAccel
1534 // Use GYRO_RANGE_250 through GYRO_RANGE_2000
16- GyroRange byte
35+ GyroRange RangeGyro
1736 sampleRatio byte // TODO(soypat): expose these as configurable.
1837 clkSel byte
1938}
@@ -23,9 +42,12 @@ type Device struct {
2342 conn drivers.I2C
2443 aRange int32 //Gyroscope FSR acording to SetAccelRange input
2544 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
45+ // data contains the accelerometer, gyroscope and temperature data read
46+ // in the last call via the Update method. The data is stored as seven 16bit unsigned
47+ // integers in big endian format:
48+ //
49+ // | ax | ay | az | temp | gx | gy | gz |
50+ data [14 ]byte
2951 address byte
3052}
3153
@@ -44,67 +66,72 @@ func New(bus drivers.I2C, addr uint16) *Device {
4466// and wakes up the peripheral.
4567func (p * Device ) Configure (data Config ) (err error ) {
4668 if err = p .Sleep (false ); err != nil {
47- return errors . New ( "set sleep: " + err . Error ())
69+ return err
4870 }
49- if err = p .SetClockSource (data .clkSel ); err != nil {
50- return errors . New ( "set clksrc: " + err . Error ())
71+ if err = p .setClockSource (data .clkSel ); err != nil {
72+ return err
5173 }
52- if err = p .SetSampleRate (data .sampleRatio ); err != nil {
53- return errors . New ( "set sampleratio: " + err . Error ())
74+ if err = p .setSampleRate (data .sampleRatio ); err != nil {
75+ return err
5476 }
55- if err = p .SetRangeGyro (data .GyroRange ); err != nil {
56- return errors . New ( "set gyrorange: " + err . Error ())
77+ if err = p .setRangeGyro (data .GyroRange ); err != nil {
78+ return err
5779 }
58- if err = p .SetRangeAccel (data .AccRange ); err != nil {
59- return errors . New ( "set accelrange: " + err . Error ())
80+ if err = p .setRangeAccel (data .AccelRange ); err != nil {
81+ return err
6082 }
6183 return nil
6284}
6385
86+ func (d Device ) Connected () bool {
87+ data := []byte {0 }
88+ d .read (_WHO_AM_I , data )
89+ return data [0 ] == 0x68
90+ }
91+
6492// Update fetches the latest data from the MPU6050
6593func (p * Device ) Update () (err error ) {
66- if err = p .read (_ACCEL_XOUT_H , p .RawData [:]); err != nil {
94+ if err = p .read (_ACCEL_XOUT_H , p .data [:]); err != nil {
6795 return err
6896 }
6997 return nil
7098}
7199
72100// 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.
101+ // When one of the axes is pointing straight to Earth and the sensor is not
102+ // moving the returned value will be around 1000000 or -1000000.
76103func (d * Device ) Acceleration () (ax , ay , az int32 ) {
77104 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
105+ ax = int32 (convertWord (d .data [accelOffset + 0 :])) * 15625 / 512 * d .aRange
106+ ay = int32 (convertWord (d .data [accelOffset + 2 :])) * 15625 / 512 * d .aRange
107+ az = int32 (convertWord (d .data [accelOffset + 4 :])) * 15625 / 512 * d .aRange
81108 return ax , ay , az
82109}
83110
84- // Rotations reads the current rotation from the device and returns it in
111+ // AngularVelocity reads the current angular velocity from the device and returns it in
85112// µ°/rad (micro-radians/sec). This means that if you were to do a complete
86113// rotation along one axis and while doing so integrate all values over time,
87114// you would get a value close to 6.3 radians (360 degrees).
88115func (d * Device ) AngularVelocity () (gx , gy , gz int32 ) {
89116 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
117+ _ = d .data [angvelOffset + 5 ] // This line fails to compile if RawData is too short.
118+ gx = int32 (convertWord (d .data [angvelOffset + 0 :])) * 4363 / 8192 * d .gRange
119+ gy = int32 (convertWord (d .data [angvelOffset + 2 :])) * 4363 / 8192 * d .gRange
120+ gz = int32 (convertWord (d .data [angvelOffset + 4 :])) * 4363 / 8192 * d .gRange
94121 return gx , gy , gz
95122}
96123
97124// Temperature returns the temperature of the device in milli-centigrade.
98125func (d * Device ) Temperature () (Celsius int32 ) {
99126 const tempOffset = 6
100- return 1506 * int32 (convertWord (d .RawData [tempOffset :]))/ 512 + 37 * 1000
127+ return 1506 * int32 (convertWord (d .data [tempOffset :]))/ 512 + 37 * 1000
101128}
102129
103130func convertWord (buf []byte ) int16 {
104131 return int16 (binary .BigEndian .Uint16 (buf ))
105132}
106133
107- // SetSampleRate sets the sample rate for the FIFO,
134+ // setSampleRate sets the sample rate for the FIFO,
108135// register ouput and DMP. The sample rate is determined
109136// by:
110137//
@@ -114,7 +141,7 @@ func convertWord(buf []byte) int16 {
114141// disabled and 1kHz otherwise. The maximum sample rate
115142// for the accelerometer is 1kHz, if a higher sample rate
116143// is chosen, the same accelerometer sample will be output.
117- func (p * Device ) SetSampleRate (srDiv byte ) (err error ) {
144+ func (p * Device ) setSampleRate (srDiv byte ) (err error ) {
118145 // setSampleRate
119146 var sr [1 ]byte
120147 sr [0 ] = srDiv
@@ -124,108 +151,78 @@ func (p *Device) SetSampleRate(srDiv byte) (err error) {
124151 return nil
125152}
126153
127- // SetClockSource configures the source of the clock
154+ // setClockSource configures the source of the clock
128155// 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
156+ func (p * Device ) setClockSource (clkSel byte ) (err error ) {
157+ return p .writeMasked (_PWR_MGMT_1 , _CLK_SEL_MASK , clkSel )
141158}
142159
143- // SetRangeGyro configures the full scale range of the gyroscope.
160+ // setRangeGyro configures the full scale range of the gyroscope.
144161// 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 ) {
162+ func (p * Device ) setRangeGyro (gyroRange RangeGyro ) (err error ) {
148163 switch gyroRange {
149- case GYRO_RANGE_250 :
164+ case RangeGyro250 :
150165 p .gRange = 250
151- case GYRO_RANGE_500 :
166+ case RangeGyro500 :
152167 p .gRange = 500
153- case GYRO_RANGE_1000 :
168+ case RangeGyro1000 :
154169 p .gRange = 1000
155- case GYRO_RANGE_2000 :
170+ case RangeGyro2000 :
156171 p .gRange = 2000
157172 default :
158- return errors . New ( "invalid gyroscope FSR input" )
173+ return errInvalidRangeGyro
159174 }
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
175+ return p .writeMasked (_GYRO_CONFIG , _G_FS_SEL , uint8 (gyroRange )<< _G_FS_SHIFT )
172176}
173177
174- // SetRangeAccel configures the full scale range of the accelerometer.
178+ // setRangeAccel configures the full scale range of the accelerometer.
175179// It has four possible values +- 2g, 4g, 8g, 16g.
176180// The function takes values of accRange from 0-3 where 0 means the
177181// lowest FSR (2g) and 3 is the highest FSR (16g)
178- func (p * Device ) SetRangeAccel (accRange byte ) (err error ) {
182+ func (p * Device ) setRangeAccel (accRange RangeAccel ) (err error ) {
179183 switch accRange {
180- case ACCEL_RANGE_2 :
184+ case RangeAccel2 :
181185 p .aRange = 2
182- case ACCEL_RANGE_4 :
186+ case RangeAccel4 :
183187 p .aRange = 4
184- case ACCEL_RANGE_8 :
188+ case RangeAccel8 :
185189 p .aRange = 8
186- case ACCEL_RANGE_16 :
190+ case RangeAccel16 :
187191 p .aRange = 16
188192 default :
189- return errors . New ( "invalid accelerometer FSR input" )
193+ return errInvalidRangeAccel
190194 }
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
195+ return p .writeMasked (_ACCEL_CONFIG , _AFS_SEL , uint8 (accRange )<< _AFS_SHIFT )
202196}
203197
204198// Sleep sets the sleep bit on the power managment 1 field.
205199// When the recieved bool is true, it sets the bit to 1 thus putting
206200// the peripheral in sleep mode.
207201// When false is recieved the bit is set to 0 and the peripheral wakes up.
208202func (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 {
203+ return p .writeMasked (_PWR_MGMT_1 , _SLEEP_MASK , b2u8 (sleepEnabled )<< _SLEEP_SHIFT )
204+ }
205+
206+ func (d * Device ) writeMasked (reg byte , mask byte , value byte ) error {
207+ var b [1 ]byte
208+ if err := d .read (reg , b [:]); err != nil {
212209 return err
213210 }
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
211+ b [ 0 ] = ( b [ 0 ] &^ mask ) | value & mask
212+ return d . write8 ( reg , b [0 ])
213+ }
214+
215+ func b2u8 ( b bool ) byte {
216+ if b {
217+ return 1
221218 }
222- return nil
219+ return 0
223220}
224221
225222func DefaultConfig () Config {
226223 return Config {
227- AccRange : ACCEL_RANGE_16 ,
228- GyroRange : GYRO_RANGE_2000 ,
224+ AccelRange : RangeAccel16 ,
225+ GyroRange : RangeGyro2000 ,
229226 sampleRatio : 0 , // TODO add const values.
230227 clkSel : 0 ,
231228 }
0 commit comments