gobot.io/x/gobot/v2@v2.1.0/drivers/i2c/adxl345_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"encoding/binary"
     5  	"log"
     6  
     7  	"github.com/pkg/errors"
     8  )
     9  
    10  const adxl345Debug = false
    11  
    12  // ADXL345 supports 2 addresses, which can be changed by the address pin, there is no internal pull-up/down resistor!
    13  // pin to GND: 0x53, pin to VDD: 0x1D
    14  const (
    15  	ADXL345AddressPullUp  = 0x1D // can be used by WithAddress()
    16  	adxl345DefaultAddress = 0x53
    17  )
    18  
    19  type ADXL345RateConfig uint8
    20  type ADXL345FsRangeConfig uint8
    21  
    22  const (
    23  	// registers are named according to the datasheet
    24  	adxl345Reg_DEVID          = 0x00 // R,     11100101,   Device ID
    25  	adxl345Reg_THRESH_TAP     = 0x1D // R/W,   00000000,   Tap threshold
    26  	adxl345Reg_OFSX           = 0x1E // R/W,   00000000,   X-axis offset
    27  	adxl345Reg_OFSY           = 0x1F // R/W,   00000000,   Y-axis offset
    28  	adxl345Reg_OFSZ           = 0x20 // R/W,   00000000,   Z-axis offset
    29  	adxl345Reg_DUR            = 0x21 // R/W,   00000000,   Tap duration
    30  	adxl345Reg_LATENT         = 0x22 // R/W,   00000000,   Tap latency
    31  	adxl345Reg_WINDOW         = 0x23 // R/W,   00000000,   Tap window
    32  	adxl345Reg_THRESH_ACT     = 0x24 // R/W,   00000000,   Activity threshold
    33  	adxl345Reg_THRESH_INACT   = 0x25 // R/W,   00000000,   Inactivity threshold
    34  	adxl345Reg_TIME_INACT     = 0x26 // R/W,   00000000,   Inactivity time
    35  	adxl345Reg_ACT_INACT_CTL  = 0x27 // R/W,   00000000,   Axis enable control for activity and inactivity detection
    36  	adxl345Reg_THRESH_FF      = 0x28 // R/W,   00000000,   Free-fall threshold
    37  	adxl345Reg_TIME_FF        = 0x29 // R/W,   00000000,   Free-fall time
    38  	adxl345Reg_TAP_AXES       = 0x2A // R/W,   00000000,   Axis control for single tap/double tap
    39  	adxl345Reg_ACT_TAP_STATUS = 0x2B // R,     00000000,   Source of single tap/double tap
    40  	adxl345Reg_BW_RATE        = 0x2C // R/W,   00001010,   Data rate and power mode control
    41  	adxl345Reg_POWER_CTL      = 0x2D // R/W,   00000000,   Power-saving features control
    42  	adxl345Reg_INT_ENABLE     = 0x2E // R/W,   00000000,   Interrupt enable control
    43  	adxl345Reg_INT_MAP        = 0x2F // R/W,   00000000,   Interrupt mapping control
    44  	adxl345Reg_INT_SOUCE      = 0x30 // R,     00000010,   Source of interrupts
    45  	adxl345Reg_DATA_FORMAT    = 0x31 // R/W,   00000000,   Data format control (FS range, justify, full resolution)
    46  	adxl345Reg_DATAX0         = 0x32 // R,     00000000,   X-Axis Data 0 (LSByte)
    47  	adxl345Reg_DATAX1         = 0x33 // R,     00000000,   X-Axis Data 1 (MSByte)
    48  	adxl345Reg_DATAY0         = 0x34 // R,     00000000,   Y-Axis Data 0
    49  	adxl345Reg_DATAY1         = 0x35 // R,     00000000,   Y-Axis Data 1
    50  	adxl345Reg_DATAZ0         = 0x36 // R,     00000000,   Z-Axis Data 0
    51  	adxl345Reg_DATAZ1         = 0x37 // R,     00000000,   Z-Axis Data 1
    52  	adxl345Reg_FIFO_CTL       = 0x38 // R/W,   00000000,   FIFO control
    53  	adxl345Reg_FIFO_STATUS    = 0x39 // R,     00000000,   FIFO status
    54  
    55  	adxl345Rate_LowPowerBit = 0x10 // set the device to low power, but increase the noise by ~2.5x
    56  
    57  	ADXL345Rate_100mHZ   ADXL345RateConfig = 0x00 // 0.10 Hz
    58  	ADXL345Rate_200mHZ   ADXL345RateConfig = 0x01 // 0.20 Hz
    59  	ADXL345Rate_390mHZ   ADXL345RateConfig = 0x02 // 0.39 Hz
    60  	ADXL345Rate_780mHZ   ADXL345RateConfig = 0x03 // 0.78 Hz
    61  	ADXL345Rate_1560mHZ  ADXL345RateConfig = 0x04 // 1.56 Hz
    62  	ADXL345Rate_3130mHZ  ADXL345RateConfig = 0x05 // 3.13 Hz
    63  	ADXL345Rate_6250mHZ  ADXL345RateConfig = 0x06 // 6.25 Hz
    64  	ADXL345Rate_12500mHZ ADXL345RateConfig = 0x07 // 12.5 Hz
    65  	ADXL345Rate_25HZ     ADXL345RateConfig = 0x08 // 25 Hz
    66  	ADXL345Rate_50HZ     ADXL345RateConfig = 0x09 // 50 Hz
    67  	ADXL345Rate_100HZ    ADXL345RateConfig = 0x0A // 100 Hz
    68  	ADXL345Rate_200HZ    ADXL345RateConfig = 0x0B // 200 Hz
    69  	ADXL345Rate_400HZ    ADXL345RateConfig = 0x0C // 400 Hz
    70  	ADXL345Rate_800HZ    ADXL345RateConfig = 0x0D // 800 Hz
    71  	ADXL345Rate_1600HZ   ADXL345RateConfig = 0x0E // 1600 Hz
    72  	ADXL345Rate_3200HZ   ADXL345RateConfig = 0x0F // 3200 Hz
    73  
    74  	ADXL345FsRange_2G  ADXL345FsRangeConfig = 0x00 // +-2 g
    75  	ADXL345FsRange_4G  ADXL345FsRangeConfig = 0x01 // +-4 g
    76  	ADXL345FsRange_8G  ADXL345FsRangeConfig = 0x02 // +-8 g
    77  	ADXL345FsRange_16G ADXL345FsRangeConfig = 0x03 // +-16 g)
    78  )
    79  
    80  // ADXL345Driver is the gobot driver for the digital accelerometer ADXL345
    81  //
    82  // Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
    83  // Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf
    84  //
    85  // Ported from the Arduino driver https://github.com/jakalada/Arduino-ADXL345
    86  type ADXL345Driver struct {
    87  	*Driver
    88  	powerCtl   adxl345PowerCtl
    89  	dataFormat adxl345DataFormat
    90  	bwRate     adxl345BwRate
    91  }
    92  
    93  // Internal structure for the power configuration
    94  type adxl345PowerCtl struct {
    95  	link      uint8
    96  	autoSleep uint8
    97  	measure   uint8
    98  	sleep     uint8
    99  	wakeUp    uint8
   100  }
   101  
   102  // Internal structure for the sensor's data format configuration
   103  type adxl345DataFormat struct {
   104  	selfTest       uint8
   105  	spi            uint8
   106  	intInvert      uint8
   107  	fullRes        uint8
   108  	justify        uint8
   109  	fullScaleRange ADXL345FsRangeConfig
   110  }
   111  
   112  // Internal structure for the sampling rate configuration
   113  type adxl345BwRate struct {
   114  	lowPower bool
   115  	rate     ADXL345RateConfig
   116  }
   117  
   118  // NewADXL345Driver creates a new driver with specified i2c interface
   119  // Params:
   120  //		c Connector - the Adaptor to use with this Driver
   121  //
   122  // Optional params:
   123  //		i2c.WithBus(int):	bus to use with this driver
   124  //		i2c.WithAddress(int):	address to use with this driver
   125  //
   126  func NewADXL345Driver(c Connector, options ...func(Config)) *ADXL345Driver {
   127  	d := &ADXL345Driver{
   128  		Driver: NewDriver(c, "ADXL345", adxl345DefaultAddress),
   129  		powerCtl: adxl345PowerCtl{
   130  			measure: 1,
   131  		},
   132  		dataFormat: adxl345DataFormat{
   133  			fullScaleRange: ADXL345FsRange_2G,
   134  		},
   135  		bwRate: adxl345BwRate{
   136  			lowPower: true,
   137  			rate:     ADXL345Rate_100HZ,
   138  		},
   139  	}
   140  	d.afterStart = d.initialize
   141  	d.beforeHalt = d.shutdown
   142  
   143  	for _, option := range options {
   144  		option(d)
   145  	}
   146  
   147  	// TODO: add commands for API
   148  	return d
   149  }
   150  
   151  // WithADXL345LowPowerMode option modifies the low power mode.
   152  func WithADXL345LowPowerMode(val bool) func(Config) {
   153  	return func(c Config) {
   154  		if d, ok := c.(*ADXL345Driver); ok {
   155  			d.bwRate.lowPower = val
   156  		} else if adxl345Debug {
   157  			log.Printf("Trying to modify low power mode for non-ADXL345Driver %v", c)
   158  		}
   159  	}
   160  }
   161  
   162  // WithADXL345DataOutputRate option sets the data output rate.
   163  // Valid settings are of type "ADXL345RateConfig"
   164  func WithADXL345DataOutputRate(val ADXL345RateConfig) func(Config) {
   165  	return func(c Config) {
   166  		if d, ok := c.(*ADXL345Driver); ok {
   167  			d.bwRate.rate = val
   168  		} else if adxl345Debug {
   169  			log.Printf("Trying to set data output rate for non-ADXL345Driver %v", c)
   170  		}
   171  	}
   172  }
   173  
   174  // WithADXL345FullScaleRange option sets the full scale range.
   175  // Valid settings are of type "ADXL345FsRangeConfig"
   176  func WithADXL345FullScaleRange(val ADXL345FsRangeConfig) func(Config) {
   177  	return func(c Config) {
   178  		if d, ok := c.(*ADXL345Driver); ok {
   179  			d.dataFormat.fullScaleRange = val
   180  		} else if adxl345Debug {
   181  			log.Printf("Trying to set full scale range for non-ADXL345Driver %v", c)
   182  		}
   183  	}
   184  }
   185  
   186  // UseLowPower change the current rate of the sensor
   187  func (d *ADXL345Driver) UseLowPower(lowPower bool) (err error) {
   188  	d.mutex.Lock()
   189  	defer d.mutex.Unlock()
   190  
   191  	d.bwRate.lowPower = lowPower
   192  	if err := d.connection.WriteByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil {
   193  		return err
   194  	}
   195  	return
   196  }
   197  
   198  // SetRate change the current rate of the sensor immediately
   199  func (d *ADXL345Driver) SetRate(rate ADXL345RateConfig) (err error) {
   200  	d.mutex.Lock()
   201  	defer d.mutex.Unlock()
   202  
   203  	d.bwRate.rate = rate
   204  	if err := d.connection.WriteByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil {
   205  		return err
   206  	}
   207  	return
   208  }
   209  
   210  // SetRange change the current range of the sensor immediately
   211  func (d *ADXL345Driver) SetRange(fullScaleRange ADXL345FsRangeConfig) (err error) {
   212  	d.mutex.Lock()
   213  	defer d.mutex.Unlock()
   214  
   215  	d.dataFormat.fullScaleRange = fullScaleRange
   216  	if err := d.connection.WriteByteData(adxl345Reg_DATA_FORMAT, d.dataFormat.toByte()); err != nil {
   217  		return err
   218  	}
   219  	return
   220  }
   221  
   222  // XYZ returns the adjusted x, y and z axis, unit [g]
   223  func (d *ADXL345Driver) XYZ() (float64, float64, float64, error) {
   224  	d.mutex.Lock()
   225  	defer d.mutex.Unlock()
   226  
   227  	xr, yr, zr, err := d.readRawData()
   228  	if err != nil {
   229  		return 0, 0, 0, err
   230  	}
   231  
   232  	return d.dataFormat.convertToG(xr), d.dataFormat.convertToG(yr), d.dataFormat.convertToG(zr), nil
   233  }
   234  
   235  // XYZ returns the raw x,y and z axis
   236  func (d *ADXL345Driver) RawXYZ() (int16, int16, int16, error) {
   237  	d.mutex.Lock()
   238  	defer d.mutex.Unlock()
   239  
   240  	return d.readRawData()
   241  }
   242  
   243  func (d *ADXL345Driver) readRawData() (int16, int16, int16, error) {
   244  	buf := []byte{0, 0, 0, 0, 0, 0}
   245  	if err := d.connection.ReadBlockData(adxl345Reg_DATAX0, buf); err != nil {
   246  		return 0, 0, 0, err
   247  	}
   248  
   249  	rx := int16(binary.LittleEndian.Uint16(buf[0:2]))
   250  	ry := int16(binary.LittleEndian.Uint16(buf[2:4]))
   251  	rz := int16(binary.LittleEndian.Uint16(buf[4:6]))
   252  	return rx, ry, rz, nil
   253  }
   254  
   255  func (d *ADXL345Driver) initialize() error {
   256  	if err := d.connection.WriteByteData(adxl345Reg_BW_RATE, d.bwRate.toByte()); err != nil {
   257  		return err
   258  	}
   259  	if err := d.connection.WriteByteData(adxl345Reg_POWER_CTL, d.powerCtl.toByte()); err != nil {
   260  		return err
   261  	}
   262  	if err := d.connection.WriteByteData(adxl345Reg_DATA_FORMAT, d.dataFormat.toByte()); err != nil {
   263  		return err
   264  	}
   265  
   266  	return nil
   267  }
   268  
   269  func (d *ADXL345Driver) shutdown() error {
   270  	d.powerCtl.measure = 0
   271  	if d.connection == nil {
   272  		return errors.New("connection not available")
   273  	}
   274  	return d.connection.WriteByteData(adxl345Reg_POWER_CTL, d.powerCtl.toByte())
   275  }
   276  
   277  // convertToG converts the given raw value by range configuration to the unit [g]
   278  func (d *adxl345DataFormat) convertToG(rawValue int16) float64 {
   279  	switch d.fullScaleRange {
   280  	case ADXL345FsRange_2G:
   281  		return float64(rawValue) * 2 / 512
   282  	case ADXL345FsRange_4G:
   283  		return float64(rawValue) * 4 / 512
   284  	case ADXL345FsRange_8G:
   285  		return float64(rawValue) * 8 / 512
   286  	case ADXL345FsRange_16G:
   287  		return float64(rawValue) * 16 / 512
   288  	default:
   289  		return 0
   290  	}
   291  }
   292  
   293  // toByte returns a byte from the powerCtl configuration
   294  func (p *adxl345PowerCtl) toByte() uint8 {
   295  	bits := p.wakeUp
   296  	bits = bits | (p.sleep << 2)
   297  	bits = bits | (p.measure << 3)
   298  	bits = bits | (p.autoSleep << 4)
   299  	return bits | (p.link << 5)
   300  }
   301  
   302  // toByte returns a byte from the dataFormat configuration
   303  func (d *adxl345DataFormat) toByte() uint8 {
   304  	bits := uint8(d.fullScaleRange)
   305  	bits = bits | (d.justify << 2)
   306  	bits = bits | (d.fullRes << 3)
   307  	bits = bits | (d.intInvert << 5)
   308  	bits = bits | (d.spi << 6)
   309  	return bits | (d.selfTest << 7)
   310  }
   311  
   312  // toByte returns a byte from the bwRate configuration
   313  func (b *adxl345BwRate) toByte() uint8 {
   314  	bits := uint8(b.rate)
   315  	if b.lowPower {
   316  		bits = bits | adxl345Rate_LowPowerBit
   317  	}
   318  	return bits
   319  }