Skip to content

Commit

Permalink
Support for LIS3DH (#492)
Browse files Browse the repository at this point in the history
* sensor_lis2dw: add lis3dh sensor and i2c communication

Signed-off-by: Luke Vuksta <[email protected]>

* docs: Add lis2dw i2c and lis3dh

Signed-off-by: Luke Vuksta <[email protected]>

* atsamd: allow i2c rate to be 400kHz

Signed-off-by: Luke Vuksta <[email protected]>

* config: Add lis3dh to Duet3D 1LC sample config

Signed-off-by: Luke Vuksta <[email protected]>

---------

Signed-off-by: Luke Vuksta <[email protected]>
  • Loading branch information
Wulfsta authored Dec 23, 2024
1 parent 20d9035 commit 2ad3338
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 65 deletions.
9 changes: 9 additions & 0 deletions config/sample-duet3-1lc.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,14 @@ heater_temp: 50.0
pin: toolboard:PA9
z_offset: 20

[samd_sercom sercom_i2c]
sercom: sercom1
tx_pin: toolboard:PA16
clk_pin: toolboard:PA17

[lis3dh]
i2c_mcu: toolboard
i2c_bus: sercom1

[mcu toolboard]
canbus_uuid: 4b194673554e
45 changes: 43 additions & 2 deletions docs/Config_Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2068,8 +2068,40 @@ Support for LIS2DW accelerometers.

```
[lis2dw]
cs_pin:
# The SPI enable pin for the sensor. This parameter must be provided.
#cs_pin:
# The SPI enable pin for the sensor. This parameter must be provided
# if using SPI.
#spi_speed: 5000000
# The SPI speed (in hz) to use when communicating with the chip.
# The default is 5000000.
#spi_bus:
#spi_software_sclk_pin:
#spi_software_mosi_pin:
#spi_software_miso_pin:
# See the "common SPI settings" section for a description of the
# above parameters.
#i2c_address:
# Default is 25 (0x19). If SA0 is high, it would be 24 (0x18) instead.
#i2c_mcu:
#i2c_bus:
#i2c_software_scl_pin:
#i2c_software_sda_pin:
#i2c_speed: 400000
# See the "common I2C settings" section for a description of the
# above parameters. The default "i2c_speed" is 400000.
#axes_map: x, y, z
# See the "adxl345" section for information on this parameter.
```

### [lis3dh]

Support for LIS3DH accelerometers.

```
[lis3dh]
#cs_pin:
# The SPI enable pin for the sensor. This parameter must be provided
# if using SPI.
#spi_speed: 5000000
# The SPI speed (in hz) to use when communicating with the chip.
# The default is 5000000.
Expand All @@ -2079,6 +2111,15 @@ cs_pin:
#spi_software_miso_pin:
# See the "common SPI settings" section for a description of the
# above parameters.
#i2c_address:
# Default is 25 (0x19). If SA0 is high, it would be 24 (0x18) instead.
#i2c_mcu:
#i2c_bus:
#i2c_software_scl_pin:
#i2c_software_sda_pin:
#i2c_speed: 400000
# See the "common I2C settings" section for a description of the
# above parameters. The default "i2c_speed" is 400000.
#axes_map: x, y, z
# See the "adxl345" section for information on this parameter.
```
Expand Down
132 changes: 99 additions & 33 deletions klippy/extras/lis2dw.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import logging
from . import bus, adxl345, bulk_sensor

from . import adxl345, bulk_sensor, bus

# LIS2DW registers
REG_LIS2DW_WHO_AM_I_ADDR = 0x0F
REG_LIS2DW_CTRL_REG1_ADDR = 0x20
REG_LIS2DW_CTRL_REG2_ADDR = 0x21
REG_LIS2DW_CTRL_REG3_ADDR = 0x22
REG_LIS2DW_CTRL_REG4_ADDR = 0x23
REG_LIS2DW_CTRL_REG5_ADDR = 0x24
REG_LIS2DW_CTRL_REG6_ADDR = 0x25
REG_LIS2DW_STATUS_REG_ADDR = 0x27
REG_LIS2DW_OUT_XL_ADDR = 0x28
Expand All @@ -26,27 +29,61 @@
# REG_MOD_MULTI = 0x40

LIS2DW_DEV_ID = 0x44
LIS3DH_DEV_ID = 0x33

LIS_I2C_ADDR = 0x19

# Right shift for left justified registers.
FREEFALL_ACCEL = 9.80665
SCALE = FREEFALL_ACCEL * 1.952 / 4
LIS2DW_SCALE = FREEFALL_ACCEL * 1.952 / 4
LIS3DH_SCALE = FREEFALL_ACCEL * 3.906 / 16

BATCH_UPDATES = 0.100

# "Enums" that should be compatible with all python versions

LIS2DW_TYPE = "LIS2DW"
LIS3DH_TYPE = "LIS3DH"

SPI_SERIAL_TYPE = "spi"
I2C_SERIAL_TYPE = "i2c"


# Printer class that controls LIS2DW chip
class LIS2DW:
def __init__(self, config):
def __init__(self, config, lis_type):
self.printer = config.get_printer()
adxl345.AccelCommandHelper(config, self)
self.axes_map = adxl345.read_axes_map(config, SCALE, SCALE, SCALE)
self.data_rate = 1600
self.lis_type = lis_type
if self.lis_type == LIS2DW_TYPE:
self.axes_map = adxl345.read_axes_map(
config, LIS2DW_SCALE, LIS2DW_SCALE, LIS2DW_SCALE
)
self.data_rate = 1600
else:
self.axes_map = adxl345.read_axes_map(
config, LIS3DH_SCALE, LIS3DH_SCALE, LIS3DH_SCALE
)
self.data_rate = 1344
# Check for spi or i2c
if config.get("cs_pin", None) is not None:
self.bus_type = SPI_SERIAL_TYPE
else:
self.bus_type = I2C_SERIAL_TYPE
# Setup mcu sensor_lis2dw bulk query code
self.spi = bus.MCU_SPI_from_config(config, 3, default_speed=5000000)
self.mcu = mcu = self.spi.get_mcu()
if self.bus_type == SPI_SERIAL_TYPE:
self.bus = bus.MCU_SPI_from_config(config, 3, default_speed=5000000)
else:
self.bus = bus.MCU_I2C_from_config(
config, default_addr=LIS_I2C_ADDR, default_speed=400000
)
self.mcu = mcu = self.bus.get_mcu()
self.oid = oid = mcu.create_oid()
self.query_lis2dw_cmd = None
mcu.add_config_cmd(
"config_lis2dw oid=%d spi_oid=%d" % (oid, self.spi.get_oid())
"config_lis2dw oid=%d bus_oid=%d bus_oid_type=%s "
"lis_chip_type=%s"
% (oid, self.bus.get_oid(), self.bus_type, self.lis_type)
)
mcu.add_config_cmd(
"query_lis2dw oid=%d rest_ticks=0" % (oid,), on_restart=True
Expand All @@ -71,7 +108,7 @@ def __init__(self, config):
)

def _build_config(self):
cmdqueue = self.spi.get_command_queue()
cmdqueue = self.bus.get_command_queue()
self.query_lis2dw_cmd = self.mcu.lookup_command(
"query_lis2dw oid=%c rest_ticks=%u", cq=cmdqueue
)
Expand All @@ -86,12 +123,18 @@ def check_connected(self):
)

