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

     1  // Package lsm6dsox implements a driver for the LSM6DSOX
     2  // a 6 axis Inertial Measurement Unit (IMU)
     3  //
     4  // Datasheet: https://www.st.com/resource/en/datasheet/lsm6dsox.pdf
     5  package lsm6dsox // import "tinygo.org/x/drivers/lsm6dsox"
     6  
     7  import (
     8  	"errors"
     9  
    10  	"tinygo.org/x/drivers"
    11  	"tinygo.org/x/drivers/internal/legacy"
    12  )
    13  
    14  type AccelRange uint8
    15  type AccelSampleRate uint8
    16  
    17  type GyroRange uint8
    18  type GyroSampleRate uint8
    19  
    20  // Device wraps an I2C connection to a LSM6DSOX device.
    21  type Device struct {
    22  	bus             drivers.I2C
    23  	Address         uint16
    24  	accelMultiplier int32
    25  	gyroMultiplier  int32
    26  	buf             [6]uint8
    27  }
    28  
    29  // Configuration for LSM6DSOX device.
    30  type Configuration struct {
    31  	AccelRange      AccelRange
    32  	AccelSampleRate AccelSampleRate
    33  	GyroRange       GyroRange
    34  	GyroSampleRate  GyroSampleRate
    35  }
    36  
    37  var errNotConnected = errors.New("lsm6dsox: failed to communicate with acel/gyro sensor")
    38  
    39  // New creates a new LSM6DSOX connection. The I2C bus must already be configured.
    40  //
    41  // This function only creates the Device object, it does not touch the device.
    42  func New(bus drivers.I2C) *Device {
    43  	return &Device{
    44  		bus:     bus,
    45  		Address: Address,
    46  	}
    47  }
    48  
    49  // Configure sets up the device for communication.
    50  func (d *Device) Configure(cfg Configuration) (err error) {
    51  
    52  	// Verify unit communication
    53  	if !d.Connected() {
    54  		return errNotConnected
    55  	}
    56  
    57  	// Multipliers come from "Table 2. Mechanical characteristics" of the datasheet * 1000
    58  	switch cfg.AccelRange {
    59  	case ACCEL_2G:
    60  		d.accelMultiplier = 61
    61  	case ACCEL_4G:
    62  		d.accelMultiplier = 122
    63  	case ACCEL_8G:
    64  		d.accelMultiplier = 244
    65  	case ACCEL_16G:
    66  		d.accelMultiplier = 488
    67  	}
    68  	switch cfg.GyroRange {
    69  	case GYRO_250DPS:
    70  		d.gyroMultiplier = 8750
    71  	case GYRO_500DPS:
    72  		d.gyroMultiplier = 17500
    73  	case GYRO_1000DPS:
    74  		d.gyroMultiplier = 35000
    75  	case GYRO_2000DPS:
    76  		d.gyroMultiplier = 70000
    77  	}
    78  
    79  	data := d.buf[:1]
    80  	// Configure accelerometer
    81  	data[0] = uint8(cfg.AccelRange) | uint8(cfg.AccelSampleRate)
    82  	err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
    83  	if err != nil {
    84  		return
    85  	}
    86  	// Configure gyroscope
    87  	data[0] = uint8(cfg.GyroRange) | uint8(cfg.GyroSampleRate)
    88  	err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
    89  	if err != nil {
    90  		return
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  // Connected returns whether a LSM6DSOX has been found.
    97  // It does a "who am I" request and checks the response.
    98  func (d *Device) Connected() bool {
    99  	data := d.buf[:1]
   100  	legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
   101  	return data[0] == 0x6C
   102  }
   103  
   104  // ReadAcceleration reads the current acceleration from the device and returns
   105  // it in µg (micro-gravity). When one of the axes is pointing straight to Earth
   106  // and the sensor is not moving the returned value will be around 1000000 or
   107  // -1000000.
   108  func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
   109  	data := d.buf[:6]
   110  	err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_A, data)
   111  	if err != nil {
   112  		return
   113  	}
   114  	x = int32(int16((uint16(data[1])<<8)|uint16(data[0]))) * d.accelMultiplier
   115  	y = int32(int16((uint16(data[3])<<8)|uint16(data[2]))) * d.accelMultiplier
   116  	z = int32(int16((uint16(data[5])<<8)|uint16(data[4]))) * d.accelMultiplier
   117  	return
   118  }
   119  
   120  // ReadRotation reads the current rotation from the device and returns it in
   121  // µ°/s (micro-degrees/sec). This means that if you were to do a complete
   122  // rotation along one axis and while doing so integrate all values over time,
   123  // you would get a value close to 360000000.
   124  func (d *Device) ReadRotation() (x, y, z int32, err error) {
   125  	data := d.buf[:6]
   126  	err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
   127  	if err != nil {
   128  		return
   129  	}
   130  	x = int32(int16((uint16(data[1])<<8)|uint16(data[0]))) * d.gyroMultiplier
   131  	y = int32(int16((uint16(data[3])<<8)|uint16(data[2]))) * d.gyroMultiplier
   132  	z = int32(int16((uint16(data[5])<<8)|uint16(data[4]))) * d.gyroMultiplier
   133  	return
   134  }
   135  
   136  // ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
   137  func (d *Device) ReadTemperature() (t int32, err error) {
   138  	data := d.buf[:2]
   139  	err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
   140  	if err != nil {
   141  		return
   142  	}
   143  	// From "Table 4. Temperature sensor characteristics"
   144  	// temp = value/256 + 25
   145  	t = 25000 + (int32(int16((int16(data[1])<<8)|int16(data[0])))*125)/32
   146  	return
   147  }