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 }