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  }