Skip to content

Commit a9b36f8

Browse files
authored
Mpu9150 (#596)
mpu9150: add mpu9150 driver
1 parent 1e45458 commit a9b36f8

File tree

6 files changed

+256
-3
lines changed

6 files changed

+256
-3
lines changed

examples/mpu9150/main.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Connects to an MPU9150 I2C accelerometer/gyroscope.
2+
package main
3+
4+
import (
5+
"machine"
6+
"time"
7+
8+
"tinygo.org/x/drivers/mpu9150"
9+
)
10+
11+
func main() {
12+
machine.I2C0.Configure(machine.I2CConfig{})
13+
14+
accel := mpu9150.New(machine.I2C0)
15+
accel.Configure()
16+
17+
for {
18+
x, y, z := accel.ReadAcceleration(mpu9150.ACCEL_XOUT_H)
19+
println(x, y, z)
20+
time.Sleep(time.Millisecond * 100)
21+
}
22+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ require (
99
golang.org/x/net v0.7.0
1010
tinygo.org/x/tinyfont v0.3.0
1111
tinygo.org/x/tinyterm v0.1.0
12-
)
12+
)

go.sum

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@ tinygo.org/x/tinyfont v0.3.0 h1:HIRLQoI3oc+2CMhPcfv+Ig88EcTImE/5npjqOnMD4lM=
5959
tinygo.org/x/tinyfont v0.3.0/go.mod h1:+TV5q0KpwSGRWnN+ITijsIhrWYJkoUCp9MYELjKpAXk=
6060
tinygo.org/x/tinyfs v0.1.0/go.mod h1:ysc8Y92iHfhTXeyEM9+c7zviUQ4fN9UCFgSOFfMWv20=
6161
tinygo.org/x/tinyterm v0.1.0 h1:80i+j+KWoxCFa/Xfp6pWbh79x+8zUdMXC1vaKj2QhkY=
62-
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=
62+
tinygo.org/x/tinyterm v0.1.0/go.mod h1:/DDhNnGwNF2/tNgHywvyZuCGnbH3ov49Z/6e8LPLRR4=

mpu9150/mpu9150.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Package mpu9150 provides a driver for the MPU9150 accelerometer and gyroscope
2+
// made by InvenSense.
3+
//
4+
// Datasheets:
5+
// https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-9150-Datasheet.pdf
6+
// https://inertialelements.com/documents/resources_page/MPU9150-register-manual.pdf
7+
8+
package mpu9150
9+
10+
import (
11+
"tinygo.org/x/drivers"
12+
"tinygo.org/x/drivers/internal/legacy"
13+
)
14+
15+
// Device wraps an I2C connection to a MPU9150 device.
16+
type Device struct {
17+
bus drivers.I2C
18+
Address uint16
19+
}
20+
21+
// New creates a new MPU9150 connection. The I2C bus must already be
22+
// configured.
23+
//
24+
// This function only creates the Device object, it does not touch the device.
25+
func New(bus drivers.I2C) Device {
26+
return Device{bus, Address}
27+
}
28+
29+
// Connected returns whether a MPU9150 has been found.
30+
// It does a "who am I" request and checks the response.
31+
func (d Device) Connected() bool {
32+
data := []byte{0}
33+
legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
34+
return data[0] == 0x68 // 4.32 Register 117 – Who Am I (MPU-9150 Register Map and Descriptions)
35+
}
36+
37+
// Configure sets up the device for communication.
38+
func (d Device) Configure() error {
39+
return d.SetClockSource(CLOCK_INTERNAL)
40+
}
41+
42+
// ReadAcceleration reads the current acceleration from the device and returns
43+
// it in µg (micro-gravity). When one of the axes is pointing straight to Earth
44+
// and the sensor is not moving the returned value will be around 1000000 or
45+
// -1000000.
46+
func (d Device) ReadAcceleration(accel_axis byte) (x int32, y int32, z int32) {
47+
data := make([]byte, 6)
48+
legacy.ReadRegister(d.bus, uint8(d.Address), accel_axis, data)
49+
// Now do two things:
50+
// 1. merge the two values to a 16-bit number (and cast to a 32-bit integer)
51+
// 2. scale the value to bring it in the -1000000..1000000 range.
52+
// This is done with a trick. What we do here is essentially multiply by
53+
// 1000000 and divide by 16384 to get the original scale, but to avoid
54+
// overflow we do it at 1/64 of the value:
55+
// 1000000 / 64 = 15625
56+
// 16384 / 64 = 256
57+
x = int32(int16((uint16(data[0])<<8)|uint16(data[1]))) * 15625 / 256
58+
y = int32(int16((uint16(data[2])<<8)|uint16(data[3]))) * 15625 / 256
59+
z = int32(int16((uint16(data[4])<<8)|uint16(data[5]))) * 15625 / 256
60+
return
61+
}
62+
63+
// ReadRotation reads the current rotation from the device and returns it in
64+
// µ°/s (micro-degrees/sec). This means that if you were to do a complete
65+
// rotation along one axis and while doing so integrate all values over time,
66+
// you would get a value close to 360000000.
67+
func (d Device) ReadRotation(gyro_axis byte) (x int32, y int32, z int32) {
68+
data := make([]byte, 6)
69+
legacy.ReadRegister(d.bus, uint8(d.Address), gyro_axis, data)
70+
// First the value is converted from a pair of bytes to a signed 16-bit
71+
// value and then to a signed 32-bit value to avoid integer overflow.
72+
// Then the value is scaled to µ°/s (micro-degrees per second).
73+
// This is done in the following steps:
74+
// 1. Multiply by 250 * 1000_000
75+
// 2. Divide by 32768
76+
// The following calculation (x * 15625 / 2048 * 1000) is essentially the
77+
// same but avoids overflow. First both operations are divided by 16 leading
78+
// to multiply by 15625000 and divide by 2048, and then part of the multiply
79+
// is done after the divide instead of before.
80+
x = int32(int16((uint16(data[0])<<8)|uint16(data[1]))) * 15625 / 2048 * 1000
81+
y = int32(int16((uint16(data[2])<<8)|uint16(data[3]))) * 15625 / 2048 * 1000
82+
z = int32(int16((uint16(data[4])<<8)|uint16(data[5]))) * 15625 / 2048 * 1000
83+
return
84+
}
85+
86+
// SetClockSource allows the user to configure the clock source.
87+
func (d Device) SetClockSource(source uint8) error {
88+
return legacy.WriteRegister(d.bus, uint8(d.Address), PWR_MGMT_1, []uint8{source})
89+
}
90+
91+
// SetFullScaleGyroRange allows the user to configure the scale range for the gyroscope.
92+
func (d Device) SetFullScaleGyroRange(rng uint8) error {
93+
return legacy.WriteRegister(d.bus, uint8(d.Address), GYRO_CONFIG, []uint8{rng})
94+
}
95+
96+
// SetFullScaleAccelRange allows the user to configure the scale range for the accelerometer.
97+
func (d Device) SetFullScaleAccelRange(rng uint8) error {
98+
return legacy.WriteRegister(d.bus, uint8(d.Address), ACCEL_CONFIG, []uint8{rng})
99+
}

mpu9150/registers.go

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package mpu9150
2+
3+
// Constants/addresses used for I2C.
4+
5+
// The I2C address which this device listens to.
6+
const Address = 0x68
7+
8+
// Registers. Names, addresses and comments copied from the datasheet.
9+
const (
10+
// Self test registers
11+
SELF_TEST_X = 0x0D
12+
SELF_TEST_Y = 0x0E
13+
SELF_TEST_Z = 0x0F
14+
SELF_TEST_A = 0x10
15+
16+
SMPLRT_DIV = 0x19 // Sample rate divider
17+
CONFIG = 0x1A // Configuration
18+
GYRO_CONFIG = 0x1B // Gyroscope configuration
19+
ACCEL_CONFIG = 0x1C // Accelerometer configuration
20+
FIFO_EN = 0x23 // FIFO enable
21+
22+
// I2C pass-through configuration
23+
I2C_MST_CTRL = 0x24
24+
I2C_SLV0_ADDR = 0x25
25+
I2C_SLV0_REG = 0x26
26+
I2C_SLV0_CTRL = 0x27
27+
I2C_SLV1_ADDR = 0x28
28+
I2C_SLV1_REG = 0x29
29+
I2C_SLV1_CTRL = 0x2A
30+
I2C_SLV2_ADDR = 0x2B
31+
I2C_SLV2_REG = 0x2C
32+
I2C_SLV2_CTRL = 0x2D
33+
I2C_SLV3_ADDR = 0x2E
34+
I2C_SLV3_REG = 0x2F
35+
I2C_SLV3_CTRL = 0x30
36+
I2C_SLV4_ADDR = 0x31
37+
I2C_SLV4_REG = 0x32
38+
I2C_SLV4_DO = 0x33
39+
I2C_SLV4_CTRL = 0x34
40+
I2C_SLV4_DI = 0x35
41+
I2C_MST_STATUS = 0x36
42+
43+
// Interrupt configuration
44+
INT_PIN_CFG = 0x37 // Interrupt pin/bypass enable configuration
45+
INT_ENABLE = 0x38 // Interrupt enable
46+
INT_STATUS = 0x3A // Interrupt status
47+
48+
// Accelerometer measurements
49+
ACCEL_XOUT_H = 0x3B
50+
ACCEL_XOUT_L = 0x3C
51+
ACCEL_YOUT_H = 0x3D
52+
ACCEL_YOUT_L = 0x3E
53+
ACCEL_ZOUT_H = 0x3F
54+
ACCEL_ZOUT_L = 0x40
55+
56+
// Temperature measurement
57+
TEMP_OUT_H = 0x41
58+
TEMP_OUT_L = 0x42
59+
60+
// Gyroscope measurements
61+
GYRO_XOUT_H = 0x43
62+
GYRO_XOUT_L = 0x44
63+
GYRO_YOUT_H = 0x45
64+
GYRO_YOUT_L = 0x46
65+
GYRO_ZOUT_H = 0x47
66+
GYRO_ZOUT_L = 0x48
67+
68+
// External sensor data
69+
EXT_SENS_DATA_00 = 0x49
70+
EXT_SENS_DATA_01 = 0x4A
71+
EXT_SENS_DATA_02 = 0x4B
72+
EXT_SENS_DATA_03 = 0x4C
73+
EXT_SENS_DATA_04 = 0x4D
74+
EXT_SENS_DATA_05 = 0x4E
75+
EXT_SENS_DATA_06 = 0x4F
76+
EXT_SENS_DATA_07 = 0x50
77+
EXT_SENS_DATA_08 = 0x51
78+
EXT_SENS_DATA_09 = 0x52
79+
EXT_SENS_DATA_10 = 0x53
80+
EXT_SENS_DATA_11 = 0x54
81+
EXT_SENS_DATA_12 = 0x55
82+
EXT_SENS_DATA_13 = 0x56
83+
EXT_SENS_DATA_14 = 0x57
84+
EXT_SENS_DATA_15 = 0x58
85+
EXT_SENS_DATA_16 = 0x59
86+
EXT_SENS_DATA_17 = 0x5A
87+
EXT_SENS_DATA_18 = 0x5B
88+
EXT_SENS_DATA_19 = 0x5C
89+
EXT_SENS_DATA_20 = 0x5D
90+
EXT_SENS_DATA_21 = 0x5E
91+
EXT_SENS_DATA_22 = 0x5F
92+
EXT_SENS_DATA_23 = 0x60
93+
94+
// I2C peripheral data out
95+
I2C_SLV0_DO = 0x63
96+
I2C_SLV1_DO = 0x64
97+
I2C_SLV2_DO = 0x65
98+
I2C_SLV3_DO = 0x66
99+
I2C_MST_DELAY_CTRL = 0x67
100+
SIGNAL_PATH_RESET = 0x68
101+
102+
USER_CTRL = 0x6A // User control
103+
PWR_MGMT_1 = 0x6B // Power Management 1
104+
PWR_MGMT_2 = 0x6C // Power Management 2
105+
FIFO_COUNTH = 0x72 // FIFO count registers (high bits)
106+
FIFO_COUNTL = 0x73 // FIFO count registers (low bits)
107+
FIFO_R_W = 0x74 // FIFO read/write
108+
WHO_AM_I = 0x75 // Who am I
109+
110+
// Clock settings (4.28 Register 107 – Power Management 1)
111+
CLOCK_INTERNAL = 0x00
112+
CLOCK_PLL_XGYRO = 0x01
113+
CLOCK_PLL_YGYRO = 0x02
114+
CLOCK_PLL_ZGYRO = 0x03
115+
CLOCK_PLL_EXTERNAL_32_768_KZ = 0x04
116+
CLOCK_PLL_EXTERNAL_19_2_MHZ = 0x05
117+
CLOCK_RESERVED = 0x06
118+
CLOCK_STOP = 0x07
119+
120+
// Gyroscope settings (4.4 Register 27 – Gyroscope Configuration)
121+
FS_RANGE_250 = 0x00
122+
FS_RANGE_500 = 0x01
123+
FS_RANGE_1000 = 0x02
124+
FS_RANGE_2000 = 0x03
125+
126+
// Accelerometer settings (4.5 Register 28 – Accelerometer Configuration)
127+
AFS_RANGE_2G = 0x00
128+
AFS_RANGE_4G = 0x01
129+
AFS_RANGE_8G = 0x02
130+
AFS_RANGE_16G = 0x03
131+
)

smoketest.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,5 @@ tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu6886/mai
131131
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ttp229/main.go
132132
tinygo build -size short -o ./build/test.hex -target=pico ./examples/ndir/main_ndir.go
133133
tinygo build -size short -o ./build/test.hex -target=microbit ./examples/ndir/main_ndir.go
134-
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ndir/main_ndir.go
134+
tinygo build -size short -o ./build/test.hex -target=arduino-nano33 ./examples/ndir/main_ndir.go
135+
tinygo build -size short -o ./build/test.uf2 -target=pico ./examples/mpu9150/main.go

0 commit comments

Comments
 (0)