gobot.io/x/gobot@v1.16.0/drivers/i2c/ads1x15_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"errors"
     5  	"math"
     6  	"strconv"
     7  	"time"
     8  
     9  	"fmt"
    10  
    11  	"gobot.io/x/gobot"
    12  )
    13  
    14  const (
    15  
    16  	// ADS1x15DefaultAddress is the default I2C address for the ADS1x15 components
    17  	ADS1x15DefaultAddress = 0x48
    18  
    19  	ads1x15PointerConversion    = 0x00
    20  	ads1x15PointerConfig        = 0x01
    21  	ads1x15PointerLowThreshold  = 0x02
    22  	ads1x15PointerHighThreshold = 0x03
    23  	// Write: Set to start a single-conversion
    24  	ads1x15ConfigOsSingle       = 0x8000
    25  	ads1x15ConfigMuxOffset      = 12
    26  	ads1x15ConfigModeContinuous = 0x0000
    27  	//Single shoot mode
    28  	ads1x15ConfigModeSingle = 0x0100
    29  
    30  	ads1x15ConfigCompWindow      = 0x0010
    31  	ads1x15ConfigCompAactiveHigh = 0x0008
    32  	ads1x15ConfigCompLatching    = 0x0004
    33  	ads1x15ConfigCompQueDisable  = 0x0003
    34  )
    35  
    36  // ADS1x15Driver is the Gobot driver for the ADS1015/ADS1115 ADC
    37  type ADS1x15Driver struct {
    38  	name            string
    39  	connector       Connector
    40  	connection      Connection
    41  	gainConfig      map[int]uint16
    42  	dataRates       map[int]uint16
    43  	gainVoltage     map[int]float64
    44  	converter       func([]byte) float64
    45  	DefaultGain     int
    46  	DefaultDataRate int
    47  	Config
    48  }
    49  
    50  // NewADS1015Driver creates a new driver for the ADS1015 (12-bit ADC)
    51  // Largely inspired by: https://github.com/adafruit/Adafruit_Python_ADS1x15
    52  func NewADS1015Driver(a Connector, options ...func(Config)) *ADS1x15Driver {
    53  	l := newADS1x15Driver(a, options...)
    54  
    55  	l.dataRates = map[int]uint16{
    56  		128:  0x0000,
    57  		250:  0x0020,
    58  		490:  0x0040,
    59  		920:  0x0060,
    60  		1600: 0x0080,
    61  		2400: 0x00A0,
    62  		3300: 0x00C0,
    63  	}
    64  	if l.DefaultDataRate == 0 {
    65  		l.DefaultDataRate = 1600
    66  	}
    67  
    68  	l.converter = func(data []byte) (value float64) {
    69  		result := (int(data[0]) << 8) | int(data[1])
    70  
    71  		if result&0x8000 != 0 {
    72  			result -= 1 << 16
    73  		}
    74  
    75  		return float64(result) / float64(1<<15)
    76  	}
    77  
    78  	return l
    79  }
    80  
    81  // NewADS1115Driver creates a new driver for the ADS1115 (16-bit ADC)
    82  func NewADS1115Driver(a Connector, options ...func(Config)) *ADS1x15Driver {
    83  	l := newADS1x15Driver(a, options...)
    84  
    85  	l.dataRates = map[int]uint16{
    86  		8:   0x0000,
    87  		16:  0x0020,
    88  		32:  0x0040,
    89  		64:  0x0060,
    90  		128: 0x0080,
    91  		250: 0x00A0,
    92  		475: 0x00C0,
    93  		860: 0x00E0,
    94  	}
    95  
    96  	if l.DefaultDataRate == 0 {
    97  		l.DefaultDataRate = 128
    98  	}
    99  
   100  	l.converter = func(data []byte) (value float64) {
   101  		result := (int(data[0]) << 8) | int(data[1])
   102  
   103  		if result&0x8000 != 0 {
   104  			result -= 1 << 16
   105  		}
   106  
   107  		return float64(result) / float64(1<<15)
   108  	}
   109  
   110  	return l
   111  }
   112  
   113  func newADS1x15Driver(a Connector, options ...func(Config)) *ADS1x15Driver {
   114  	l := &ADS1x15Driver{
   115  		name:      gobot.DefaultName("ADS1x15"),
   116  		connector: a,
   117  		// Mapping of gain values to config register values.
   118  		gainConfig: map[int]uint16{
   119  			2 / 3: 0x0000,
   120  			1:     0x0200,
   121  			2:     0x0400,
   122  			4:     0x0600,
   123  			8:     0x0800,
   124  			16:    0x0A00,
   125  		},
   126  		gainVoltage: map[int]float64{
   127  			2 / 3: 6.144,
   128  			1:     4.096,
   129  			2:     2.048,
   130  			4:     1.024,
   131  			8:     0.512,
   132  			16:    0.256,
   133  		},
   134  		DefaultGain: 1,
   135  
   136  		Config: NewConfig(),
   137  	}
   138  
   139  	for _, option := range options {
   140  		option(l)
   141  	}
   142  
   143  	// TODO: add commands to API
   144  	return l
   145  }
   146  
   147  // Start initializes the sensor
   148  func (d *ADS1x15Driver) Start() (err error) {
   149  	bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
   150  	address := d.GetAddressOrDefault(ADS1x15DefaultAddress)
   151  
   152  	if d.connection, err = d.connector.GetConnection(address, bus); err != nil {
   153  		return err
   154  	}
   155  
   156  	return
   157  }
   158  
   159  // Name returns the Name for the Driver
   160  func (d *ADS1x15Driver) Name() string { return d.name }
   161  
   162  // SetName sets the Name for the Driver
   163  func (d *ADS1x15Driver) SetName(n string) { d.name = n }
   164  
   165  // Connection returns the connection for the Driver
   166  func (d *ADS1x15Driver) Connection() gobot.Connection { return d.connector.(gobot.Connection) }
   167  
   168  // Halt returns true if devices is halted successfully
   169  func (d *ADS1x15Driver) Halt() (err error) { return }
   170  
   171  // WithADS1x15Gain option sets the ADS1x15Driver gain option.
   172  // Valid gain settings are any of the ADS1x15RegConfigPga* values
   173  func WithADS1x15Gain(val int) func(Config) {
   174  	return func(c Config) {
   175  		d, ok := c.(*ADS1x15Driver)
   176  		if ok {
   177  			d.DefaultGain = val
   178  		} else {
   179  			// TODO: return error for trying to set Gain for non-ADS1015Driver
   180  			return
   181  		}
   182  	}
   183  }
   184  
   185  // WithADS1x15DataRate option sets the ADS1x15Driver data rate option.
   186  // Valid gain settings are any of the ADS1x15RegConfigPga* values
   187  func WithADS1x15DataRate(val int) func(Config) {
   188  	return func(c Config) {
   189  		d, ok := c.(*ADS1x15Driver)
   190  		if ok {
   191  			d.DefaultDataRate = val
   192  		} else {
   193  			// TODO: return error for trying to set data rate for non-ADS1015Driver
   194  			return
   195  		}
   196  	}
   197  }
   198  
   199  // BestGainForVoltage returns the gain the most adapted to read up to the specified difference of potential.
   200  func (d *ADS1x15Driver) BestGainForVoltage(voltage float64) (bestGain int, err error) {
   201  	var max float64
   202  	difference := math.MaxFloat64
   203  	currentBestGain := -1
   204  
   205  	for key, value := range d.gainVoltage {
   206  		max = math.Max(max, value)
   207  		newDiff := value - voltage
   208  		if newDiff >= 0 && newDiff < difference {
   209  			difference = newDiff
   210  			currentBestGain = key
   211  		}
   212  	}
   213  
   214  	if currentBestGain < 0 {
   215  		err = fmt.Errorf("The maximum voltage which can be read is %f", max)
   216  		return
   217  	}
   218  
   219  	bestGain = currentBestGain
   220  	return
   221  }
   222  
   223  // ReadDifferenceWithDefaults reads the difference in V between 2 inputs. It uses the default gain and data rate
   224  // diff can be:
   225  // * 0: Channel 0 - channel 1
   226  // * 1: Channel 0 - channel 3
   227  // * 2: Channel 1 - channel 3
   228  // * 3: Channel 2 - channel 3
   229  func (d *ADS1x15Driver) ReadDifferenceWithDefaults(diff int) (value float64, err error) {
   230  	return d.ReadDifference(diff, d.DefaultGain, d.DefaultDataRate)
   231  }
   232  
   233  // ReadDifference reads the difference in V between 2 inputs.
   234  // diff can be:
   235  // * 0: Channel 0 - channel 1
   236  // * 1: Channel 0 - channel 3
   237  // * 2: Channel 1 - channel 3
   238  // * 3: Channel 2 - channel 3
   239  func (d *ADS1x15Driver) ReadDifference(diff int, gain int, dataRate int) (value float64, err error) {
   240  	if err = d.checkChannel(diff); err != nil {
   241  		return
   242  	}
   243  
   244  	return d.rawRead(diff, gain, dataRate)
   245  }
   246  
   247  // ReadWithDefaults reads the voltage at the specified channel (between 0 and 3).
   248  // Default values are used for the gain and data rate. The result is in V.
   249  func (d *ADS1x15Driver) ReadWithDefaults(channel int) (value float64, err error) {
   250  	return d.Read(channel, d.DefaultGain, d.DefaultDataRate)
   251  }
   252  
   253  // Read reads the voltage at the specified channel (between 0 and 3). The result is in V.
   254  func (d *ADS1x15Driver) Read(channel int, gain int, dataRate int) (value float64, err error) {
   255  	if err = d.checkChannel(channel); err != nil {
   256  		return
   257  	}
   258  	mux := channel + 0x04
   259  
   260  	return d.rawRead(mux, gain, dataRate)
   261  }
   262  
   263  // AnalogRead returns value from analog reading of specified pin
   264  func (d *ADS1x15Driver) AnalogRead(pin string) (value int, err error) {
   265  	var useDifference = false
   266  	var channel int
   267  	var read float64
   268  
   269  	// First case: the ADC is used in difference mode
   270  	switch pin {
   271  	case "0-1":
   272  		useDifference = true
   273  		channel = 0
   274  		break
   275  	case "0-3":
   276  		useDifference = true
   277  		channel = 1
   278  		break
   279  	case "1-3":
   280  		useDifference = true
   281  		channel = 2
   282  		break
   283  	case "2-3":
   284  		useDifference = true
   285  		channel = 3
   286  		break
   287  	}
   288  
   289  	if useDifference {
   290  		read, err = d.ReadDifferenceWithDefaults(channel)
   291  	} else {
   292  		// Second case: read the voltage at a specific pin, compared to the ground
   293  		channel, err = strconv.Atoi(pin)
   294  		if err != nil {
   295  			return
   296  		}
   297  
   298  		read, err = d.ReadWithDefaults(channel)
   299  	}
   300  
   301  	if err == nil {
   302  		value = int(gobot.ToScale(gobot.FromScale(read, 0, d.gainVoltage[d.DefaultGain]), 0, 1023))
   303  	}
   304  
   305  	return
   306  }
   307  
   308  func (d *ADS1x15Driver) rawRead(mux int, gain int, dataRate int) (value float64, err error) {
   309  	var config uint16
   310  	config = ads1x15ConfigOsSingle // Go out of power-down mode for conversion.
   311  	// Specify mux value.
   312  	config |= uint16((mux & 0x07) << ads1x15ConfigMuxOffset)
   313  	// Validate the passed in gain and then set it in the config.
   314  
   315  	gainConf, ok := d.gainConfig[gain]
   316  
   317  	if !ok {
   318  		err = errors.New("Gain must be one of: 2/3, 1, 2, 4, 8, 16")
   319  		return
   320  	}
   321  	config |= gainConf
   322  	// Set the mode (continuous or single shot).
   323  	config |= ads1x15ConfigModeSingle
   324  	// Get the default data rate if none is specified (default differs between
   325  	// ADS1015 and ADS1115).
   326  	dataRateConf, ok := d.dataRates[dataRate]
   327  
   328  	if !ok {
   329  		keys := []int{}
   330  		for k := range d.dataRates {
   331  			keys = append(keys, k)
   332  		}
   333  
   334  		err = fmt.Errorf("Invalid data rate. Accepted values: %d", keys)
   335  		return
   336  	}
   337  	// Set the data rate (this is controlled by the subclass as it differs
   338  	// between ADS1015 and ADS1115).
   339  	config |= dataRateConf
   340  	config |= ads1x15ConfigCompQueDisable // Disable comparator mode.
   341  
   342  	// Send the config value to start the ADC conversion.
   343  	// Explicitly break the 16-bit value down to a big endian pair of bytes.
   344  	if _, err = d.connection.Write([]byte{ads1x15PointerConfig, byte((config >> 8) & 0xFF), byte(config & 0xFF)}); err != nil {
   345  		return
   346  	}
   347  
   348  	// Wait for the ADC sample to finish based on the sample rate plus a
   349  	// small offset to be sure (0.1 millisecond).
   350  	time.Sleep(time.Duration(1000000/dataRate+100) * time.Microsecond)
   351  
   352  	// Retrieve the result.
   353  	if _, err = d.connection.Write([]byte{ads1x15PointerConversion}); err != nil {
   354  		return
   355  	}
   356  
   357  	data := make([]byte, 2)
   358  	_, err = d.connection.Read(data)
   359  	if err != nil {
   360  		return
   361  	}
   362  
   363  	voltageMultiplier, ok := d.gainVoltage[gain]
   364  
   365  	if !ok {
   366  		err = errors.New("Gain must be one of: 2/3, 1, 2, 4, 8, 16")
   367  		return
   368  	}
   369  
   370  	value = d.converter(data) * voltageMultiplier
   371  
   372  	return
   373  }
   374  
   375  func (d *ADS1x15Driver) checkChannel(channel int) (err error) {
   376  	if channel < 0 || channel > 3 {
   377  		err = errors.New("Invalid channel, must be between 0 and 3")
   378  	}
   379  	return
   380  }