// Package lis3dh provides a driver for the LIS3DH digital accelerometer. // // Datasheet: https://www.st.com/resource/en/datasheet/lis3dh.pdf package lis3dh // import "tinygo.org/x/drivers/lis3dh" import ( "tinygo.org/x/drivers" "tinygo.org/x/drivers/internal/legacy" ) // Device wraps an I2C connection to a LIS3DH device. type Device struct { bus drivers.I2C address uint16 r Range } // Driver configuration, used for the Configure call. All fields are optional. type Config struct { Address uint16 } // New creates a new LIS3DH connection. The I2C bus must already be configured. // // This function only creates the Device object, it does not touch the device. func New(bus drivers.I2C) Device { return Device{bus: bus, address: Address0} } // Configure sets up the device for communication func (d *Device) Configure(config Config) error { if config.Address != 0 { d.address = config.Address } // enable all axes, normal mode err := legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL1, []byte{0x07}) if err != nil { return err } // 400Hz rate err = d.SetDataRate(DATARATE_400_HZ) if err != nil { return err } // High res & BDU enabled err = legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL4, []byte{0x88}) if err != nil { return err } // get current range d.r, err = d.ReadRange() return err } // Connected returns whether a LIS3DH has been found. // It does a "who am I" request and checks the response. func (d *Device) Connected() bool { data := []byte{0} err := legacy.ReadRegister(d.bus, uint8(d.address), WHO_AM_I, data) if err != nil { return false } return data[0] == 0x33 } // SetDataRate sets the speed of data collected by the LIS3DH. func (d *Device) SetDataRate(rate DataRate) error { ctl1 := []byte{0} err := legacy.ReadRegister(d.bus, uint8(d.address), REG_CTRL1, ctl1) if err != nil { return err } // mask off bits ctl1[0] &^= 0xf0 ctl1[0] |= (byte(rate) << 4) return legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL1, ctl1) } // SetRange sets the G range for LIS3DH. func (d *Device) SetRange(r Range) error { ctl := []byte{0} err := legacy.ReadRegister(d.bus, uint8(d.address), REG_CTRL4, ctl) if err != nil { return err } // mask off bits ctl[0] &^= 0x30 ctl[0] |= (byte(r) << 4) err = legacy.WriteRegister(d.bus, uint8(d.address), REG_CTRL4, ctl) if err != nil { return err } // store the new range d.r = r return nil } // ReadRange returns the current G range for LIS3DH. func (d *Device) ReadRange() (r Range, err error) { ctl := []byte{0} err = legacy.ReadRegister(d.bus, uint8(d.address), REG_CTRL4, ctl) if err != nil { return 0, err } // mask off bits r = Range(ctl[0] >> 4) r &= 0x03 return r, nil } // ReadAcceleration reads the current acceleration from the device and returns // it in µg (micro-gravity). When one of the axes is pointing straight to Earth // and the sensor is not moving the returned value will be around 1000000 or // -1000000. func (d *Device) ReadAcceleration() (int32, int32, int32, error) { x, y, z := d.ReadRawAcceleration() divider := float32(1) switch d.r { case RANGE_16_G: divider = 1365 case RANGE_8_G: divider = 4096 case RANGE_4_G: divider = 8190 case RANGE_2_G: divider = 16380 } return int32(float32(x) / divider * 1000000), int32(float32(y) / divider * 1000000), int32(float32(z) / divider * 1000000), nil } // ReadRawAcceleration returns the raw x, y and z axis from the LIS3DH func (d *Device) ReadRawAcceleration() (x int16, y int16, z int16) { legacy.WriteRegister(d.bus, uint8(d.address), REG_OUT_X_L|0x80, nil) data := []byte{0, 0, 0, 0, 0, 0} d.bus.Tx(d.address, nil, data) x = int16((uint16(data[1]) << 8) | uint16(data[0])) y = int16((uint16(data[3]) << 8) | uint16(data[2])) z = int16((uint16(data[5]) << 8) | uint16(data[4])) return }