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

     1  // Package lsm6ds3tr implements a driver for the LSM6DS3TR
     2  // a 6 axis Inertial Measurement Unit (IMU)
     3  //
     4  // Datasheet: https://www.st.com/resource/en/datasheet/lsm6ds3tr.pdf
     5  package lsm6ds3tr // import "tinygo.org/x/drivers/lsm6ds3tr"
     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  type AccelBandwidth uint8
    17  
    18  type GyroRange uint8
    19  type GyroSampleRate uint8
    20  
    21  // Device wraps an I2C connection to a LSM6DS3TR device.
    22  type Device struct {
    23  	bus             drivers.I2C
    24  	Address         uint16
    25  	accelRange      AccelRange
    26  	accelSampleRate AccelSampleRate
    27  	gyroRange       GyroRange
    28  	gyroSampleRate  GyroSampleRate
    29  	buf             [6]uint8
    30  }
    31  
    32  // Configuration for LSM6DS3TR device.
    33  type Configuration struct {
    34  	AccelRange       AccelRange
    35  	AccelSampleRate  AccelSampleRate
    36  	AccelBandWidth   AccelBandwidth
    37  	GyroRange        GyroRange
    38  	GyroSampleRate   GyroSampleRate
    39  	IsPedometer      bool
    40  	ResetStepCounter bool
    41  }
    42  
    43  var errNotConnected = errors.New("lsm6ds3tr: failed to communicate with acel/gyro sensor")
    44  
    45  // New creates a new LSM6DS3TR connection. The I2C bus must already be configured.
    46  //
    47  // This function only creates the Device object, it does not touch the device.
    48  func New(bus drivers.I2C) *Device {
    49  	return &Device{
    50  		bus:     bus,
    51  		Address: Address,
    52  	}
    53  }
    54  
    55  // Configure sets up the device for communication.
    56  func (d *Device) doConfigure(cfg Configuration) (err error) {
    57  
    58  	// Verify unit communication
    59  	if !d.Connected() {
    60  		return errNotConnected
    61  	}
    62  
    63  	if cfg.AccelRange != 0 {
    64  		d.accelRange = cfg.AccelRange
    65  	} else {
    66  		d.accelRange = ACCEL_2G
    67  	}
    68  
    69  	if cfg.AccelSampleRate != 0 {
    70  		d.accelSampleRate = cfg.AccelSampleRate
    71  	} else {
    72  		d.accelSampleRate = ACCEL_SR_104
    73  	}
    74  
    75  	if cfg.GyroRange != 0 {
    76  		d.gyroRange = cfg.GyroRange
    77  	} else {
    78  		d.gyroRange = GYRO_2000DPS
    79  	}
    80  
    81  	if cfg.GyroSampleRate != 0 {
    82  		d.gyroSampleRate = cfg.GyroSampleRate
    83  	} else {
    84  		d.gyroSampleRate = GYRO_SR_104
    85  	}
    86  
    87  	data := d.buf[:1]
    88  
    89  	// Configure accelerometer
    90  	data[0] = uint8(d.accelRange) | uint8(d.accelSampleRate)
    91  	err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL1_XL, data)
    92  	if err != nil {
    93  		return
    94  	}
    95  
    96  	// Set ODR bit
    97  	err = legacy.ReadRegister(d.bus, uint8(d.Address), CTRL4_C, data)
    98  	if err != nil {
    99  		return
   100  	}
   101  	data[0] = data[0] &^ BW_SCAL_ODR_ENABLED
   102  	data[0] |= BW_SCAL_ODR_ENABLED
   103  	err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL4_C, data)
   104  	if err != nil {
   105  		return
   106  	}
   107  
   108  	// Configure gyroscope
   109  	data[0] = uint8(d.gyroRange) | uint8(d.gyroSampleRate)
   110  	err = legacy.WriteRegister(d.bus, uint8(d.Address), CTRL2_G, data)
   111  	if err != nil {
   112  		return
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  // Connected returns whether a LSM6DS3TR has been found.
   119  // It does a "who am I" request and checks the response.
   120  func (d *Device) Connected() bool {
   121  	data := d.buf[:1]
   122  	legacy.ReadRegister(d.bus, uint8(d.Address), WHO_AM_I, data)
   123  	return data[0] == 0x6A
   124  }
   125  
   126  // ReadAcceleration reads the current acceleration from the device and returns
   127  // it in µg (micro-gravity). When one of the axes is pointing straight to Earth
   128  // and the sensor is not moving the returned value will be around 1000000 or
   129  // -1000000.
   130  func (d *Device) ReadAcceleration() (x, y, z int32, err error) {
   131  	data := d.buf[:6]
   132  	err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_XL, data)
   133  	if err != nil {
   134  		return
   135  	}
   136  	// k comes from "Table 3. Mechanical characteristics" 3 of the datasheet * 1000
   137  	k := int32(61) // 2G
   138  	if d.accelRange == ACCEL_4G {
   139  		k = 122
   140  	} else if d.accelRange == ACCEL_8G {
   141  		k = 244
   142  	} else if d.accelRange == ACCEL_16G {
   143  		k = 488
   144  	}
   145  	x = int32(int16((uint16(data[1])<<8)|uint16(data[0]))) * k
   146  	y = int32(int16((uint16(data[3])<<8)|uint16(data[2]))) * k
   147  	z = int32(int16((uint16(data[5])<<8)|uint16(data[4]))) * k
   148  	return
   149  }
   150  
   151  // ReadRotation reads the current rotation from the device and returns it in
   152  // µ°/s (micro-degrees/sec). This means that if you were to do a complete
   153  // rotation along one axis and while doing so integrate all values over time,
   154  // you would get a value close to 360000000.
   155  func (d *Device) ReadRotation() (x, y, z int32, err error) {
   156  	data := d.buf[:6]
   157  	err = legacy.ReadRegister(d.bus, uint8(d.Address), OUTX_L_G, data)
   158  	if err != nil {
   159  		return
   160  	}
   161  	// k comes from "Table 3. Mechanical characteristics" 3 of the datasheet * 1000
   162  	k := int32(4375) // 125DPS
   163  	if d.gyroRange == GYRO_245DPS {
   164  		k = 8750
   165  	} else if d.gyroRange == GYRO_500DPS {
   166  		k = 17500
   167  	} else if d.gyroRange == GYRO_1000DPS {
   168  		k = 35000
   169  	} else if d.gyroRange == GYRO_2000DPS {
   170  		k = 70000
   171  	}
   172  	x = int32(int16((uint16(data[1])<<8)|uint16(data[0]))) * k
   173  	y = int32(int16((uint16(data[3])<<8)|uint16(data[2]))) * k
   174  	z = int32(int16((uint16(data[5])<<8)|uint16(data[4]))) * k
   175  	return
   176  }
   177  
   178  // ReadTemperature returns the temperature in celsius milli degrees (°C/1000)
   179  func (d *Device) ReadTemperature() (t int32, err error) {
   180  	data := d.buf[:2]
   181  	err = legacy.ReadRegister(d.bus, uint8(d.Address), OUT_TEMP_L, data)
   182  	if err != nil {
   183  		return
   184  	}
   185  	// From "Table 5. Temperature sensor characteristics"
   186  	// temp = value/256 + 25
   187  	t = 25000 + (int32(int16((int16(data[1])<<8)|int16(data[0])))*125)/32
   188  	return
   189  }