lis3dh: implement accelerometer functionality

Signed-off-by: Ron Evans <ron@hybridgroup.com>
This commit is contained in:
Ron Evans
2019-04-15 19:15:58 +02:00
committed by Ayke
parent 720097ebad
commit c0cadf8d82
5 changed files with 237 additions and 0 deletions
+1
View File
@@ -21,6 +21,7 @@ jobs:
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/ds3231/main.go
- run: tinygo build -size short -o test.elf -target=microbit ./examples/easystepper/main.go
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/espat/esphub/main.go
- run: tinygo build -size short -o test.elf -target=circuitplay-express ./examples/lis3dh/main.go
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mag3110/main.go
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mma8653/main.go
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 ./examples/mpu6050/main.go
+1
View File
@@ -62,6 +62,7 @@ func main() {
| [DS3231 real time clock](https://datasheets.maximintegrated.com/en/ds/DS3231.pdf) | I2C |
| ["Easystepper" stepper motor controller](https://en.wikipedia.org/wiki/Stepper_motor) | GPIO |
| [ESP8266/ESP32 AT Command set for WiFi/TCP/UDP](https://github.com/espressif/esp32-at) | UART |
| [LIS3DH accelerometer](https://www.st.com/resource/en/datasheet/lis3dh.pdf) | I2C |
| [MAG3110 magnetometer](https://www.nxp.com/docs/en/data-sheet/MAG3110.pdf) | I2C |
| [MMA8653 accelerometer](https://www.nxp.com/docs/en/data-sheet/MMA8653FC.pdf) | I2C |
| [MPU6050 accelerometer/gyroscope](https://store.invensense.com/datasheets/invensense/MPU-6050_DataSheet_V3%204.pdf) | I2C |
+32
View File
@@ -0,0 +1,32 @@
// Connects to a LIS3DH I2C accelerometer on the Adafruit Circuit Playground Express.
package main
import (
"machine"
"time"
"github.com/tinygo-org/drivers/lis3dh"
)
var i2c = machine.I2C1
func main() {
i2c.Configure(machine.I2CConfig{})
accel := lis3dh.New(i2c)
accel.Address = lis3dh.Address1 // address on the Circuit Playground Express
accel.Configure()
accel.SetRange(lis3dh.RANGE_2_G)
println(accel.Connected())
for {
x, y, z, _ := accel.ReadAcceleration()
println("X:", x, "Y:", y, "Z:", z)
rx, ry, rz := accel.ReadRawAcceleration()
println("X (raw):", rx, "Y (raw):", ry, "Z (raw):", rz)
time.Sleep(time.Millisecond * 100)
}
}
+126
View File
@@ -0,0 +1,126 @@
// Package lis3dh provides a driver for the LIS3DH digital accelerometer.
//
// Datasheet: https://www.st.com/resource/en/datasheet/lis3dh.pdf
package lis3dh
import (
"machine"
)
// Device wraps an I2C connection to a LIS3DH device.
type Device struct {
bus machine.I2C
Address uint16
r Range
}
// 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 machine.I2C) Device {
return Device{bus: bus, Address: Address0}
}
// Configure sets up the device for communication
func (d *Device) Configure() {
// enable all axes, normal mode
d.bus.WriteRegister(uint8(d.Address), REG_CTRL1, []byte{0x07})
// 400Hz rate
d.SetDataRate(DATARATE_400_HZ)
// High res & BDU enabled
d.bus.WriteRegister(uint8(d.Address), REG_CTRL4, []byte{0x88})
// get current range
d.r = d.ReadRange()
}
// 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 := d.bus.ReadRegister(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) {
ctl1 := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CTRL1, ctl1)
if err != nil {
println(err.Error())
}
// mask off bits
ctl1[0] &^= 0xf0
ctl1[0] |= (byte(rate) << 4)
d.bus.WriteRegister(uint8(d.Address), REG_CTRL1, ctl1)
}
// SetRange sets the G range for LIS3DH.
func (d *Device) SetRange(r Range) {
ctl := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CTRL4, ctl)
if err != nil {
println(err.Error())
}
// mask off bits
ctl[0] &^= 0x30
ctl[0] |= (byte(r) << 4)
d.bus.WriteRegister(uint8(d.Address), REG_CTRL4, ctl)
// store the new range
d.r = r
}
// ReadRange returns the current G range for LIS3DH.
func (d *Device) ReadRange() (r Range) {
ctl := []byte{0}
err := d.bus.ReadRegister(uint8(d.Address), REG_CTRL4, ctl)
if err != nil {
println(err.Error())
}
// mask off bits
r = Range(ctl[0] >> 4)
r &= 0x03
return r
}
// 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) {
d.bus.WriteRegister(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
}
+77
View File
@@ -0,0 +1,77 @@
package lis3dh
// Constants/addresses used for I2C.
// The I2C addresses which this device listens to.
const (
Address0 = 0x18 // SA0 is low
Address1 = 0x19 // SA0 is high
)
// Registers. Names, addresses and comments copied from the datasheet.
const (
WHO_AM_I = 0x0F
REG_STATUS1 = 0x07
REG_OUTADC1_L = 0x08
REG_OUTADC1_H = 0x09
REG_OUTADC2_L = 0x0A
REG_OUTADC2_H = 0x0B
REG_OUTADC3_L = 0x0C
REG_OUTADC3_H = 0x0D
REG_INTCOUNT = 0x0E
REG_WHOAMI = 0x0F
REG_TEMPCFG = 0x1F
REG_CTRL1 = 0x20
REG_CTRL2 = 0x21
REG_CTRL3 = 0x22
REG_CTRL4 = 0x23
REG_CTRL5 = 0x24
REG_CTRL6 = 0x25
REG_REFERENCE = 0x26
REG_STATUS2 = 0x27
REG_OUT_X_L = 0x28
REG_OUT_X_H = 0x29
REG_OUT_Y_L = 0x2A
REG_OUT_Y_H = 0x2B
REG_OUT_Z_L = 0x2C
REG_OUT_Z_H = 0x2D
REG_FIFOCTRL = 0x2E
REG_FIFOSRC = 0x2F
REG_INT1CFG = 0x30
REG_INT1SRC = 0x31
REG_INT1THS = 0x32
REG_INT1DUR = 0x33
REG_CLICKCFG = 0x38
REG_CLICKSRC = 0x39
REG_CLICKTHS = 0x3A
REG_TIMELIMIT = 0x3B
REG_TIMELATEN = 0x3C
REG_TIMEWINDO = 0x3D
REG_ACTTHS = 0x3E
REG_ACTDUR = 0x3F
)
type Range uint8
const (
RANGE_16_G Range = 3 // +/- 16g
RANGE_8_G = 2 // +/- 8g
RANGE_4_G = 1 // +/- 4g
RANGE_2_G = 0 // +/- 2g (default value)
)
type DataRate uint8
// Data rate constants.
const (
DATARATE_400_HZ DataRate = 7 // 400Hz
DATARATE_200_HZ = 6 // 200Hz
DATARATE_100_HZ = 5 // 100Hz
DATARATE_50_HZ = 4 // 50Hz
DATARATE_25_HZ = 3 // 25Hz
DATARATE_10_HZ = 2 // 10 Hz
DATARATE_1_HZ = 1 // 1 Hz
DATARATE_POWERDOWN = 0
DATARATE_LOWPOWER_1K6HZ = 8
DATARATE_LOWPOWER_5KHZ = 9
)