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 }