From a0f580fcea13d5c6a14751b6d48854bac6242ba2 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 10:57:07 +0100 Subject: [PATCH 01/13] adxl345: Driver, initial commit for review. --- CONTRIBUTORS | 1 + adxl345/adxl345.go | 219 +++++++++++++++++++++++++++++++++++++ adxl345/doc.go | 10 ++ adxl345/example/example.go | 51 +++++++++ 4 files changed, 281 insertions(+) create mode 100644 adxl345/adxl345.go create mode 100644 adxl345/doc.go create mode 100644 adxl345/example/example.go diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 46bbf79..cab4994 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -36,6 +36,7 @@ Matt Aimonetti Max Ekman Matias Insaurralde Seán C McCord +Benoit Pereira da Silva Stephan Sperber Thorsten von Eicken Weston Schmidt diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go new file mode 100644 index 0000000..3d5c129 --- /dev/null +++ b/adxl345/adxl345.go @@ -0,0 +1,219 @@ +package adxl345 + +import ( + "encoding/binary" + "fmt" + "periph.io/x/conn/v3/physic" + "periph.io/x/conn/v3/spi" +) + +const ( + DeviceID = 0x00 // Device ID, expected to be 0xE5 when using ADXL345 + + // 0x01 to 0x1C are reserved for future use + + ThreshTap = 0x1D // Tap threshold + OfsX = 0x1E // X-axis offset + OfsY = 0x1F // Y-axis offset + OfsZ = 0x20 // Z-axis offset + Dur = 0x21 // Tap duration + Latent = 0x22 // Tap latency + Window = 0x23 // Tap window + ThreshAct = 0x24 // Activity threshold + ThreshInact = 0x25 // Inactivity threshold + TimeInact = 0x26 // Inactivity time + ActInactCtl = 0x27 // Axis control for activity/inactivity detection + ThreshFf = 0x28 // Free-fall threshold + TapAxes = 0x2A // Axis control for single tap/double tap + TapStatus = 0x2B // Source of single tap/double tap + ActivityStatus = 0x2A // Source of activity detection + InactivityStatus = 0x2B // Source of inactivity detection + + // Control registers + + BwRate = 0x2C // Data rate and power mode control + PowerCtl = 0x2D // Power saving features control + IntEnable = 0x2E // Interrupt enable control + IntMap = 0x2F // Interrupt mapping control + IntSource = 0x30 // Source of interrupts + DataFormat = 0x31 // Data format control + + // Data registers + DataX0 = 0x32 // X-Axis Data 0 + DataX1 = 0x33 // X-Axis Data 1 + DataY0 = 0x34 // Y-Axis Data 0 + DataY1 = 0x35 // Y-Axis Data 1 + DataZ0 = 0x36 // Z-Axis Data 0 + DataZ1 = 0x37 // Z-Axis Data 1 + + // FIFO control + FifoCtl = 0x38 // FIFO control + FifoStatus = 0x39 // FIFO status + +) + +// DefaultSpiFrequency is the default SPI frequency used to communicate with the device. +var ( + SpiFrequency = physic.KiloHertz * 50 + SpiMode = spi.Mode3 // Defines the base clock signal, along with the polarity and phase of the data signal. + SpiBits = 8 +) + +var DefaultOpts = Opts{ + TurnOnOnStart: true, + ExpectedDevid: 0xE5, +} + +type Opts struct { + TurnOnOnStart bool // Turn on the device in measurement mode on start. + ExpectedDevid byte // Expected device ID used to verify that the device is an ADXL345. +} + +// Dev is a driver for the ADXL345 accelerometer +// It uses the SPI interface to communicate with the device. +type Dev struct { + name string + s spi.Conn +} + +func (d *Dev) String() string { + return fmt.Sprintf("ADXL345") +} + +// New creates a new ADXL345 Dev or returns an error. +// The bus and chip parameters define the SPI bus and chip select to use. +// The SPI s is configured. +// The device is turned on. +// The device is verified to be an ADXL345. +func New(p spi.Port, o *Opts) (*Dev, error) { + // Convert the spi.Port into a spi.Conn so it can be used for communication. + c, err := p.Connect(SpiFrequency, SpiMode, SpiBits) + if err != nil { + return nil, err + } + d := &Dev{ + name: "ADXL345", + s: c, + } + if o.TurnOnOnStart { + err = d.TurnOn() + if err != nil { + return nil, err + } + } + // Verify that the device is an ADXL345. + rx, _ := d.RawReadRegister(DeviceID) + if rx[1] != o.ExpectedDevid { + return nil, fmt.Errorf("wrong device connected should be an adxl345 should be\"%#x\" rx0=\"%#x\" rx1=\"%#x\"", o.ExpectedDevid, rx[0], rx[1]) + } + return d, nil +} + +// TurnOn turns on the measurement mode of the ADXL345. +// This is required before reading data from the device. +func (d *Dev) TurnOn() error { + return d.WriteRegister(PowerCtl, 0x08) +} + +// TurnOff turns off the measurement mode of the ADXL345. +func (d *Dev) TurnOff() error { + return d.WriteRegister(PowerCtl, 0x00) +} + +// Update reads the acceleration values from the ADXL345. +// By reading the acceleration the 3 axes acceleration values. +// This is a simple synchronous implementation. +func (d *Dev) Update() Acceleration { + return Acceleration{ + X: d.readAndCombine(DataX0, DataX1), + Y: d.readAndCombine(DataY0, DataY1), + Z: d.readAndCombine(DataZ0, DataZ1), + } +} + +// readAndCombine combines two registers to form a 16-bit value. +// Example: +// `DATAX0` is the address of the lower byte (LSB, least significant byte) of the X-axis data +// `DATAX1` is the address of the upper byte (MSB, most significant byte) of the X-axis data +// The ADXL345 combines both registers to deliver 16-bit output for each acceleration axis. +// A similar approach is used for the Y and Z axes. This technique provides higher precision in the measurements. +func (d *Dev) readAndCombine(reg1, reg2 byte) int16 { + low, _ := d.ReadRegister(reg1) + high, _ := d.ReadRegister(reg2) + return int16(uint16(high)<<8) | int16(low) +} + +// ReadRegister reads a 16-bit value from the specified register address. +func (d *Dev) ReadRegister(regAddress byte) (int16, error) { + // Send a two-byte sequence: + // - The first byte contains the address with bit 7 set high to indicate read op + // - The second byte is a "don't care" value, usually zero + tx := []byte{regAddress | 0x80, 0x00} + rx := make([]byte, len(tx)) + err := d.s.Tx(tx, rx) + r := int16(binary.LittleEndian.Uint16(rx)) + return r, err +} + +// RawReadRegister reads a []byte value from the specified register address. +func (d *Dev) RawReadRegister(regAddress byte) ([]byte, error) { + // Send a two-byte sequence: + // - The first byte contains the address with bit 7 set high to indicate read op + // - The second byte is a "don't care" value, usually zero + tx := []byte{regAddress | 0x80, 0x00} + rx := make([]byte, len(tx)) + err := d.s.Tx(tx, rx) + return rx, err +} + +// WriteRegister writes a 1 byte value to the specified register address. +func (d *Dev) WriteRegister(regAddress byte, value byte) error { + // Prepare a 2-byte buffer with the register address and the desired value. + tx := []byte{regAddress, value} + // Prepare a receiving buffer of the same size as the transmit buffer. + rx := make([]byte, len(tx)) + // Perform the transfer. We expect the SPI device to write back an acknowledgement. + err := d.s.Tx(tx, rx) + return err +} + +// Acceleration represents the acceleration on the three axes +type Acceleration struct { + X int16 + Y int16 + Z int16 +} + +// sum returns the sum of the accelerations on the three axes +func (a Acceleration) sum() int64 { + return int64(a.X) + int64(a.Y) + int64(a.Z) +} + +// diff returns the absolute difference between the two Acceleration +func (a Acceleration) diff(b Acceleration) Acceleration { + diff := Acceleration{ + X: a.X - b.X, + Y: a.Y - b.Y, + Z: a.Z - b.Z, + } + if diff.X < 0 { + diff.X = -diff.X + } + if diff.Y < 0 { + diff.Y = -diff.Y + } + if diff.Z < 0 { + diff.Z = -diff.Z + } + return diff +} + +// isZero returns true if the Acceleration is zero +func (a Acceleration) isZero() bool { + return a.X == 0 && a.Y == 0 && a.Z == 0 +} + +// String returns a string representation of the Acceleration +func (a Acceleration) String() string { + return fmt.Sprintf("X:%d Y:%d Z:%d", a.X, a.Y, a.Z) +} diff --git a/adxl345/doc.go b/adxl345/doc.go new file mode 100644 index 0000000..9c2e32e --- /dev/null +++ b/adxl345/doc.go @@ -0,0 +1,10 @@ +// Copyright 2018 The Periph Authors. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +// Package adxl345 controls an ADXL345 3-axis accelerometer over SPI. +// +// # Datasheet +// +// http://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf +package adxl345 diff --git a/adxl345/example/example.go b/adxl345/example/example.go new file mode 100644 index 0000000..b87341a --- /dev/null +++ b/adxl345/example/example.go @@ -0,0 +1,51 @@ +package example + +import ( + "fmt" + "log" + "periph.io/x/conn/v3/spi/spireg" + "periph.io/x/devices/v3/adxl345" + "periph.io/x/host/v3" + "time" +) + +// Example reads the acceleration values every 30ms for 3 seconds. +func Example() { + + // Initialize the host + // Make sure periph is initialized. + if _, err := host.Init(); err != nil { + log.Fatal(err) + } + + // Use spireg SPI port registry to find the first available SPI bus. + p, err := spireg.Open("") + if err != nil { + log.Fatal(err) + } + + defer p.Close() + + o := adxl345.DefaultOpts + d, err := adxl345.New(p, &o) + if err != nil { + panic(err) + } + + // use a ticker to read the acceleration values every 200ms + ticker := time.NewTicker(30 * time.Millisecond) + defer ticker.Stop() + + // stop after 3 seconds + stop := time.After(3 * time.Second) + + for { + select { + case <-stop: + return + case <-ticker.C: + a := d.Update() + fmt.Println(a) + } + } +} From d3ad1aac1e54381766cde130a522e22ea48bbc14 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 11:31:41 +0100 Subject: [PATCH 02/13] Added sensitivity option. --- adxl345/adxl345.go | 46 +++++++++++++++++++++++++++++++------- adxl345/example/example.go | 2 ++ 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 3d5c129..8cd5e54 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -7,10 +7,15 @@ import ( "periph.io/x/conn/v3/spi" ) +type Sensitivity byte + const ( DeviceID = 0x00 // Device ID, expected to be 0xE5 when using ADXL345 - // 0x01 to 0x1C are reserved for future use + S2G Sensitivity = 0x00 // Sensitivity at 2g + S4G Sensitivity = 0x01 // Sensitivity at 4g + S8G Sensitivity = 0x02 // Sensitivity at 8g + S16G Sensitivity = 0x03 // Sensitivity at 16g ThreshTap = 0x1D // Tap threshold OfsX = 0x1E // X-axis offset @@ -60,13 +65,15 @@ var ( ) var DefaultOpts = Opts{ - TurnOnOnStart: true, - ExpectedDevid: 0xE5, + TurnOnOnStart: true, + ExpectedDeviceID: 0xE5, + Sensitivity: S2G, } type Opts struct { - TurnOnOnStart bool // Turn on the device in measurement mode on start. - ExpectedDevid byte // Expected device ID used to verify that the device is an ADXL345. + TurnOnOnStart bool // Turn on the device in measurement mode on start. + ExpectedDeviceID byte // Expected device ID used to verify that the device is an ADXL345. + Sensitivity Sensitivity // Sensitivity of the device (2G, 4G, 8G, 16G) } // Dev is a driver for the ADXL345 accelerometer @@ -77,7 +84,7 @@ type Dev struct { } func (d *Dev) String() string { - return fmt.Sprintf("ADXL345") + return fmt.Sprintf("ADXL345{Sensitivity:%d}", d.Sensitivity()) } // New creates a new ADXL345 Dev or returns an error. @@ -101,14 +108,37 @@ func New(p spi.Port, o *Opts) (*Dev, error) { return nil, err } } + if o.Sensitivity != S2G { // default + err = d.setSensitivity(o.Sensitivity) + if err != nil { + return nil, err + } + } // Verify that the device is an ADXL345. rx, _ := d.RawReadRegister(DeviceID) - if rx[1] != o.ExpectedDevid { - return nil, fmt.Errorf("wrong device connected should be an adxl345 should be\"%#x\" rx0=\"%#x\" rx1=\"%#x\"", o.ExpectedDevid, rx[0], rx[1]) + if rx[1] != o.ExpectedDeviceID { + return nil, fmt.Errorf("wrong device connected should be an adxl345 should be\"%#x\" rx0=\"%#x\" rx1=\"%#x\"", o.ExpectedDeviceID, rx[0], rx[1]) } return d, nil } +// SetSensitivity sets the sensitivity of the ADXL345. +// The sensitivity parameter should be one of 2, 4, 8, or 16, representing ±2g, ±4g, ±8g, or ±16g respectively. +func (d *Dev) setSensitivity(sensitivity Sensitivity) error { + switch sensitivity { + case S2G, S4G, S8G, S16G: + // Write to the DataFormat register + return d.WriteRegister(DataFormat, byte(sensitivity)) + default: + return fmt.Errorf("invalid sensitivity: %d. Valid values are 2, 4, 8, 16", sensitivity) + } +} + +func (d *Dev) Sensitivity() Sensitivity { + rx, _ := d.RawReadRegister(DataFormat) + return Sensitivity(rx[1]) +} + // TurnOn turns on the measurement mode of the ADXL345. // This is required before reading data from the device. func (d *Dev) TurnOn() error { diff --git a/adxl345/example/example.go b/adxl345/example/example.go index b87341a..fea5c47 100644 --- a/adxl345/example/example.go +++ b/adxl345/example/example.go @@ -32,6 +32,8 @@ func Example() { panic(err) } + fmt.Println(d.String()) + // use a ticker to read the acceleration values every 200ms ticker := time.NewTicker(30 * time.Millisecond) defer ticker.Stop() From 006e2f063cf60c5c4c033ebdf938ae76d25c4efa Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 12:13:16 +0100 Subject: [PATCH 03/13] Keep it simple remove useless Acceleration func --- adxl345/adxl345.go | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 8cd5e54..2ea4927 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -214,35 +214,6 @@ type Acceleration struct { Z int16 } -// sum returns the sum of the accelerations on the three axes -func (a Acceleration) sum() int64 { - return int64(a.X) + int64(a.Y) + int64(a.Z) -} - -// diff returns the absolute difference between the two Acceleration -func (a Acceleration) diff(b Acceleration) Acceleration { - diff := Acceleration{ - X: a.X - b.X, - Y: a.Y - b.Y, - Z: a.Z - b.Z, - } - if diff.X < 0 { - diff.X = -diff.X - } - if diff.Y < 0 { - diff.Y = -diff.Y - } - if diff.Z < 0 { - diff.Z = -diff.Z - } - return diff -} - -// isZero returns true if the Acceleration is zero -func (a Acceleration) isZero() bool { - return a.X == 0 && a.Y == 0 && a.Z == 0 -} - // String returns a string representation of the Acceleration func (a Acceleration) String() string { return fmt.Sprintf("X:%d Y:%d Z:%d", a.X, a.Y, a.Z) From 76bf27630756751f73f6b841bf9a279fd63ef4b7 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 12:35:12 +0100 Subject: [PATCH 04/13] Expose the simpliest api possible. --- adxl345/adxl345.go | 50 ++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 2ea4927..d1eedce 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -79,12 +79,13 @@ type Opts struct { // Dev is a driver for the ADXL345 accelerometer // It uses the SPI interface to communicate with the device. type Dev struct { - name string - s spi.Conn + name string + s spi.Conn + sensitivity Sensitivity } func (d *Dev) String() string { - return fmt.Sprintf("ADXL345{Sensitivity:%d}", d.Sensitivity()) + return fmt.Sprintf("ADXL345{Sensitivity:%d}", d.sensitivity) } // New creates a new ADXL345 Dev or returns an error. @@ -115,7 +116,7 @@ func New(p spi.Port, o *Opts) (*Dev, error) { } } // Verify that the device is an ADXL345. - rx, _ := d.RawReadRegister(DeviceID) + rx, _ := d.ReadRaw(DeviceID) if rx[1] != o.ExpectedDeviceID { return nil, fmt.Errorf("wrong device connected should be an adxl345 should be\"%#x\" rx0=\"%#x\" rx1=\"%#x\"", o.ExpectedDeviceID, rx[0], rx[1]) } @@ -128,26 +129,22 @@ func (d *Dev) setSensitivity(sensitivity Sensitivity) error { switch sensitivity { case S2G, S4G, S8G, S16G: // Write to the DataFormat register - return d.WriteRegister(DataFormat, byte(sensitivity)) + d.sensitivity = sensitivity + return d.Write(DataFormat, byte(sensitivity)) default: return fmt.Errorf("invalid sensitivity: %d. Valid values are 2, 4, 8, 16", sensitivity) } } -func (d *Dev) Sensitivity() Sensitivity { - rx, _ := d.RawReadRegister(DataFormat) - return Sensitivity(rx[1]) -} - // TurnOn turns on the measurement mode of the ADXL345. // This is required before reading data from the device. func (d *Dev) TurnOn() error { - return d.WriteRegister(PowerCtl, 0x08) + return d.Write(PowerCtl, 0x08) } // TurnOff turns off the measurement mode of the ADXL345. func (d *Dev) TurnOff() error { - return d.WriteRegister(PowerCtl, 0x00) + return d.Write(PowerCtl, 0x00) } // Update reads the acceleration values from the ADXL345. @@ -168,25 +165,22 @@ func (d *Dev) Update() Acceleration { // The ADXL345 combines both registers to deliver 16-bit output for each acceleration axis. // A similar approach is used for the Y and Z axes. This technique provides higher precision in the measurements. func (d *Dev) readAndCombine(reg1, reg2 byte) int16 { - low, _ := d.ReadRegister(reg1) - high, _ := d.ReadRegister(reg2) + low, _ := d.Read(reg1) + high, _ := d.Read(reg2) return int16(uint16(high)<<8) | int16(low) } -// ReadRegister reads a 16-bit value from the specified register address. -func (d *Dev) ReadRegister(regAddress byte) (int16, error) { - // Send a two-byte sequence: - // - The first byte contains the address with bit 7 set high to indicate read op - // - The second byte is a "don't care" value, usually zero - tx := []byte{regAddress | 0x80, 0x00} - rx := make([]byte, len(tx)) - err := d.s.Tx(tx, rx) - r := int16(binary.LittleEndian.Uint16(rx)) - return r, err +// Read reads a 16-bit value from the specified register address. +func (d *Dev) Read(regAddress byte) (int16, error) { + rx, err := d.ReadRaw(regAddress) + if err != nil { + return 0, err + } + return int16(binary.LittleEndian.Uint16(rx)), nil } -// RawReadRegister reads a []byte value from the specified register address. -func (d *Dev) RawReadRegister(regAddress byte) ([]byte, error) { +// ReadRaw reads a []byte value from the specified register address. +func (d *Dev) ReadRaw(regAddress byte) ([]byte, error) { // Send a two-byte sequence: // - The first byte contains the address with bit 7 set high to indicate read op // - The second byte is a "don't care" value, usually zero @@ -196,8 +190,8 @@ func (d *Dev) RawReadRegister(regAddress byte) ([]byte, error) { return rx, err } -// WriteRegister writes a 1 byte value to the specified register address. -func (d *Dev) WriteRegister(regAddress byte, value byte) error { +// Write writes a 1 byte value to the specified register address. +func (d *Dev) Write(regAddress byte, value byte) error { // Prepare a 2-byte buffer with the register address and the desired value. tx := []byte{regAddress, value} // Prepare a receiving buffer of the same size as the transmit buffer. From 9f4770f8c7770987f5f950c5b4a427b8eea5ce22 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 12:41:41 +0100 Subject: [PATCH 05/13] Added a bunch of clarifications --- adxl345/adxl345.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index d1eedce..81f1741 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -152,19 +152,20 @@ func (d *Dev) TurnOff() error { // This is a simple synchronous implementation. func (d *Dev) Update() Acceleration { return Acceleration{ - X: d.readAndCombine(DataX0, DataX1), - Y: d.readAndCombine(DataY0, DataY1), - Z: d.readAndCombine(DataZ0, DataZ1), + X: d.ReadAndCombine(DataX0, DataX1), + Y: d.ReadAndCombine(DataY0, DataY1), + Z: d.ReadAndCombine(DataZ0, DataZ1), } } -// readAndCombine combines two registers to form a 16-bit value. -// Example: -// `DATAX0` is the address of the lower byte (LSB, least significant byte) of the X-axis data -// `DATAX1` is the address of the upper byte (MSB, most significant byte) of the X-axis data +// ReadAndCombine combines two registers to form a 16-bit value. +// The ADXL345 uses two 8-bit registers to store the output data for each axis. +// X := d.ReadAndCombine(DataX0, DataX1) where: +// `DataX0` is the address of the lower byte (LSB, least significant byte) +// `DataX1` is the address of the upper byte (MSB, most significant byte) // The ADXL345 combines both registers to deliver 16-bit output for each acceleration axis. // A similar approach is used for the Y and Z axes. This technique provides higher precision in the measurements. -func (d *Dev) readAndCombine(reg1, reg2 byte) int16 { +func (d *Dev) ReadAndCombine(reg1, reg2 byte) int16 { low, _ := d.Read(reg1) high, _ := d.Read(reg2) return int16(uint16(high)<<8) | int16(low) From 75b1480cb38e21c9de534808fd4af8a3799eddb4 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 14:13:14 +0100 Subject: [PATCH 06/13] Sensitivity String returns a human readable value --- adxl345/adxl345.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 81f1741..f7542f4 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -85,7 +85,7 @@ type Dev struct { } func (d *Dev) String() string { - return fmt.Sprintf("ADXL345{Sensitivity:%d}", d.sensitivity) + return fmt.Sprintf("ADXL345{Sensitivity:%s}", d.sensitivity) } // New creates a new ADXL345 Dev or returns an error. @@ -213,3 +213,18 @@ type Acceleration struct { func (a Acceleration) String() string { return fmt.Sprintf("X:%d Y:%d Z:%d", a.X, a.Y, a.Z) } + +func (s Sensitivity) String() string { + switch s { + case S2G: + return "+/-2g" + case S4G: + return "+/-4g" + case S8G: + return "+/-8g" + case S16G: + return "+/-16g" + default: + return "unsupported" + } +} From 7e0a946901ea1cac8ff0e26ea7b569e4ffea198c Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 15:46:19 +0100 Subject: [PATCH 07/13] - Mark the register constants more explicitly. - Moved the Sensitivity constants to a dedicated section. - SpiFrequency is set to 2Mz ( ADXL345 supports up to 5Mz ) - Removed the TurnOnOnStart options, we start measuring on instantiation. - Minor typo and example.go fix. --- adxl345/adxl345.go | 42 +++++++++++++++++++++++--------------- adxl345/example/example.go | 3 +-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index f7542f4..186869b 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -9,14 +9,12 @@ import ( type Sensitivity byte +// The following constants are register used by the ADXL345 +// Check the table 19 of the datasheet for more details. +// https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf const ( DeviceID = 0x00 // Device ID, expected to be 0xE5 when using ADXL345 - S2G Sensitivity = 0x00 // Sensitivity at 2g - S4G Sensitivity = 0x01 // Sensitivity at 4g - S8G Sensitivity = 0x02 // Sensitivity at 8g - S16G Sensitivity = 0x03 // Sensitivity at 16g - ThreshTap = 0x1D // Tap threshold OfsX = 0x1E // X-axis offset OfsY = 0x1F // Y-axis offset @@ -57,21 +55,29 @@ const ( ) -// DefaultSpiFrequency is the default SPI frequency used to communicate with the device. +// Sensitivity constants represents the sensitivity of the ADXL345. +// The ADXL345 supports 4 sensitivity settings, ±2g, ±4g, ±8g, and ±16g, with the default being ±2g. +// Sensitivity is an option that can be set at initialization in Opts. +// You can set the sensitivity of the ADXL345 with the DataFormat register. +const ( + S2G Sensitivity = 0x00 // Sensitivity at 2g + S4G Sensitivity = 0x01 // Sensitivity at 4g + S8G Sensitivity = 0x02 // Sensitivity at 8g + S16G Sensitivity = 0x03 // Sensitivity at 16g +) + var ( - SpiFrequency = physic.KiloHertz * 50 + SpiFrequency = physic.MegaHertz * 2 SpiMode = spi.Mode3 // Defines the base clock signal, along with the polarity and phase of the data signal. SpiBits = 8 ) var DefaultOpts = Opts{ - TurnOnOnStart: true, ExpectedDeviceID: 0xE5, Sensitivity: S2G, } type Opts struct { - TurnOnOnStart bool // Turn on the device in measurement mode on start. ExpectedDeviceID byte // Expected device ID used to verify that the device is an ADXL345. Sensitivity Sensitivity // Sensitivity of the device (2G, 4G, 8G, 16G) } @@ -79,8 +85,10 @@ type Opts struct { // Dev is a driver for the ADXL345 accelerometer // It uses the SPI interface to communicate with the device. type Dev struct { - name string - s spi.Conn + name string + s spi.Conn + // The sensitivity of the device (2G, 4G, 8G, 16G) + // Set to 2G by default, can be changed in the Opts at initialization. sensitivity Sensitivity } @@ -103,11 +111,9 @@ func New(p spi.Port, o *Opts) (*Dev, error) { name: "ADXL345", s: c, } - if o.TurnOnOnStart { - err = d.TurnOn() - if err != nil { - return nil, err - } + err = d.TurnOn() + if err != nil { + return nil, err } if o.Sensitivity != S2G { // default err = d.setSensitivity(o.Sensitivity) @@ -173,7 +179,9 @@ func (d *Dev) ReadAndCombine(reg1, reg2 byte) int16 { // Read reads a 16-bit value from the specified register address. func (d *Dev) Read(regAddress byte) (int16, error) { - rx, err := d.ReadRaw(regAddress) + tx := []byte{regAddress | 0x80, 0x00} + rx := make([]byte, len(tx)) + err := d.s.Tx(tx, rx) if err != nil { return 0, err } diff --git a/adxl345/example/example.go b/adxl345/example/example.go index fea5c47..01bbc3d 100644 --- a/adxl345/example/example.go +++ b/adxl345/example/example.go @@ -26,8 +26,7 @@ func Example() { defer p.Close() - o := adxl345.DefaultOpts - d, err := adxl345.New(p, &o) + d, err := adxl345.New(p, &adxl345.DefaultOpts) if err != nil { panic(err) } From 99ce1e25a332448094519cc257c2ee64414ed390 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 16:21:17 +0100 Subject: [PATCH 08/13] Licence compliance, adding Copyright 2023 The Periph Authors. All rights reserved.... --- adxl345/adxl345.go | 7 +++++++ adxl345/doc.go | 2 +- adxl345/example/example.go | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 186869b..c4f60ba 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -1,8 +1,13 @@ +// Copyright 2023 The Periph Authors. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + package adxl345 import ( "encoding/binary" "fmt" + "periph.io/x/conn/v3/mmr" "periph.io/x/conn/v3/physic" "periph.io/x/conn/v3/spi" ) @@ -85,6 +90,7 @@ type Opts struct { // Dev is a driver for the ADXL345 accelerometer // It uses the SPI interface to communicate with the device. type Dev struct { + c mmr.Dev16 name string s spi.Conn // The sensitivity of the device (2G, 4G, 8G, 16G) @@ -174,6 +180,7 @@ func (d *Dev) Update() Acceleration { func (d *Dev) ReadAndCombine(reg1, reg2 byte) int16 { low, _ := d.Read(reg1) high, _ := d.Read(reg2) + return int16(uint16(high)<<8) | int16(low) } diff --git a/adxl345/doc.go b/adxl345/doc.go index 9c2e32e..2fa3231 100644 --- a/adxl345/doc.go +++ b/adxl345/doc.go @@ -1,4 +1,4 @@ -// Copyright 2018 The Periph Authors. All rights reserved. +// Copyright 2032 The Periph Authors. All rights reserved. // Use of this source code is governed under the Apache License, Version 2.0 // that can be found in the LICENSE file. diff --git a/adxl345/example/example.go b/adxl345/example/example.go index 01bbc3d..7490af8 100644 --- a/adxl345/example/example.go +++ b/adxl345/example/example.go @@ -1,3 +1,7 @@ +// Copyright 2023 The Periph Authors. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + package example import ( From a5a4a2c870e71ccec20f01aa90aad5f3ce2c7ce4 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 16:29:23 +0100 Subject: [PATCH 09/13] Doc --- adxl345/adxl345.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index c4f60ba..e707095 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -217,7 +217,13 @@ func (d *Dev) Write(regAddress byte, value byte) error { return err } -// Acceleration represents the acceleration on the three axes +// Acceleration represents the acceleration on the three axes X,Y,Z. +// The sensitivity can be set to different levels: ±2g, ±4g, ±8g, or ±16g. (S2G, S4G, S8G, S16G) +// The output are 16-bit integers, so the device measures between -32768 and +32767 for each axis. +// For example, if the sensitivity is set to ±2g and you're getting a reading of 16384 on the X axis, that would correspond to 1g of acceleration along the X axis. +// To convert the raw values to a physical unit (like g or m/s²), you would need to know the sensitivity setting of your device. +// For instance, if your sensitivity is set to ±2g, the conversion factor would be 2 / 32768 = 0.000061g per count. +// So, you would multiply the raw acceleration values by this factor to get the acceleration in `g`. type Acceleration struct { X int16 Y int16 @@ -229,6 +235,7 @@ func (a Acceleration) String() string { return fmt.Sprintf("X:%d Y:%d Z:%d", a.X, a.Y, a.Z) } +// Sensitivity returns the sensitivity of the device as a human-readable string. func (s Sensitivity) String() string { switch s { case S2G: From b62bbe245f514036cd644abb6eaad5d5d2ea3244 Mon Sep 17 00:00:00 2001 From: bpds Date: Thu, 28 Dec 2023 16:44:01 +0100 Subject: [PATCH 10/13] Prepare to support I2C in the future --- adxl345/adxl345.go | 6 ++---- adxl345/example/example.go | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index e707095..54bf23b 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -7,7 +7,6 @@ package adxl345 import ( "encoding/binary" "fmt" - "periph.io/x/conn/v3/mmr" "periph.io/x/conn/v3/physic" "periph.io/x/conn/v3/spi" ) @@ -90,7 +89,6 @@ type Opts struct { // Dev is a driver for the ADXL345 accelerometer // It uses the SPI interface to communicate with the device. type Dev struct { - c mmr.Dev16 name string s spi.Conn // The sensitivity of the device (2G, 4G, 8G, 16G) @@ -102,12 +100,12 @@ func (d *Dev) String() string { return fmt.Sprintf("ADXL345{Sensitivity:%s}", d.sensitivity) } -// New creates a new ADXL345 Dev or returns an error. +// NewSpi creates a new ADXL345 Dev with a spi connection or returns an error. // The bus and chip parameters define the SPI bus and chip select to use. // The SPI s is configured. // The device is turned on. // The device is verified to be an ADXL345. -func New(p spi.Port, o *Opts) (*Dev, error) { +func NewSpi(p spi.Port, o *Opts) (*Dev, error) { // Convert the spi.Port into a spi.Conn so it can be used for communication. c, err := p.Connect(SpiFrequency, SpiMode, SpiBits) if err != nil { diff --git a/adxl345/example/example.go b/adxl345/example/example.go index 7490af8..595a676 100644 --- a/adxl345/example/example.go +++ b/adxl345/example/example.go @@ -30,7 +30,7 @@ func Example() { defer p.Close() - d, err := adxl345.New(p, &adxl345.DefaultOpts) + d, err := adxl345.NewSpi(p, &adxl345.DefaultOpts) if err != nil { panic(err) } From 9ddc05227dde4891954613ab5506a0444b18e86e Mon Sep 17 00:00:00 2001 From: bpds Date: Fri, 29 Dec 2023 10:16:27 +0100 Subject: [PATCH 11/13] Some adxlXXX device may be well-supported so i added an internal switch to automatically recognize the device or enable to test one by declaring its expected value. --- adxl345/adxl345.go | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 54bf23b..dc56e6b 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -11,6 +11,7 @@ import ( "periph.io/x/conn/v3/spi" ) +// Sensitivity represents the sensitivity of the Accelerometer. type Sensitivity byte // The following constants are register used by the ADXL345 @@ -70,6 +71,13 @@ const ( S16G Sensitivity = 0x03 // Sensitivity at 16g ) +// Currently tested devices + +const ( + AdxlXXX = 0x00 // No specific expectation + Adxl345 = 0xE5 // Expecting an Adxl345 +) + var ( SpiFrequency = physic.MegaHertz * 2 SpiMode = spi.Mode3 // Defines the base clock signal, along with the polarity and phase of the data signal. @@ -77,7 +85,7 @@ var ( ) var DefaultOpts = Opts{ - ExpectedDeviceID: 0xE5, + ExpectedDeviceID: AdxlXXX, // No specific expectation by default Sensitivity: S2G, } @@ -97,7 +105,7 @@ type Dev struct { } func (d *Dev) String() string { - return fmt.Sprintf("ADXL345{Sensitivity:%s}", d.sensitivity) + return fmt.Sprintf("%s{Sensitivity:%s}", d.name, d.sensitivity) } // NewSpi creates a new ADXL345 Dev with a spi connection or returns an error. @@ -112,8 +120,7 @@ func NewSpi(p spi.Port, o *Opts) (*Dev, error) { return nil, err } d := &Dev{ - name: "ADXL345", - s: c, + s: c, } err = d.TurnOn() if err != nil { @@ -125,12 +132,18 @@ func NewSpi(p spi.Port, o *Opts) (*Dev, error) { return nil, err } } - // Verify that the device is an ADXL345. + // Verify that the device Id rx, _ := d.ReadRaw(DeviceID) - if rx[1] != o.ExpectedDeviceID { - return nil, fmt.Errorf("wrong device connected should be an adxl345 should be\"%#x\" rx0=\"%#x\" rx1=\"%#x\"", o.ExpectedDeviceID, rx[0], rx[1]) + switch rx[1] { + case Adxl345: + d.name = "adxl345" + return d, nil + case o.ExpectedDeviceID: + d.name = fmt.Sprintf("expected%#x", o.ExpectedDeviceID) + return d, nil + default: + return nil, fmt.Errorf("unrecognized device expected=\"%#x\" found=\"%#x\" ", o.ExpectedDeviceID, rx[0]) } - return d, nil } // SetSensitivity sets the sensitivity of the ADXL345. @@ -245,6 +258,6 @@ func (s Sensitivity) String() string { case S16G: return "+/-16g" default: - return "unsupported" + return fmt.Sprintf("unknown sensitivity: %#x", s) } } From 5eba749b5f5d77e06a565c25b69b63e06f65f639 Mon Sep 17 00:00:00 2001 From: bpds Date: Fri, 29 Dec 2023 14:46:53 +0100 Subject: [PATCH 12/13] =?UTF-8?q?Added=20I=C2=B2C=20support.=20-=20Removed?= =?UTF-8?q?=20useless=20ReadRaw=20-=20Changed=20the=20scope=20of=20ReadAnd?= =?UTF-8?q?Combine=20to=20private=20readAndCombine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- adxl345/adxl345.go | 108 ++++++++++++++++++++++-------------- adxl345/example/example.go | 56 ------------------- adxl345/example/examples.go | 96 ++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 99 deletions(-) delete mode 100644 adxl345/example/example.go create mode 100644 adxl345/example/examples.go diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index dc56e6b..53dd683 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -7,6 +7,8 @@ package adxl345 import ( "encoding/binary" "fmt" + "periph.io/x/conn/v3" + "periph.io/x/conn/v3/i2c" "periph.io/x/conn/v3/physic" "periph.io/x/conn/v3/spi" ) @@ -74,7 +76,7 @@ const ( // Currently tested devices const ( - AdxlXXX = 0x00 // No specific expectation + AdxlXXX = 0x01 // No specific expectation. For non-detected devices the response is 0x00 Adxl345 = 0xE5 // Expecting an Adxl345 ) @@ -97,22 +99,44 @@ type Opts struct { // Dev is a driver for the ADXL345 accelerometer // It uses the SPI interface to communicate with the device. type Dev struct { - name string - s spi.Conn + c conn.Conn + name string + isSPI bool // The sensitivity of the device (2G, 4G, 8G, 16G) // Set to 2G by default, can be changed in the Opts at initialization. sensitivity Sensitivity } +func (d *Dev) Mode() string { + if d.isSPI { + return "SPI" + } else { + return "I²C" + } +} + func (d *Dev) String() string { - return fmt.Sprintf("%s{Sensitivity:%s}", d.name, d.sensitivity) + return fmt.Sprintf("%s{Sensitivity:%s, Mode:%s}", d.name, d.sensitivity, d.Mode()) } -// NewSpi creates a new ADXL345 Dev with a spi connection or returns an error. -// The bus and chip parameters define the SPI bus and chip select to use. -// The SPI s is configured. -// The device is turned on. -// The device is verified to be an ADXL345. +// NewI2C returns an object that communicates over I²C to ADXL345 +// accelerometer. +// +// The device is automatically turned on and the sensitivity is set to the Opts.Sensitivity. +func NewI2C(b i2c.Bus, addr uint16, opts *Opts) (*Dev, error) { + d := &Dev{ + c: &i2c.Dev{Bus: b, Addr: addr}, + isSPI: false} + if err := d.makeDev(opts); err != nil { + return nil, err + } + return d, nil +} + +// NewSpi returns an object that communicates over spi to ADXL345 +// accelerometer. +// +// The device is automatically turned on and the sensitivity is set to the Opts.Sensitivity. func NewSpi(p spi.Port, o *Opts) (*Dev, error) { // Convert the spi.Port into a spi.Conn so it can be used for communication. c, err := p.Connect(SpiFrequency, SpiMode, SpiBits) @@ -120,29 +144,42 @@ func NewSpi(p spi.Port, o *Opts) (*Dev, error) { return nil, err } d := &Dev{ - s: c, + c: c, + isSPI: true, } - err = d.TurnOn() + err = d.makeDev(o) if err != nil { return nil, err } + return d, nil +} + +// makeDev turns on with the expected sensitivity and verifies if it is a supported device. +func (d *Dev) makeDev(o *Opts) error { + err := d.TurnOn() + if err != nil { + return err + } if o.Sensitivity != S2G { // default err = d.setSensitivity(o.Sensitivity) if err != nil { - return nil, err + return err } } // Verify that the device Id - rx, _ := d.ReadRaw(DeviceID) - switch rx[1] { + rx, err := d.Read(DeviceID) + if err != nil { + return fmt.Errorf("unable to read the deviceID \"%s\"", err.Error()) + } + switch byte(rx & 0xff) { case Adxl345: d.name = "adxl345" - return d, nil + return nil case o.ExpectedDeviceID: d.name = fmt.Sprintf("expected%#x", o.ExpectedDeviceID) - return d, nil + return nil default: - return nil, fmt.Errorf("unrecognized device expected=\"%#x\" found=\"%#x\" ", o.ExpectedDeviceID, rx[0]) + return fmt.Errorf("unrecognized device expected=\"%#02x\" or \"%#02x\"found=\"%#02x\" ", o.ExpectedDeviceID, Adxl345, rx) } } @@ -175,57 +212,42 @@ func (d *Dev) TurnOff() error { // This is a simple synchronous implementation. func (d *Dev) Update() Acceleration { return Acceleration{ - X: d.ReadAndCombine(DataX0, DataX1), - Y: d.ReadAndCombine(DataY0, DataY1), - Z: d.ReadAndCombine(DataZ0, DataZ1), + X: d.readAndCombine(DataX0, DataX1), + Y: d.readAndCombine(DataY0, DataY1), + Z: d.readAndCombine(DataZ0, DataZ1), } } -// ReadAndCombine combines two registers to form a 16-bit value. +// readAndCombine combines two registers to form a 16-bit value. // The ADXL345 uses two 8-bit registers to store the output data for each axis. -// X := d.ReadAndCombine(DataX0, DataX1) where: +// X := d.readAndCombine(DataX0, DataX1) where: // `DataX0` is the address of the lower byte (LSB, least significant byte) // `DataX1` is the address of the upper byte (MSB, most significant byte) // The ADXL345 combines both registers to deliver 16-bit output for each acceleration axis. // A similar approach is used for the Y and Z axes. This technique provides higher precision in the measurements. -func (d *Dev) ReadAndCombine(reg1, reg2 byte) int16 { +func (d *Dev) readAndCombine(reg1, reg2 byte) int16 { low, _ := d.Read(reg1) high, _ := d.Read(reg2) - return int16(uint16(high)<<8) | int16(low) } // Read reads a 16-bit value from the specified register address. func (d *Dev) Read(regAddress byte) (int16, error) { + // Send a two-byte sequence: + // - The first byte contains the address with bit 7 set high to indicate read op + // - The second byte is a "don't care" value, usually zero tx := []byte{regAddress | 0x80, 0x00} rx := make([]byte, len(tx)) - err := d.s.Tx(tx, rx) + err := d.c.Tx(tx, rx) if err != nil { return 0, err } return int16(binary.LittleEndian.Uint16(rx)), nil } -// ReadRaw reads a []byte value from the specified register address. -func (d *Dev) ReadRaw(regAddress byte) ([]byte, error) { - // Send a two-byte sequence: - // - The first byte contains the address with bit 7 set high to indicate read op - // - The second byte is a "don't care" value, usually zero - tx := []byte{regAddress | 0x80, 0x00} - rx := make([]byte, len(tx)) - err := d.s.Tx(tx, rx) - return rx, err -} - // Write writes a 1 byte value to the specified register address. func (d *Dev) Write(regAddress byte, value byte) error { - // Prepare a 2-byte buffer with the register address and the desired value. - tx := []byte{regAddress, value} - // Prepare a receiving buffer of the same size as the transmit buffer. - rx := make([]byte, len(tx)) - // Perform the transfer. We expect the SPI device to write back an acknowledgement. - err := d.s.Tx(tx, rx) - return err + return d.c.Tx([]byte{regAddress, value}, nil) } // Acceleration represents the acceleration on the three axes X,Y,Z. diff --git a/adxl345/example/example.go b/adxl345/example/example.go deleted file mode 100644 index 595a676..0000000 --- a/adxl345/example/example.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2023 The Periph Authors. All rights reserved. -// Use of this source code is governed under the Apache License, Version 2.0 -// that can be found in the LICENSE file. - -package example - -import ( - "fmt" - "log" - "periph.io/x/conn/v3/spi/spireg" - "periph.io/x/devices/v3/adxl345" - "periph.io/x/host/v3" - "time" -) - -// Example reads the acceleration values every 30ms for 3 seconds. -func Example() { - - // Initialize the host - // Make sure periph is initialized. - if _, err := host.Init(); err != nil { - log.Fatal(err) - } - - // Use spireg SPI port registry to find the first available SPI bus. - p, err := spireg.Open("") - if err != nil { - log.Fatal(err) - } - - defer p.Close() - - d, err := adxl345.NewSpi(p, &adxl345.DefaultOpts) - if err != nil { - panic(err) - } - - fmt.Println(d.String()) - - // use a ticker to read the acceleration values every 200ms - ticker := time.NewTicker(30 * time.Millisecond) - defer ticker.Stop() - - // stop after 3 seconds - stop := time.After(3 * time.Second) - - for { - select { - case <-stop: - return - case <-ticker.C: - a := d.Update() - fmt.Println(a) - } - } -} diff --git a/adxl345/example/examples.go b/adxl345/example/examples.go new file mode 100644 index 0000000..ca1e60c --- /dev/null +++ b/adxl345/example/examples.go @@ -0,0 +1,96 @@ +// Copyright 2023 The Periph Authors. All rights reserved. +// Use of this source code is governed under the Apache License, Version 2.0 +// that can be found in the LICENSE file. + +package example + +import ( + "fmt" + "log" + "periph.io/x/conn/v3/i2c/i2creg" + "periph.io/x/conn/v3/spi/spireg" + "periph.io/x/devices/v3/adxl345" + "periph.io/x/host/v3" + "time" +) + +// I2C uses an adxl345 device connected by I²C. +// it reads the acceleration values every 30ms for 30 seconds. +// You can i use `i2dctools` to find the I²C bus number +// e.g : sudo apt-get install i2c-tools +// +// sudo i2cdetect -y 1 +func I2C(addr uint16) { + + mustInitHost() + + // Use i2creg to find the first available I²C bus. + // Generally I2C1 on raspberry pi. + p, err := i2creg.Open("") + if err != nil { + log.Fatal(err) + } + fmt.Print(p.String()) + + defer p.Close() + + d, err := adxl345.NewI2C(p, addr, &adxl345.DefaultOpts) + if err != nil { + panic(err) + } + measure(d, 30*time.Second) +} + +// Spi uses an adxl345 device connected by SPI. +// it reads the acceleration values every 30ms for 30 seconds. +func Spi() { + + mustInitHost() + + // Use spireg SPI port registry to find the first available SPI bus. + p, err := spireg.Open("") + if err != nil { + log.Fatal(err) + } + + defer p.Close() + + d, err := adxl345.NewSpi(p, &adxl345.DefaultOpts) + if err != nil { + panic(err) + } + + measure(d, 30*time.Second) +} + +// mustInitHost Make sure host is initialized. +func mustInitHost() { + + if _, err := host.Init(); err != nil { + log.Fatal(err) + } +} + +// measure reads the acceleration values every 30ms for seconds +func measure(d *adxl345.Dev, duration time.Duration) { + + fmt.Println(d.String()) + + mode := d.Mode() + // use a ticker to read the acceleration values every 200ms + ticker := time.NewTicker(30 * time.Millisecond) + defer ticker.Stop() + + // stop after 3 seconds + stop := time.After(duration) + + for { + select { + case <-stop: + return + case <-ticker.C: + a := d.Update() + fmt.Println(mode, a) + } + } +} From 3dfa61987f582fb8c9fb3edfbee99c6e31073bed Mon Sep 17 00:00:00 2001 From: bpds Date: Fri, 29 Dec 2023 16:47:58 +0100 Subject: [PATCH 13/13] Fixing inconsistent Read of device id on multiple instantiation. --- adxl345/adxl345.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adxl345/adxl345.go b/adxl345/adxl345.go index 53dd683..59dac36 100644 --- a/adxl345/adxl345.go +++ b/adxl345/adxl345.go @@ -167,11 +167,13 @@ func (d *Dev) makeDev(o *Opts) error { } } // Verify that the device Id - rx, err := d.Read(DeviceID) + tx := []byte{DeviceID | 0x80, 0x00} + rx := make([]byte, len(tx)) + err = d.c.Tx(tx, rx) if err != nil { return fmt.Errorf("unable to read the deviceID \"%s\"", err.Error()) } - switch byte(rx & 0xff) { + switch rx[1] { case Adxl345: d.name = "adxl345" return nil