@ -17,16 +17,73 @@ import (
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin"
)
)
const (
// I2CAddr is the default I2C address for the ADS1x15 components.
// I2CAddr is the default I2C address for the ADS1x15 components.
I2CAddr uint16 = 0x48
const I2CAddr uint16 = 0x48
// Channel is the analog reading to do. It can be either an absolute reading or
// a differential reading between two pins.
type Channel int
Channel0 = 0
const (
Channel1 = 1
// Absolute reading.
Channel2 = 2
Channel0 Channel = 4
Channel3 = 3
Channel1 Channel = 5
Channel2 Channel = 6
Channel3 Channel = 7
// Differential reading.
Channel0Minus1 Channel = 0
Channel0Minus3 Channel = 1
Channel1Minus3 Channel = 2
Channel2Minus3 Channel = 3
)
)
func ( c Channel ) String ( ) string {
switch c {
case Channel0 :
return "0"
case Channel1 :
return "1"
case Channel2 :
return "2"
case Channel3 :
return "3"
case Channel0Minus1 :
return "0-1"
case Channel0Minus3 :
return "0-3"
case Channel1Minus3 :
return "1-3"
case Channel2Minus3 :
return "2-3"
default :
return "Invalid"
}
}
func ( c Channel ) number ( ) int {
switch c {
case Channel0 :
return 0
case Channel1 :
return 1
case Channel2 :
return 2
case Channel3 :
return 3
case Channel0Minus1 :
return 4
case Channel0Minus3 :
return 5
case Channel1Minus3 :
return 6
case Channel2Minus3 :
return 7
default :
return - 1
}
}
// ConversionQuality represents a request for a compromise between energy
// ConversionQuality represents a request for a compromise between energy
// saving versus conversion quality.
// saving versus conversion quality.
type ConversionQuality int
type ConversionQuality int
@ -58,13 +115,13 @@ type Dev struct {
mu sync . Mutex
mu sync . Mutex
}
}
// Reading is the result of AnalogPin.Read() (obviously not the case right now but this could be)
// Reading is the result of AnalogPin.Read()
type Reading struct {
type Reading struct {
V physic . ElectricPotential
V physic . ElectricPotential
Raw int32
Raw int32
}
}
// AnalogPin represents a pin which is able to read an electric potential
// AnalogPin represents a pin which is able to read an electric potential .
type AnalogPin interface {
type AnalogPin interface {
pin . Pin
pin . Pin
// Range returns the maximum supported range [min, max] of the values.
// Range returns the maximum supported range [min, max] of the values.
@ -120,47 +177,11 @@ func (d *Dev) Halt() error {
return nil
return nil
}
}
// PinForChannel returns a pin able to measure the electric potential at the
// PinForChannel returns an AnalogPin for the requested channel at the
// given channel.
// requested frequency.
func ( d * Dev ) PinForChannel ( channel int , maxVoltage physic . ElectricPotential , requestedFrequency physic . Frequency , conversionQuality ConversionQuality ) ( AnalogPin , error ) {
//
if err := d . checkChannel ( channel ) ; err != nil {
// The channel can either be an absolute reading or a differential one.
return nil , err
func ( d * Dev ) PinForChannel ( c Channel , maxVoltage physic . ElectricPotential , f physic . Frequency , q ConversionQuality ) ( AnalogPin , error ) {
}
return d . prepareQuery ( channel + 0x04 , maxVoltage , requestedFrequency , conversionQuality )
}
// PinForDifferenceOfChannels returns a pin which measures the difference in
// volts between 2 inputs: channelA - channelB.
// diff can be:
// * Channel 0 - channel 1
// * Channel 0 - channel 3
// * Channel 1 - channel 3
// * Channel 2 - channel 3
func ( d * Dev ) PinForDifferenceOfChannels ( channelA int , channelB int , maxVoltage physic . ElectricPotential , requestedFrequency physic . Frequency , conversionQuality ConversionQuality ) ( AnalogPin , error ) {
var mux int
if err := d . checkChannel ( channelA ) ; err != nil {
return nil , err
}
if err := d . checkChannel ( channelB ) ; err != nil {
return nil , err
}
if channelA == Channel0 && channelB == Channel1 {
mux = 0
} else if channelA == Channel0 && channelB == Channel3 {
mux = 1
} else if channelA == Channel1 && channelB == Channel3 {
mux = 2
} else if channelA == Channel2 && channelB == Channel3 {
mux = 3
} else {
return nil , errors . New ( "only some differences of channels are allowed: 0 - 1, 0 - 3, 1 - 3 or 2 - 3" )
}
return d . prepareQuery ( mux , maxVoltage , requestedFrequency , conversionQuality )
}
func ( d * Dev ) prepareQuery ( mux int , maxVoltage physic . ElectricPotential , requestedFrequency physic . Frequency , conversionQuality ConversionQuality ) ( AnalogPin , error ) {
// Determine the most appropriate gain
// Determine the most appropriate gain
gain , err := d . bestGainForElectricPotential ( maxVoltage )
gain , err := d . bestGainForElectricPotential ( maxVoltage )
if err != nil {
if err != nil {
@ -179,16 +200,15 @@ func (d *Dev) prepareQuery(mux int, maxVoltage physic.ElectricPotential, request
return nil , errors . New ( "gain must be one of: 2/3, 1, 2, 4, 8, 16" )
return nil , errors . New ( "gain must be one of: 2/3, 1, 2, 4, 8, 16" )
}
}
// Determine the most appropriate data rate
// Determine the most appropriate data rate .
dataRate , err := d . bestDataRateForFrequency ( requestedFrequency, conversionQuality )
dataRate , err := d . bestDataRateForFrequency ( f, q )
if err != nil {
if err != nil {
return nil , err
return nil , err
}
}
dataRateConf , ok := d . dataRates [ dataRate ]
dataRateConf , ok := d . dataRates [ dataRate ]
if ! ok {
if ! ok {
// Write a nice error message in case the data rate is not found
// Write a nice error message in case the data rate is not found .
keys := [ ] int { }
keys := [ ] int { }
for k := range d . dataRates {
for k := range d . dataRates {
keys = append ( keys , k )
keys = append ( keys , k )
@ -200,7 +220,7 @@ func (d *Dev) prepareQuery(mux int, maxVoltage physic.ElectricPotential, request
var config uint16
var config uint16
config = ads1x15ConfigOsSingle // Go out of power-down mode for conversion.
config = ads1x15ConfigOsSingle // Go out of power-down mode for conversion.
// Specify mux value.
// Specify mux value.
config |= uint16 ( ( mux & 0x07 ) << ads1x15ConfigMuxOffset )
config |= uint16 ( c ) << ads1x15ConfigMuxOffset
// Validate the passed in gain and then set it in the config.
// Validate the passed in gain and then set it in the config.
config |= gainConf
config |= gainConf
// Set the mode (continuous or single shot).
// Set the mode (continuous or single shot).
@ -211,21 +231,21 @@ func (d *Dev) prepareQuery(mux int, maxVoltage physic.ElectricPotential, request
config |= dataRateConf
config |= dataRateConf
config |= ads1x15ConfigCompQueDisable // Disable comparator mode.
config |= ads1x15ConfigCompQueDisable // Disable comparator mode.
// Build the query to the ADC
// Build the query to the ADC.
configBytes := make ( [ ] byte , 2 )
configBytes := [ 2 ] byte { }
binary . BigEndian . PutUint16 ( configBytes , config )
binary . BigEndian . PutUint16 ( configBytes [ : ] , config )
query := append ( [ ] byte { ads1x15PointerConfig } , configBytes ... )
// The wait for the ADC sample to finish is based on the sample rate plus a
// The wait for the ADC sample to finish is based on the sample rate plus a
// small offset to be sure (0.1 millisecond).
// small offset to be sure (0.1 millisecond).
waitTime := time . Second / time . Duration ( dataRate ) + 100 * time . Microsecond
waitTime := time . Second / time . Duration ( dataRate ) + 100 * time . Microsecond
return & a ds1x15A nalogPin{
return & a nalogPin{
adc : d ,
adc : d ,
query : query ,
c : c ,
query : [ ... ] byte { ads1x15PointerConfig , configBytes [ 0 ] , configBytes [ 1 ] } ,
voltageMultiplier : voltageMultiplier ,
voltageMultiplier : voltageMultiplier ,
waitTime : waitTime ,
waitTime : waitTime ,
requestedFrequency : requestedFrequency ,
requestedFrequency : f ,
} , nil
} , nil
}
}
@ -277,14 +297,14 @@ func (d *Dev) bestGainForElectricPotential(voltage physic.ElectricPotential) (in
}
}
if currentBestGain < 0 {
if currentBestGain < 0 {
return 0 , fmt. Errorf ( "maximum voltage which can be read is %s" , max . String ( ) )
return 0 , errors. New ( "maximum voltage which can be read is " + max . String ( ) )
}
}
return currentBestGain , nil
return currentBestGain , nil
}
}
// bestDataRateForFrequency returns the gain the most data rate to read samples
// bestDataRateForFrequency returns the gain the most data rate to read samples
// at least at the requested frequency.
// at least at the requested frequency.
func ( d * Dev ) bestDataRateForFrequency ( requestedFrequency physic . Frequency , conversionQuality ConversionQuality ) ( int , error ) {
func ( d * Dev ) bestDataRateForFrequency ( f physic . Frequency , q ConversionQuality ) ( int , error ) {
var max physic . Frequency
var max physic . Frequency
currentBestDataRate := - 1
currentBestDataRate := - 1
@ -296,7 +316,7 @@ func (d *Dev) bestDataRateForFrequency(requestedFrequency physic.Frequency, conv
var comparator func ( physic . Frequency , physic . Frequency ) bool
var comparator func ( physic . Frequency , physic . Frequency ) bool
var difference physic . Frequency
var difference physic . Frequency
switch conversionQuality {
switch q {
case SaveEnergy :
case SaveEnergy :
// Saving energy requires the maximum data rate
// Saving energy requires the maximum data rate
difference = physic . Frequency ( - 1 )
difference = physic . Frequency ( - 1 )
@ -306,7 +326,7 @@ func (d *Dev) bestDataRateForFrequency(requestedFrequency physic.Frequency, conv
difference = physic . Frequency ( math . MaxInt64 )
difference = physic . Frequency ( math . MaxInt64 )
comparator = func ( newDiff physic . Frequency , difference physic . Frequency ) bool { return newDiff < difference }
comparator = func ( newDiff physic . Frequency , difference physic . Frequency ) bool { return newDiff < difference }
default :
default :
return 0 , fmt. Errorf ( "unknown value for ConversionQuality" )
return 0 , errors. New ( "unknown value for ConversionQuality" )
}
}
for key := range d . dataRates {
for key := range d . dataRates {
@ -317,7 +337,7 @@ func (d *Dev) bestDataRateForFrequency(requestedFrequency physic.Frequency, conv
max = freq
max = freq
}
}
newDiff := freq - requestedFrequency
newDiff := freq - f
// Conversion rate slower than the requested frequency is not suitable
// Conversion rate slower than the requested frequency is not suitable
if newDiff < 0 {
if newDiff < 0 {
continue
continue
@ -330,19 +350,11 @@ func (d *Dev) bestDataRateForFrequency(requestedFrequency physic.Frequency, conv
}
}
if currentBestDataRate < 0 {
if currentBestDataRate < 0 {
return 0 , fmt. Errorf ( "maximum frequency which can be read is %s" , max . String ( ) )
return 0 , errors. New ( "maximum frequency which can be read is " + max . String ( ) )
}
}
return currentBestDataRate , nil
return currentBestDataRate , nil
}
}
func ( d * Dev ) checkChannel ( channel int ) error {
if channel < 0 || channel > 3 {
return errors . New ( "invalid channel, must be between 0 and 3" )
}
return nil
}
//
//
const (
const (
@ -383,9 +395,10 @@ var (
}
}
)
)
type a ds1x15A nalogPin struct {
type a nalogPin struct {
adc * Dev
adc * Dev
query [ ] byte
c Channel
query [ 3 ] byte
voltageMultiplier physic . ElectricPotential
voltageMultiplier physic . ElectricPotential
waitTime time . Duration
waitTime time . Duration
requestedFrequency physic . Frequency
requestedFrequency physic . Frequency
@ -393,26 +406,26 @@ type ads1x15AnalogPin struct {
}
}
// Range returns the maximum supported range [min, max] of the values.
// Range returns the maximum supported range [min, max] of the values.
func ( p * a ds1x15A nalogPin) Range ( ) ( Reading , Reading ) {
func ( p * a nalogPin) Range ( ) ( Reading , Reading ) {
max := Reading { Raw : math . MaxInt16 , V : p . voltageMultiplier }
max := Reading { Raw : math . MaxInt16 , V : p . voltageMultiplier }
min := Reading { Raw : - math . MaxInt16 , V : - p . voltageMultiplier }
min := Reading { Raw : - math . MaxInt16 , V : - p . voltageMultiplier }
return min , max
return min , max
}
}
// Read returns the current pin level.
// Read returns the current pin level.
func ( p * a ds1x15A nalogPin) Read ( ) ( Reading , error ) {
func ( p * a nalogPin) Read ( ) ( Reading , error ) {
return p . adc . executePreparedQuery ( p . query , p . waitTime , p . voltageMultiplier )
return p . adc . executePreparedQuery ( p . query [: ] , p . waitTime , p . voltageMultiplier )
}
}
func ( p * a ds1x15A nalogPin) ReadContinuous ( ) <- chan Reading {
func ( p * a nalogPin) ReadContinuous ( ) <- chan Reading {
p . stopContinous ( )
p . Halt ( )
reading := make ( chan Reading )
reading := make ( chan Reading )
p . stop = make ( chan struct { } )
p . stop = make ( chan struct { } )
go func ( ) {
go func ( ) {
t := time . NewTicker ( p . requestedFrequency . Duration ( ) )
t := time . NewTicker ( p . requestedFrequency . Duration ( ) )
defer t . Stop ( )
defer t . Stop ( )
defer p . stopContinous ( )
defer p . Halt ( )
defer close ( reading )
defer close ( reading )
for {
for {
@ -433,30 +446,26 @@ func (p *ads1x15AnalogPin) ReadContinuous() <-chan Reading {
return reading
return reading
}
}
func ( p * ads1x15AnalogPin ) Name ( ) string {
func ( p * analogPin ) Name ( ) string {
return fmt . Sprintf ( "%s pin" , p . adc . name )
return p . adc . name + "(" + p . c . String ( ) + ")"
}
func ( p * ads1x15AnalogPin ) Number ( ) int {
return - 1
}
}
func ( p * ads1x15AnalogPin ) Function ( ) string {
func ( p * analogPin ) Number ( ) int {
return "DEPRECATED"
return p . c . number ( )
}
func ( p * ads1x15AnalogPin ) Halt ( ) error {
p . stopContinous ( )
return nil
}
}
func ( p * a ds1x15AnalogPin) String ( ) string {
func ( p * analogPin ) Function ( ) string {
return p . Name ( )
return "ADC"
}
}
func ( p * a ds1x15AnalogPin) stopContinous ( ) {
func ( p * a nalogPin) Halt ( ) error {
if p . stop != nil {
if p . stop != nil {
close ( p . stop )
close ( p . stop )
p . stop = nil
p . stop = nil
}
}
return nil
}
func ( p * analogPin ) String ( ) string {
return p . Name ( )
}
}