def read_reg(self, reg):
params = self.spi.spi_transfer([reg | REG_MOD_READ, 0x00])
response = bytearray(params["response"])
return response[1]
if self.bus_type == SPI_SERIAL_TYPE:
params = self.bus.spi_transfer([reg | REG_MOD_READ, 0x00])
response = bytearray(params["response"])
return response[1]
params = self.bus.i2c_read([reg], 1)
return bytearray(params["response"])[0]

def set_reg(self, reg, val, minclock=0):
self.spi.spi_send([reg, val & 0xFF], minclock=minclock)
if self.bus_type == SPI_SERIAL_TYPE:
self.bus.spi_send([reg, val & 0xFF], minclock=minclock)
else:
self.bus.i2c_write([reg, val & 0xFF], minclock=minclock)
stored_val = self.read_reg(reg)
if stored_val != val:
raise self.printer.command_error(
Expand Down Expand Up @@ -125,27 +168,50 @@ def _start_measurements(self):
# noise or wrong signal as a correctly initialized device
dev_id = self.read_reg(REG_LIS2DW_WHO_AM_I_ADDR)
logging.info("lis2dw_dev_id: %x", dev_id)
if dev_id != LIS2DW_DEV_ID:
raise self.printer.command_error(
"Invalid lis2dw id (got %x vs %x).\n"
"This is generally indicative of connection problems\n"
"(e.g. faulty wiring) or a faulty lis2dw chip."
% (dev_id, LIS2DW_DEV_ID)
)
# Setup chip in requested query rate
# ODR/2, +-16g, low-pass filter, Low-noise abled
self.set_reg(REG_LIS2DW_CTRL_REG6_ADDR, 0x34)
# Continuous mode: If the FIFO is full
# the new sample overwrites the older sample.
self.set_reg(REG_LIS2DW_FIFO_CTRL, 0xC0)
# High-Performance / Low-Power mode 1600/200 Hz
# High-Performance Mode (14-bit resolution)
self.set_reg(REG_LIS2DW_CTRL_REG1_ADDR, 0x94)

if self.lis_type == LIS2DW_TYPE:
if dev_id != LIS2DW_DEV_ID:
raise self.printer.command_error(
"Invalid lis2dw id (got %x vs %x).\n"
"This is generally indicative of connection problems\n"
"(e.g. faulty wiring) or a faulty lis2dw chip."
% (dev_id, LIS2DW_DEV_ID)
)
# Setup chip in requested query rate
# ODR/2, +-16g, low-pass filter, Low-noise abled
self.set_reg(REG_LIS2DW_CTRL_REG6_ADDR, 0x34)
# Continuous mode: If the FIFO is full
# the new sample overwrites the older sample.
self.set_reg(REG_LIS2DW_FIFO_CTRL, 0xC0)
# High-Performance / Low-Power mode 1600/200 Hz
# High-Performance Mode (14-bit resolution)
self.set_reg(REG_LIS2DW_CTRL_REG1_ADDR, 0x94)
else:
if dev_id != LIS3DH_DEV_ID:
raise self.printer.command_error(
"Invalid lis3dh id (got %x vs %x).\n"
"This is generally indicative of connection problems\n"
"(e.g. faulty wiring) or a faulty lis3dh chip."
% (dev_id, LIS3DH_DEV_ID)
)
# High Resolution / Low Power mode 1344/5376 Hz
# High Resolution mode (12-bit resolution)
# Enable X Y Z axes
self.set_reg(REG_LIS2DW_CTRL_REG1_ADDR, 0x97)
# Disable all filtering
self.set_reg(REG_LIS2DW_CTRL_REG2_ADDR, 0)
# Set +-8g, High Resolution mode
self.set_reg(REG_LIS2DW_CTRL_REG4_ADDR, 0x28)
# Enable FIFO
self.set_reg(REG_LIS2DW_CTRL_REG5_ADDR, 0x40)
# Stream mode
self.set_reg(REG_LIS2DW_FIFO_CTRL, 0x80)
# Start bulk reading
rest_ticks = self.mcu.seconds_to_clock(4.0 / self.data_rate)
self.query_lis2dw_cmd.send([self.oid, rest_ticks])
self.set_reg(REG_LIS2DW_FIFO_CTRL, 0xC0)
if self.lis_type == LIS2DW_TYPE:
self.set_reg(REG_LIS2DW_FIFO_CTRL, 0xC0)
else:
self.set_reg(REG_LIS2DW_FIFO_CTRL, 0x80)
logging.info("LIS2DW starting '%s' measurements", self.name)
# Initialize clock tracking
self.ffreader.note_start()
Expand All @@ -172,8 +238,8 @@ def _process_batch(self, eventtime):


def load_config(config):
return LIS2DW(config)
return LIS2DW(config, LIS2DW_TYPE)


def load_config_prefix(config):
return LIS2DW(config)
return LIS2DW(config, LIS2DW_TYPE)
14 changes: 14 additions & 0 deletions klippy/extras/lis3dh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Support for reading acceleration data from an LIS3DH chip
#
# Copyright (C) 2024 Luke Vuksta <[email protected]>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
from . import lis2dw


def load_config(config):
return lis2dw.LIS2DW(config, lis2dw.LIS3DH_TYPE)


def load_config_prefix(config):
return lis2dw.LIS2DW(config, lis2dw.LIS3DH_TYPE)
6 changes: 3 additions & 3 deletions src/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ config WANT_SENSORS
default y
config WANT_LIS2DW
bool
depends on HAVE_GPIO_SPI
depends on HAVE_GPIO_SPI || HAVE_GPIO_I2C
default y
config WANT_LDC1612
bool
Expand Down Expand Up @@ -151,8 +151,8 @@ config WANT_SENSORS
bool "Support external sensor devices"
depends on HAVE_GPIO_I2C || HAVE_GPIO_SPI
config WANT_LIS2DW
bool "Support lis2dw 3-axis accelerometer"
depends on HAVE_GPIO_SPI
bool "Support lis2dw and lis3dh 3-axis accelerometers"
depends on HAVE_GPIO_SPI || HAVE_GPIO_I2C
config WANT_LDC1612
bool "Support ldc1612 eddy current sensor"
depends on HAVE_GPIO_I2C
Expand Down
4 changes: 4 additions & 0 deletions src/ar100/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ void spi_prepare(struct spi_config config);
void spi_transfer(struct spi_config config, uint8_t receive_data
, uint8_t len, uint8_t *data);

struct i2c_config {
void *cfg;
};

#endif
14 changes: 10 additions & 4 deletions src/atsamd/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
#include "i2ccmds.h" // I2C_BUS_SUCCESS

#define TIME_RISE 125ULL // 125 nanoseconds
#define I2C_FREQ 100000
#define I2C_FREQ 100000
#define I2C_FREQ_FAST 400000

static void
i2c_init(uint32_t bus, SercomI2cm *si)
i2c_init(uint32_t bus, uint32_t rate, SercomI2cm *si)
{
static uint8_t have_run_init;
if (have_run_init & (1<<bus))
Expand All @@ -29,7 +30,12 @@ i2c_init(uint32_t bus, SercomI2cm *si)
| SERCOM_I2CM_CTRLA_MODE(5));
si->CTRLA.reg = areg;
uint32_t freq = sercom_get_pclock_frequency(bus);
uint32_t baud = (freq/I2C_FREQ - 10 - freq*TIME_RISE/1000000000) / 2;
uint32_t baud = 0;
if (rate < I2C_FREQ_FAST) {
baud = (freq/I2C_FREQ - 10 - freq*TIME_RISE/1000000000) / 2;
} else {
baud = (freq/I2C_FREQ_FAST - 10 - freq*TIME_RISE/1000000000) / 2;
}
si->BAUD.reg = baud;
si->CTRLA.reg = areg | SERCOM_I2CM_CTRLA_ENABLE;
while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_ENABLE)
Expand All @@ -47,7 +53,7 @@ i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr)
Sercom *sercom = sercom_enable_pclock(bus);
sercom_i2c_pins(bus);
SercomI2cm *si = &sercom->I2CM;
i2c_init(bus, si);
i2c_init(bus, rate, si);
return (struct i2c_config){ .si=si, .addr=addr<<1 };
}

Expand Down
4 changes: 4 additions & 0 deletions src/generic/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ void spi_prepare(struct spi_config config);
void spi_transfer(struct spi_config config, uint8_t receive_data
, uint8_t len, uint8_t *data);

struct i2c_config {
uint32_t cfg;
};

#endif // gpio.h
Loading

0 comments on commit 2ad3338

Please sign in to comment.