Skip to content

Commit bc9678a

Browse files
authored
mpu9250: Add i2c interface support (#101)
* Refactor SPI transport to be dual transport. * Implement I2C support.
1 parent 38cb339 commit bc9678a

File tree

3 files changed

+156
-136
lines changed

3 files changed

+156
-136
lines changed

mpu9250/mpu9250.go

+8-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
// Use of this source code is governed under the Apache License, Version 2.0
33
// that can be found in the LICENSE file.
44

5-
// Package mpu9250 MPU-9250 is a 9-axis MotionTracking device that combines a 3-axis gyroscope, 3-axis accelerometer, 3-axis magnetometer and a Digital Motion Processor™ (DMP)
5+
// Package mpu9250 MPU-9250 is a 9-axis MotionTracking device that combines a
6+
// 3-axis gyroscope, 3-axis accelerometer, 3-axis magnetometer and a Digital
7+
// Motion Processor™ (DMP). Connections via SPI or I2C are supported.
8+
//
9+
// There is a sample program in periph.io/x/cmd/mpu9250 that you can run to
10+
// test using the sensor.
611
//
712
// # Datasheet
813
//
@@ -24,16 +29,6 @@ const (
2429
accelsenSitivity = 16384
2530
)
2631

27-
// Proto defines the low-level methods used by different transports.
28-
type Proto interface {
29-
writeMaskedReg(address byte, mask byte, value byte) error
30-
readMaskedReg(address byte, mask byte) (byte, error)
31-
readByte(address byte) (byte, error)
32-
writeByte(address byte, value byte) error
33-
readUint16(address ...byte) (uint16, error)
34-
writeMagReg(address byte, value byte) error
35-
}
36-
3732
// AccelerometerData the values for x/y/z axises.
3833
type AccelerometerData struct {
3934
X, Y, Z int16
@@ -62,14 +57,14 @@ type SelfTestResult struct {
6257

6358
// MPU9250 defines the structure to keep reference to the transport.
6459
type MPU9250 struct {
65-
transport Proto
60+
transport Transport
6661
debug func(string, ...interface{})
6762
}
6863

6964
// New creates the new instance of the driver.
7065
//
7166
// transport the transport interface.
72-
func New(transport Proto) (*MPU9250, error) {
67+
func New(transport Transport) (*MPU9250, error) {
7368
return &MPU9250{transport: transport, debug: noop}, nil
7469
}
7570

mpu9250/spi.go

-123
This file was deleted.

mpu9250/transport.go

+148
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// Copyright 2020 The Periph Authors. All rights reserved.
2+
// Use of this source code is governed under the Apache License, Version 2.0
3+
// that can be found in the LICENSE file.
4+
5+
package mpu9250
6+
7+
import (
8+
"fmt"
9+
10+
"periph.io/x/conn/v3/gpio"
11+
"periph.io/x/conn/v3/i2c"
12+
"periph.io/x/conn/v3/physic"
13+
"periph.io/x/conn/v3/spi"
14+
"periph.io/x/conn/v3/spi/spireg"
15+
)
16+
17+
// DebugF the debug function type.
18+
type DebugF func(string, ...interface{})
19+
20+
// Transport Encapsulates the SPI transport parameters.
21+
type Transport struct {
22+
device spi.Conn
23+
d *i2c.Dev
24+
cs gpio.PinOut
25+
debug DebugF
26+
}
27+
28+
// NewSpiTransport Creates the SPI transport using the provided device path and chip select pin reference.
29+
func NewSpiTransport(path string, cs gpio.PinOut) (*Transport, error) {
30+
dev, err := spireg.Open(path)
31+
if err != nil {
32+
return nil, wrapf("can't open SPI %v", err)
33+
}
34+
conn, err := dev.Connect(1*physic.MegaHertz, spi.Mode0, 8)
35+
if err != nil {
36+
return nil, wrapf("can't initialize SPI %v", err)
37+
}
38+
return &Transport{device: conn, cs: cs, debug: noop}, nil
39+
}
40+
41+
func NewI2cTransport(bus i2c.Bus, address uint16) (*Transport, error) {
42+
return &Transport{d: &i2c.Dev{Bus: bus, Addr: address}, debug: noop}, nil
43+
}
44+
45+
// EnableDebug Sets the debugging output using the local print function.
46+
func (t *Transport) EnableDebug(f DebugF) {
47+
t.debug = f
48+
}
49+
50+
func (t *Transport) writeByte(address byte, value byte) error {
51+
if t.d == nil {
52+
return t.writeByteSPI(address, value)
53+
}
54+
return t.writeByteI2C(address, value)
55+
}
56+
57+
func (t *Transport) writeByteSPI(address, value byte) error {
58+
t.debug("write register %x value %x", address, value)
59+
var (
60+
buf = [...]byte{address, value}
61+
res [2]byte
62+
)
63+
if err := t.cs.Out(gpio.Low); err != nil {
64+
return err
65+
}
66+
if err := t.device.Tx(buf[:], res[:]); err != nil {
67+
return err
68+
}
69+
return t.cs.Out(gpio.High)
70+
}
71+
72+
func (t *Transport) writeByteI2C(address, value byte) error {
73+
w := []byte{address, value}
74+
return t.d.Tx(w, nil)
75+
}
76+
77+
func (t *Transport) writeMaskedReg(address byte, mask byte, value byte) error {
78+
t.debug("write masked %x, mask %x, value %x", address, mask, value)
79+
maskedValue := mask & value
80+
t.debug("masked value %x", maskedValue)
81+
regVal, err := t.readByte(address)
82+
if err != nil {
83+
return err
84+
}
85+
t.debug("current register %x", regVal)
86+
regVal = (regVal &^ maskedValue) | maskedValue
87+
t.debug("new value %x", regVal)
88+
return t.writeByte(address, regVal)
89+
}
90+
91+
func (t *Transport) readMaskedReg(address byte, mask byte) (byte, error) {
92+
t.debug("read masked %x, mask %x", address, mask)
93+
reg, err := t.readByte(address)
94+
if err != nil {
95+
return 0, err
96+
}
97+
t.debug("masked value %x", reg)
98+
return reg & mask, nil
99+
}
100+
101+
func (t *Transport) readByte(address byte) (byte, error) {
102+
if t.d == nil {
103+
return t.readByteSPI(address)
104+
}
105+
return t.readByteI2C(address)
106+
}
107+
108+
func (t *Transport) readByteSPI(address byte) (byte, error) {
109+
t.debug("read register %x", address)
110+
var (
111+
buf = [...]byte{0x80 | address, 0}
112+
res [2]byte
113+
)
114+
if err := t.cs.Out(gpio.Low); err != nil {
115+
return 0, err
116+
}
117+
if err := t.device.Tx(buf[:], res[:]); err != nil {
118+
return 0, err
119+
}
120+
t.debug("register content %x:%x", res[0], res[1])
121+
if err := t.cs.Out(gpio.High); err != nil {
122+
return 0, err
123+
}
124+
return res[1], nil
125+
}
126+
127+
func (t *Transport) readByteI2C(address byte) (byte, error) {
128+
r := make([]byte, 1)
129+
err := t.d.Tx([]byte{address}, r)
130+
return r[0], err
131+
}
132+
133+
func (t *Transport) readUint16(address ...byte) (uint16, error) {
134+
if len(address) != 2 {
135+
return 0, fmt.Errorf("only 2 bytes per read")
136+
}
137+
h, err := t.readByte(address[0])
138+
if err != nil {
139+
return 0, err
140+
}
141+
l, err := t.readByte(address[1])
142+
if err != nil {
143+
return 0, err
144+
}
145+
return uint16(h)<<8 | uint16(l), nil
146+
}
147+
148+
func noop(string, ...interface{}) {}

0 commit comments

Comments
 (0)