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

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