tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/mpu9150/mpu9150.go (about)

     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  }