gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/ads1x15_driver.go (about) 1 package i2c 2 3 import ( 4 "log" 5 "math" 6 "sort" 7 "strconv" 8 "time" 9 10 "fmt" 11 ) 12 13 const ads1x15DefaultAddress = 0x48 14 15 const ( 16 ads1x15Debug = false 17 ads1x15WaitMaxCount = 200 18 ads1x15FullScaleValue = 0x7FFF // same as 32768, 1<<15 or 64 19 ) 20 21 const ( 22 // Address pointer registers 23 ads1x15PointerConversion = 0x00 24 ads1x15PointerConfig = 0x01 25 ads1x15PointerLowThreshold = 0x02 26 ads1x15PointerHighThreshold = 0x03 27 28 // Values for config register 29 ads1x15ConfigCompQueDisable = 0x0003 30 ads1x15ConfigCompLatching = 0x0004 31 ads1x15ConfigCompActiveHigh = 0x0008 32 ads1x15ConfigCompWindow = 0x0010 33 34 ads1x15ConfigModeContinuous = 0x0000 35 ads1x15ConfigModeSingle = 0x0100 // single shot mode 36 ads1x15ConfigOsSingle = 0x8000 // write: set to start a single-conversion, read: wait for finished 37 ads1x15ConfigMuxOffset = 12 38 ads1x15ConfigPgaOffset = 9 39 ) 40 41 type ads1x15ChanCfg struct { 42 gain int 43 dataRate int 44 } 45 46 type ads1x15GainCfg struct { 47 bits uint16 48 fullrange float64 49 } 50 51 // ADS1x15Driver is the Gobot driver for the ADS1015/ADS1115 ADC 52 // datasheet: 53 // https://www.ti.com/lit/gpn/ads1115 54 // 55 // reference implementations: 56 // * https://github.com/adafruit/Adafruit_Python_ADS1x15 57 // * https://github.com/Wh1teRabbitHU/ADS1115-Driver 58 type ADS1x15Driver struct { 59 *Driver 60 dataRates map[int]uint16 61 channelCfgs map[int]*ads1x15ChanCfg 62 waitOnlyOneCycle bool 63 } 64 65 var ads1x15FullScaleRange = map[int]float64{ 66 0: 6.144, 67 1: 4.096, 68 2: 2.048, 69 3: 1.024, 70 4: 0.512, 71 5: 0.256, 72 6: 0.256, 73 7: 0.256, 74 } 75 76 // NewADS1015Driver creates a new driver for the ADS1015 (12-bit ADC) 77 func NewADS1015Driver(a Connector, options ...func(Config)) *ADS1x15Driver { 78 dataRates := map[int]uint16{ 79 128: 0x0000, 80 250: 0x0020, 81 490: 0x0040, 82 920: 0x0060, 83 1600: 0x0080, 84 2400: 0x00A0, 85 3300: 0x00C0, 86 } 87 defaultDataRate := 1600 88 89 return newADS1x15Driver(a, "ADS1015", dataRates, defaultDataRate, options...) 90 } 91 92 // NewADS1115Driver creates a new driver for the ADS1115 (16-bit ADC) 93 func NewADS1115Driver(a Connector, options ...func(Config)) *ADS1x15Driver { 94 dataRates := map[int]uint16{ 95 8: 0x0000, 96 16: 0x0020, 97 32: 0x0040, 98 64: 0x0060, 99 128: 0x0080, 100 250: 0x00A0, 101 475: 0x00C0, 102 860: 0x00E0, 103 } 104 defaultDataRate := 128 105 106 return newADS1x15Driver(a, "ADS1115", dataRates, defaultDataRate, options...) 107 } 108 109 func newADS1x15Driver(c Connector, name string, drs map[int]uint16, ddr int, options ...func(Config)) *ADS1x15Driver { 110 ccs := map[int]*ads1x15ChanCfg{0: {1, ddr}, 1: {1, ddr}, 2: {1, ddr}, 3: {1, ddr}} 111 d := &ADS1x15Driver{ 112 Driver: NewDriver(c, name, ads1x15DefaultAddress), 113 dataRates: drs, 114 channelCfgs: ccs, 115 } 116 117 for _, option := range options { 118 option(d) 119 } 120 121 d.AddCommand("ReadDifferenceWithDefaults", func(params map[string]interface{}) interface{} { 122 channel := params["channel"].(int) 123 val, err := d.ReadDifferenceWithDefaults(channel) 124 return map[string]interface{}{"val": val, "err": err} 125 }) 126 127 d.AddCommand("ReadDifference", func(params map[string]interface{}) interface{} { 128 channel := params["channel"].(int) 129 gain := params["gain"].(int) 130 dataRate := params["dataRate"].(int) 131 val, err := d.ReadDifference(channel, gain, dataRate) 132 return map[string]interface{}{"val": val, "err": err} 133 }) 134 135 d.AddCommand("ReadWithDefaults", func(params map[string]interface{}) interface{} { 136 channel := params["channel"].(int) 137 val, err := d.ReadWithDefaults(channel) 138 return map[string]interface{}{"val": val, "err": err} 139 }) 140 141 d.AddCommand("Read", func(params map[string]interface{}) interface{} { 142 channel := params["channel"].(int) 143 gain := params["gain"].(int) 144 dataRate := params["dataRate"].(int) 145 val, err := d.Read(channel, gain, dataRate) 146 return map[string]interface{}{"val": val, "err": err} 147 }) 148 149 d.AddCommand("AnalogRead", func(params map[string]interface{}) interface{} { 150 pin := params["pin"].(string) 151 val, err := d.AnalogRead(pin) 152 return map[string]interface{}{"val": val, "err": err} 153 }) 154 155 return d 156 } 157 158 // WithADS1x15BestGainForVoltage option sets the ADS1x15Driver best gain for all channels. 159 func WithADS1x15BestGainForVoltage(voltage float64) func(Config) { 160 return func(c Config) { 161 d, ok := c.(*ADS1x15Driver) 162 if ok { 163 // validate the given value 164 bestGain, err := ads1x15BestGainForVoltage(voltage) 165 if err != nil { 166 panic(err) 167 } 168 WithADS1x15Gain(bestGain)(d) 169 } else if ads1x15Debug { 170 log.Printf("Trying to set best gain for voltage for non-ADS1x15Driver %v", c) 171 } 172 } 173 } 174 175 // WithADS1x15ChannelBestGainForVoltage option sets the ADS1x15Driver best gain for one channel. 176 func WithADS1x15ChannelBestGainForVoltage(channel int, voltage float64) func(Config) { 177 return func(c Config) { 178 d, ok := c.(*ADS1x15Driver) 179 if ok { 180 // validate the given value 181 bestGain, err := ads1x15BestGainForVoltage(voltage) 182 if err != nil { 183 panic(err) 184 } 185 WithADS1x15ChannelGain(channel, bestGain)(d) 186 } else if ads1x15Debug { 187 log.Printf("Trying to set channel best gain for voltage for non-ADS1x15Driver %v", c) 188 } 189 } 190 } 191 192 // WithADS1x15Gain option sets the ADS1x15Driver gain for all channels. 193 // Valid gain settings are any of the PGA values (0..7). 194 func WithADS1x15Gain(val int) func(Config) { 195 return func(c Config) { 196 d, ok := c.(*ADS1x15Driver) 197 if ok { 198 // validate the given value 199 if _, err := ads1x15GetFullScaleRange(val); err != nil { 200 panic(err) 201 } 202 d.setChannelGains(val) 203 } else if ads1x15Debug { 204 log.Printf("Trying to set gain for non-ADS1x15Driver %v", c) 205 } 206 } 207 } 208 209 // WithADS1x15ChannelGain option sets the ADS1x15Driver gain for one channel. 210 // Valid gain settings are any of the PGA values (0..7). 211 func WithADS1x15ChannelGain(channel int, val int) func(Config) { 212 return func(c Config) { 213 d, ok := c.(*ADS1x15Driver) 214 if ok { 215 // validate the given value 216 if _, err := ads1x15GetFullScaleRange(val); err != nil { 217 panic(err) 218 } 219 if err := d.checkChannel(channel); err != nil { 220 panic(err) 221 } 222 d.channelCfgs[channel].gain = val 223 } else if ads1x15Debug { 224 log.Printf("Trying to set channel gain for non-ADS1x15Driver %v", c) 225 } 226 } 227 } 228 229 // WithADS1x15DataRate option sets the ADS1x15Driver data rate for all channels. 230 // Valid gain settings are any of the DR values in SPS. 231 func WithADS1x15DataRate(val int) func(Config) { 232 return func(c Config) { 233 d, ok := c.(*ADS1x15Driver) 234 if ok { 235 // validate the given value 236 if _, err := ads1x15GetDataRateBits(d.dataRates, val); err != nil { 237 panic(err) 238 } 239 d.setChannelDataRates(val) 240 } else if ads1x15Debug { 241 log.Printf("Trying to set data rate for non-ADS1x15Driver %v", c) 242 } 243 } 244 } 245 246 // WithADS1x15ChannelDataRate option sets the ADS1x15Driver data rate for one channel. 247 // Valid gain settings are any of the DR values in SPS. 248 func WithADS1x15ChannelDataRate(channel int, val int) func(Config) { 249 return func(c Config) { 250 d, ok := c.(*ADS1x15Driver) 251 if ok { 252 // validate the given values 253 if _, err := ads1x15GetDataRateBits(d.dataRates, val); err != nil { 254 panic(err) 255 } 256 if err := d.checkChannel(channel); err != nil { 257 panic(err) 258 } 259 d.channelCfgs[channel].dataRate = val 260 } else if ads1x15Debug { 261 log.Printf("Trying to set channel data rate for non-ADS1x15Driver %v", c) 262 } 263 } 264 } 265 266 // WithADS1x15WaitSingleCycle option sets the ADS1x15Driver to wait only a single cycle for conversion. According to the 267 // specification, chapter "Output Data Rate and Conversion Time", the device normally finishes the conversion within one 268 // cycle (after wake up). The cycle time depends on configured data rate and will be calculated. For unknown reasons 269 // some devices do not work with this setting. So the default behavior for single shot mode is to wait for a conversion 270 // is finished by reading the configuration register bit 15. Activating this option will switch off this behavior and 271 // will possibly create faster response. But, if multiple inputs are used and some inputs calculates the same result, 272 // most likely the device is not working with this option. 273 func WithADS1x15WaitSingleCycle() func(Config) { 274 return func(c Config) { 275 d, ok := c.(*ADS1x15Driver) 276 if ok { 277 d.waitOnlyOneCycle = true 278 } else if ads1x15Debug { 279 log.Printf("Trying to set wait single cycle for non-ADS1x15Driver %v", c) 280 } 281 } 282 } 283 284 // ReadDifferenceWithDefaults reads the difference in V between 2 inputs. It uses the default gain and data rate 285 // diff can be: 286 // * 0: Channel 0 - channel 1 287 // * 1: Channel 0 - channel 3 288 // * 2: Channel 1 - channel 3 289 // * 3: Channel 2 - channel 3 290 func (d *ADS1x15Driver) ReadDifferenceWithDefaults(diff int) (value float64, err error) { 291 d.mutex.Lock() 292 defer d.mutex.Unlock() 293 294 if err = d.checkChannel(diff); err != nil { 295 return 296 } 297 return d.readVoltage(diff, 0, d.channelCfgs[diff].gain, d.channelCfgs[diff].dataRate) 298 } 299 300 // ReadDifference reads the difference in V between 2 inputs. 301 // diff can be: 302 // * 0: Channel 0 - channel 1 303 // * 1: Channel 0 - channel 3 304 // * 2: Channel 1 - channel 3 305 // * 3: Channel 2 - channel 3 306 func (d *ADS1x15Driver) ReadDifference(diff int, gain int, dataRate int) (value float64, err error) { 307 d.mutex.Lock() 308 defer d.mutex.Unlock() 309 310 if err = d.checkChannel(diff); err != nil { 311 return 312 } 313 return d.readVoltage(diff, 0, gain, dataRate) 314 } 315 316 // ReadWithDefaults reads the voltage at the specified channel (between 0 and 3). 317 // Default values are used for the gain and data rate. The result is in V. 318 func (d *ADS1x15Driver) ReadWithDefaults(channel int) (value float64, err error) { 319 d.mutex.Lock() 320 defer d.mutex.Unlock() 321 322 if err = d.checkChannel(channel); err != nil { 323 return 324 } 325 return d.readVoltage(channel, 0x04, d.channelCfgs[channel].gain, d.channelCfgs[channel].dataRate) 326 } 327 328 // Read reads the voltage at the specified channel (between 0 and 3). The result is in V. 329 func (d *ADS1x15Driver) Read(channel int, gain int, dataRate int) (value float64, err error) { 330 d.mutex.Lock() 331 defer d.mutex.Unlock() 332 333 if err = d.checkChannel(channel); err != nil { 334 return 335 } 336 return d.readVoltage(channel, 0x04, gain, dataRate) 337 } 338 339 // AnalogRead returns value from analog reading of specified pin using the default values. 340 func (d *ADS1x15Driver) AnalogRead(pin string) (value int, err error) { 341 d.mutex.Lock() 342 defer d.mutex.Unlock() 343 344 var channel int 345 var channelOffset int 346 347 // Check for the ADC is used in difference mode 348 switch pin { 349 case "0-1": 350 channel = 0 351 case "0-3": 352 channel = 1 353 case "1-3": 354 channel = 2 355 case "2-3": 356 channel = 3 357 default: 358 // read the voltage at a specific pin, compared to the ground 359 channel, err = strconv.Atoi(pin) 360 if err != nil { 361 return 362 } 363 channelOffset = 0x04 364 } 365 366 if err = d.checkChannel(channel); err != nil { 367 return 368 } 369 370 value, err = d.rawRead(channel, channelOffset, d.channelCfgs[channel].gain, d.channelCfgs[channel].dataRate) 371 372 return 373 } 374 375 func (d *ADS1x15Driver) readVoltage(channel int, channelOffset int, gain int, dataRate int) (value float64, err error) { 376 fsr, err := ads1x15GetFullScaleRange(gain) 377 if err != nil { 378 return 379 } 380 381 rawValue, err := d.rawRead(channel, channelOffset, gain, dataRate) 382 383 // Calculate return value in V 384 value = float64(rawValue) / float64(1<<15) * fsr 385 386 return 387 } 388 389 func (d *ADS1x15Driver) rawRead(channel int, channelOffset int, gain int, dataRate int) (data int, err error) { 390 // Validate the passed in data rate (differs between ADS1015 and ADS1115). 391 dataRateBits, err := ads1x15GetDataRateBits(d.dataRates, dataRate) 392 if err != nil { 393 return 394 } 395 396 var config uint16 397 // Go out of power-down mode for conversion. 398 config = ads1x15ConfigOsSingle 399 400 // Specify mux value. 401 mux := channel + channelOffset 402 config |= uint16((mux & 0x07) << ads1x15ConfigMuxOffset) 403 404 // Set the programmable gain amplifier bits. 405 config |= uint16(gain) << ads1x15ConfigPgaOffset 406 407 // Set the mode (continuous or single shot). 408 config |= ads1x15ConfigModeSingle 409 410 // Set the data rate. 411 config |= dataRateBits 412 413 // Disable comparator mode. 414 config |= ads1x15ConfigCompQueDisable 415 416 // Send the config value to start the ADC conversion. 417 if err = d.writeWordBigEndian(ads1x15PointerConfig, config); err != nil { 418 return 419 } 420 421 // Wait for the ADC sample to finish based on the sample rate plus a 422 // small offset to be sure (0.1 millisecond). 423 delay := time.Duration(1000000/dataRate+100) * time.Microsecond 424 if err = d.waitForConversionFinished(delay); err != nil { 425 return 426 } 427 428 // Retrieve the result. 429 udata, err := d.readWordBigEndian(ads1x15PointerConversion) 430 if err != nil { 431 return 432 } 433 434 // Handle negative values as two's complement 435 return int(twosComplement16Bit(udata)), nil 436 } 437 438 func (d *ADS1x15Driver) checkChannel(channel int) (err error) { 439 if channel < 0 || channel > 3 { 440 err = fmt.Errorf("Invalid channel (%d), must be between 0 and 3", channel) 441 } 442 return 443 } 444 445 func (d *ADS1x15Driver) waitForConversionFinished(delay time.Duration) (err error) { 446 start := time.Now() 447 448 for i := 0; i < ads1x15WaitMaxCount; i++ { 449 if i == ads1x15WaitMaxCount-1 { 450 // most likely the last try will also not finish, so we stop with an error 451 return fmt.Errorf("The conversion is not finished within %s", time.Since(start)) 452 } 453 var data uint16 454 if data, err = d.readWordBigEndian(ads1x15PointerConfig); err != nil { 455 return 456 } 457 if ads1x15Debug { 458 log.Printf("ADS1x15Driver: config register state: 0x%X\n", data) 459 } 460 // the highest bit 15: 0-device perform a conversion, 1-no conversion in progress 461 if data&ads1x15ConfigOsSingle > 0 { 462 break 463 } 464 time.Sleep(delay) 465 if d.waitOnlyOneCycle { 466 break 467 } 468 } 469 470 if ads1x15Debug { 471 elapsed := time.Since(start) 472 log.Printf("conversion takes %s", elapsed) 473 } 474 475 return 476 } 477 478 func (d *ADS1x15Driver) writeWordBigEndian(reg uint8, val uint16) error { 479 return d.connection.WriteWordData(reg, swapBytes(val)) 480 } 481 482 func (d *ADS1x15Driver) readWordBigEndian(reg uint8) (data uint16, err error) { 483 if data, err = d.connection.ReadWordData(reg); err != nil { 484 return 485 } 486 return swapBytes(data), err 487 } 488 489 func (d *ADS1x15Driver) setChannelDataRates(ddr int) { 490 for i := 0; i <= 3; i++ { 491 d.channelCfgs[i].dataRate = ddr 492 } 493 } 494 495 func (d *ADS1x15Driver) setChannelGains(gain int) { 496 for i := 0; i <= 3; i++ { 497 d.channelCfgs[i].gain = gain 498 } 499 } 500 501 func ads1x15GetFullScaleRange(gain int) (fsr float64, err error) { 502 fsr, ok := ads1x15FullScaleRange[gain] 503 if ok { 504 return 505 } 506 507 keys := []int{} 508 for k := range ads1x15FullScaleRange { 509 keys = append(keys, k) 510 } 511 sort.Ints(keys) 512 err = fmt.Errorf("Gain (%d) must be one of: %d", gain, keys) 513 return 514 } 515 516 func ads1x15GetDataRateBits(dataRates map[int]uint16, dataRate int) (bits uint16, err error) { 517 bits, ok := dataRates[dataRate] 518 if ok { 519 return 520 } 521 522 keys := []int{} 523 for k := range dataRates { 524 keys = append(keys, k) 525 } 526 sort.Ints(keys) 527 err = fmt.Errorf("Invalid data rate (%d). Accepted values: %d", dataRate, keys) 528 return 529 } 530 531 // ads1x15BestGainForVoltage returns the gain the most adapted to read up to the specified difference of potential. 532 func ads1x15BestGainForVoltage(voltage float64) (bestGain int, err error) { 533 var max float64 534 difference := math.MaxFloat64 535 currentBestGain := -1 536 537 for key, fsr := range ads1x15FullScaleRange { 538 max = math.Max(max, fsr) 539 newDiff := fsr - voltage 540 if newDiff >= 0 && newDiff < difference { 541 difference = newDiff 542 currentBestGain = key 543 } 544 } 545 546 if currentBestGain < 0 { 547 err = fmt.Errorf("The maximum voltage which can be read is %f", max) 548 return 549 } 550 551 bestGain = currentBestGain 552 return 553 }