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

     1  package i2c
     2  
     3  import (
     4  	"encoding/binary"
     5  
     6  	"github.com/pkg/errors"
     7  	"gobot.io/x/gobot"
     8  )
     9  
    10  const ADXL345AddressLow = 0x53
    11  const ADXL345AddressHigh = 0x1D
    12  
    13  const (
    14  	// Data rate
    15  	ADXL345_RATE_3200HZ = 0x0F // 3200 Hz
    16  	ADXL345_RATE_1600HZ = 0x0E // 1600 Hz
    17  	ADXL345_RATE_800HZ  = 0x0D // 800 Hz
    18  	ADXL345_RATE_400HZ  = 0x0C // 400 Hz
    19  	ADXL345_RATE_200HZ  = 0x0B // 200 Hz
    20  	ADXL345_RATE_100HZ  = 0x0A // 100 Hz
    21  	ADXL345_RATE_50HZ   = 0x09 // 50 Hz
    22  	ADXL345_RATE_25HZ   = 0x08 // 25 Hz
    23  	ADXL345_RATE_12_5HZ = 0x07 // 12.5 Hz
    24  	ADXL345_RATE_6_25HZ = 0x06 // 6.25 Hz
    25  	ADXL345_RATE_3_13HZ = 0x05 // 3.13 Hz
    26  	ADXL345_RATE_1_56HZ = 0x04 // 1.56 Hz
    27  	ADXL345_RATE_0_78HZ = 0x03 // 0.78 Hz
    28  	ADXL345_RATE_0_39HZ = 0x02 // 0.39 Hz
    29  	ADXL345_RATE_0_20HZ = 0x01 // 0.20 Hz
    30  	ADXL345_RATE_0_10HZ = 0x00 // 0.10 Hz
    31  
    32  	// Data range
    33  	ADXL345_RANGE_2G  = 0x00 // +-2 g
    34  	ADXL345_RANGE_4G  = 0x01 // +-4 g
    35  	ADXL345_RANGE_8G  = 0x02 // +-8 g
    36  	ADXL345_RANGE_16G = 0x03 // +-16 g)
    37  
    38  	ADXL345_REG_DEVID          = 0x00 // R,     11100101,   Device ID
    39  	ADXL345_REG_THRESH_TAP     = 0x1D // R/W,   00000000,   Tap threshold
    40  	ADXL345_REG_OFSX           = 0x1E // R/W,   00000000,   X-axis offset
    41  	ADXL345_REG_OFSY           = 0x1F // R/W,   00000000,   Y-axis offset
    42  	ADXL345_REG_OFSZ           = 0x20 // R/W,   00000000,   Z-axis offset
    43  	ADXL345_REG_DUR            = 0x21 // R/W,   00000000,   Tap duration
    44  	ADXL345_REG_LATENT         = 0x22 // R/W,   00000000,   Tap latency
    45  	ADXL345_REG_WINDOW         = 0x23 // R/W,   00000000,   Tap window
    46  	ADXL345_REG_THRESH_ACT     = 0x24 // R/W,   00000000,   Activity threshold
    47  	ADXL345_REG_THRESH_INACT   = 0x25 // R/W,   00000000,   Inactivity threshold
    48  	ADXL345_REG_TIME_INACT     = 0x26 // R/W,   00000000,   Inactivity time
    49  	ADXL345_REG_ACT_INACT_CTL  = 0x27 // R/W,   00000000,   Axis enable control for activity and inactiv ity detection
    50  	ADXL345_REG_THRESH_FF      = 0x28 // R/W,   00000000,   Free-fall threshold
    51  	ADXL345_REG_TIME_FF        = 0x29 // R/W,   00000000,   Free-fall time
    52  	ADXL345_REG_TAP_AXES       = 0x2A // R/W,   00000000,   Axis control for single tap/double tap
    53  	ADXL345_REG_ACT_TAP_STATUS = 0x2B // R,     00000000,   Source of single tap/double tap
    54  	ADXL345_REG_BW_RATE        = 0x2C // R/W,   00001010,   Data rate and power mode control
    55  	ADXL345_REG_POWER_CTL      = 0x2D // R/W,   00000000,   Power-saving features control
    56  	ADXL345_REG_INT_ENABLE     = 0x2E // R/W,   00000000,   Interrupt enable control
    57  	ADXL345_REG_INT_MAP        = 0x2F // R/W,   00000000,   Interrupt mapping control
    58  	ADXL345_REG_INT_SOUCE      = 0x30 // R,     00000010,   Source of interrupts
    59  	ADXL345_REG_DATA_FORMAT    = 0x31 // R/W,   00000000,   Data format control
    60  	ADXL345_REG_DATAX0         = 0x32 // R,     00000000,   X-Axis Data 0
    61  	ADXL345_REG_DATAX1         = 0x33 // R,     00000000,   X-Axis Data 1
    62  	ADXL345_REG_DATAY0         = 0x34 // R,     00000000,   Y-Axis Data 0
    63  	ADXL345_REG_DATAY1         = 0x35 // R,     00000000,   Y-Axis Data 1
    64  	ADXL345_REG_DATAZ0         = 0x36 // R,     00000000,   Z-Axis Data 0
    65  	ADXL345_REG_DATAZ1         = 0x37 // R,     00000000,   Z-Axis Data 1
    66  	ADXL345_REG_FIFO_CTL       = 0x38 // R/W,   00000000,   FIFO control
    67  	ADXL345_REG_FIFO_STATUS    = 0x39 // R,     00000000,   FIFO status
    68  )
    69  
    70  // ADXL345Driver is the gobot driver for the digital accelerometer ADXL345
    71  //
    72  // Datasheet EN: http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
    73  // Datasheet JP: http://www.analog.com/media/jp/technical-documentation/data-sheets/ADXL345_jp.pdf
    74  //
    75  // Ported from the Arduino driver https://github.com/jakalada/Arduino-ADXL345
    76  type ADXL345Driver struct {
    77  	name       string
    78  	connector  Connector
    79  	connection Connection
    80  
    81  	powerCtl   adxl345PowerCtl
    82  	dataFormat adxl345DataFormat
    83  	bwRate     adxl345BwRate
    84  
    85  	x, y, z          float64
    86  	rawX, rawY, rawZ int16
    87  
    88  	Config
    89  }
    90  
    91  // Internal structure for the power configuration
    92  type adxl345PowerCtl struct {
    93  	link      uint8
    94  	autoSleep uint8
    95  	measure   uint8
    96  	sleep     uint8
    97  	wakeUp    uint8
    98  }
    99  
   100  // Internal structure for the sensor's data format configuration
   101  type adxl345DataFormat struct {
   102  	selfTest    uint8
   103  	spi         uint8
   104  	intInvert   uint8
   105  	fullRes     uint8
   106  	justify     uint8
   107  	sensorRange uint8
   108  }
   109  
   110  // Internal structure for the sampling rate configuration
   111  type adxl345BwRate struct {
   112  	lowPower uint8
   113  	rate     uint8
   114  }
   115  
   116  // NewADXL345Driver creates a new driver with specified i2c interface
   117  // Params:
   118  //		conn Connector - the Adaptor to use with this Driver
   119  //
   120  // Optional params:
   121  //		i2c.WithBus(int):	bus to use with this driver
   122  //		i2c.WithAddress(int):	address to use with this driver
   123  //
   124  func NewADXL345Driver(a Connector, options ...func(Config)) *ADXL345Driver {
   125  	m := &ADXL345Driver{
   126  		name:      gobot.DefaultName("ADXL345"),
   127  		connector: a,
   128  		powerCtl: adxl345PowerCtl{
   129  			measure: 1,
   130  		},
   131  		dataFormat: adxl345DataFormat{
   132  			sensorRange: ADXL345_RANGE_2G,
   133  		},
   134  		bwRate: adxl345BwRate{
   135  			lowPower: 1,
   136  			rate:     ADXL345_RATE_100HZ,
   137  		},
   138  		Config: NewConfig(),
   139  	}
   140  
   141  	for _, option := range options {
   142  		option(m)
   143  	}
   144  
   145  	// TODO: add commands for API
   146  	return m
   147  }
   148  
   149  // Name returns the Name for the Driver
   150  func (h *ADXL345Driver) Name() string { return h.name }
   151  
   152  // SetName sets the Name for the Driver
   153  func (h *ADXL345Driver) SetName(n string) { h.name = n }
   154  
   155  // Connection returns the connection for the Driver
   156  func (h *ADXL345Driver) Connection() gobot.Connection { return h.connector.(gobot.Connection) }
   157  
   158  // Start initialized the adxl345
   159  func (h *ADXL345Driver) Start() (err error) {
   160  	bus := h.GetBusOrDefault(h.connector.GetDefaultBus())
   161  	address := h.GetAddressOrDefault(ADXL345AddressLow)
   162  
   163  	h.connection, err = h.connector.GetConnection(address, bus)
   164  	if err != nil {
   165  		return err
   166  	}
   167  
   168  	if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil {
   169  		return err
   170  	}
   171  
   172  	if _, err := h.connection.Write([]byte{ADXL345_REG_POWER_CTL, h.powerCtl.toByte()}); err != nil {
   173  		return err
   174  	}
   175  
   176  	if _, err := h.connection.Write([]byte{ADXL345_REG_DATA_FORMAT, h.dataFormat.toByte()}); err != nil {
   177  		return err
   178  	}
   179  
   180  	return
   181  }
   182  
   183  // Stop adxl345
   184  func (h *ADXL345Driver) Stop() (err error) {
   185  	h.powerCtl.measure = 0
   186  	if h.connection == nil {
   187  		return errors.New("connection not available")
   188  	}
   189  	if _, err := h.connection.Write([]byte{ADXL345_REG_POWER_CTL, h.powerCtl.toByte()}); err != nil {
   190  		return err
   191  	}
   192  
   193  	return
   194  }
   195  
   196  // Halt returns true if devices is halted successfully
   197  func (h *ADXL345Driver) Halt() (err error) {
   198  	h.Stop()
   199  	return
   200  }
   201  
   202  // XYZ returns the adjusted x, y and z axis from the adxl345
   203  func (h *ADXL345Driver) XYZ() (float64, float64, float64, error) {
   204  	err := h.update()
   205  	return h.x, h.y, h.z, err
   206  }
   207  
   208  // XYZ returns the raw x,y and z axis from the adxl345
   209  func (h *ADXL345Driver) RawXYZ() (int16, int16, int16, error) {
   210  	err := h.update()
   211  	return h.rawX, h.rawY, h.rawZ, err
   212  }
   213  
   214  // update the cached values for the axis to avoid errors if the connection is not available (polling too frequently)
   215  func (h *ADXL345Driver) update() (err error) {
   216  
   217  	if h.connection == nil {
   218  		return errors.New("connection not available")
   219  	}
   220  
   221  	h.connection.Write([]byte{ADXL345_REG_DATAX0})
   222  	buf := []byte{0, 0, 0, 0, 0, 0}
   223  
   224  	_, err = h.connection.Read(buf)
   225  	if err != nil {
   226  		return
   227  	}
   228  
   229  	h.rawX = int16(binary.LittleEndian.Uint16(buf[0:2]))
   230  	h.rawY = int16(binary.LittleEndian.Uint16(buf[2:4]))
   231  	h.rawZ = int16(binary.LittleEndian.Uint16(buf[4:6]))
   232  
   233  	h.x = h.dataFormat.ConvertToSI(h.rawX)
   234  	h.y = h.dataFormat.ConvertToSI(h.rawY)
   235  	h.z = h.dataFormat.ConvertToSI(h.rawZ)
   236  
   237  	return
   238  }
   239  
   240  // SetRate change the current rate of the sensor
   241  func (h *ADXL345Driver) UseLowPower(power bool) (err error) {
   242  	if power {
   243  		h.bwRate.lowPower = 1
   244  	} else {
   245  		h.bwRate.lowPower = 0
   246  	}
   247  	if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil {
   248  		return err
   249  	}
   250  	return
   251  }
   252  
   253  // SetRate change the current rate of the sensor
   254  func (h *ADXL345Driver) SetRate(rate byte) (err error) {
   255  	if rate <= ADXL345_RATE_3200HZ {
   256  		return errors.New("not a valid rate")
   257  	}
   258  	h.bwRate.rate = rate & 0x0F
   259  	if _, err := h.connection.Write([]byte{ADXL345_REG_BW_RATE, h.bwRate.toByte()}); err != nil {
   260  		return err
   261  	}
   262  	return
   263  }
   264  
   265  // SetRange change the current range of the sensor
   266  func (h *ADXL345Driver) SetRange(sensorRange byte) (err error) {
   267  	if sensorRange != ADXL345_RANGE_2G &&
   268  		sensorRange != ADXL345_RANGE_4G &&
   269  		sensorRange != ADXL345_RANGE_8G &&
   270  		sensorRange != ADXL345_RANGE_16G {
   271  		return errors.New("not a valid range")
   272  	}
   273  	h.dataFormat.sensorRange = sensorRange & 0x03
   274  	if _, err := h.connection.Write([]byte{ADXL345_REG_DATA_FORMAT, h.dataFormat.toByte()}); err != nil {
   275  		return err
   276  	}
   277  	return
   278  }
   279  
   280  // ConvertToSI adjusts the raw values from the adxl345 with the range configuration
   281  func (d *adxl345DataFormat) ConvertToSI(rawValue int16) float64 {
   282  	switch d.sensorRange {
   283  	case ADXL345_RANGE_2G:
   284  		return float64(rawValue) * 2 / 512
   285  	case ADXL345_RANGE_4G:
   286  		return float64(rawValue) * 4 / 512
   287  	case ADXL345_RANGE_8G:
   288  		return float64(rawValue) * 8 / 512
   289  	case ADXL345_RANGE_16G:
   290  		return float64(rawValue) * 16 / 512
   291  	default:
   292  		return 0
   293  	}
   294  }
   295  
   296  // toByte returns a byte from the powerCtl configuration
   297  func (p *adxl345PowerCtl) toByte() (bits uint8) {
   298  	bits = 0x00
   299  	bits = bits | (p.link << 5)
   300  	bits = bits | (p.autoSleep << 4)
   301  	bits = bits | (p.measure << 3)
   302  	bits = bits | (p.sleep << 2)
   303  	bits = bits | p.wakeUp
   304  
   305  	return bits
   306  }
   307  
   308  // toByte returns a byte from the dataFormat configuration
   309  func (d *adxl345DataFormat) toByte() (bits uint8) {
   310  	bits = 0x00
   311  	bits = bits | (d.selfTest << 7)
   312  	bits = bits | (d.spi << 6)
   313  	bits = bits | (d.intInvert << 5)
   314  	bits = bits | (d.fullRes << 3)
   315  	bits = bits | (d.justify << 2)
   316  	bits = bits | d.sensorRange
   317  
   318  	return bits
   319  }
   320  
   321  // toByte returns a byte from the bwRate configuration
   322  func (b *adxl345BwRate) toByte() (bits uint8) {
   323  	bits = 0x00
   324  	bits = bits | (b.lowPower << 4)
   325  	bits = bits | b.rate
   326  
   327  	return bits
   328  }