adxl345: Verify the register writes, added debug adxl345 commands

Signed-off-by: Dmitry Butyugin <dmbutyugin@google.com>
This commit is contained in:
Dmitry Butyugin 2021-03-26 19:32:32 +01:00 committed by KevinOConnor
parent a58e9eddbe
commit 200b62bcb4
2 changed files with 83 additions and 21 deletions

View File

@ -717,6 +717,13 @@ The following commands are available when an
is used. This command is useful to test the connection to the
ADXL345 accelerometer: one of the returned values should be a
free-fall acceleration (+/- some noise of the chip).
- `ADXL345_DEBUG_READ [CHIP=<config_name>] REG=<register>`: queries
ADXL345 register <register> (e.g. 44 or 0x2C). Can be useful for
debugging purposes.
- `ADXL345_DEBUG_WRITE [CHIP=<config_name>] REG=<reg> VAL=<value>`:
writes raw <value> into a register <register>. Both <value> and
<register> can be a decimal or a hexadecimal integer. Use with care,
and refer to ADXL345 data sheet for the reference.
## Resonance Testing Commands

View File

@ -20,7 +20,10 @@ QUERY_RATES = {
800: 0xd, 1600: 0xe, 3200: 0xf,
}
SCALE = 0.004 * 9.80665 * 1000. # 4mg/LSB * Earth gravity in mm/s**2
ADXL345_DEV_ID = 0xe5
FREEFALL_ACCEL = 9.80665 * 1000.
SCALE = 0.0039 * FREEFALL_ACCEL # 3.9mg/LSB * Earth gravity in mm/s**2
Accel_Measurement = collections.namedtuple(
'Accel_Measurement', ('time', 'accel_x', 'accel_y', 'accel_z'))
@ -93,7 +96,7 @@ class ADXL345Results:
write_proc.daemon = True
write_proc.start()
# Printer class that controls measurments
# Printer class that controls ADXL345 chip
class ADXL345:
def __init__(self, config):
self.printer = config.get_printer()
@ -135,11 +138,36 @@ class ADXL345:
gcode.register_mux_command("ACCELEROMETER_QUERY", "CHIP", self.name,
self.cmd_ACCELEROMETER_QUERY,
desc=self.cmd_ACCELEROMETER_QUERY_help)
gcode.register_mux_command("ADXL345_DEBUG_READ", "CHIP", self.name,
self.cmd_ADXL345_DEBUG_READ,
desc=self.cmd_ADXL345_DEBUG_READ_help)
gcode.register_mux_command("ADXL345_DEBUG_WRITE", "CHIP", self.name,
self.cmd_ADXL345_DEBUG_WRITE,
desc=self.cmd_ADXL345_DEBUG_WRITE_help)
if self.name == "default":
gcode.register_mux_command("ACCELEROMETER_MEASURE", "CHIP", None,
self.cmd_ACCELEROMETER_MEASURE)
gcode.register_mux_command("ACCELEROMETER_QUERY", "CHIP", None,
self.cmd_ACCELEROMETER_QUERY)
gcode.register_mux_command("ADXL345_DEBUG_READ", "CHIP", None,
self.cmd_ADXL345_DEBUG_READ,
desc=self.cmd_ADXL345_DEBUG_READ_help)
gcode.register_mux_command("ADXL345_DEBUG_WRITE", "CHIP", None,
self.cmd_ADXL345_DEBUG_WRITE,
desc=self.cmd_ADXL345_DEBUG_WRITE_help)
def is_initialized(self):
# In case of miswiring, testing ADXL345 device ID prevents treating
# noise or wrong signal as a correctly initialized device
return (self.read_reg(REG_DEVID) == ADXL345_DEV_ID and
(self.read_reg(REG_DATA_FORMAT) & 0xB) != 0)
def initialize(self):
# Setup ADXL345 parameters and verify chip connectivity
self.set_reg(REG_POWER_CTL, 0x00)
dev_id = self.read_reg(REG_DEVID)
if dev_id != ADXL345_DEV_ID:
raise self.printer.command_error("Invalid adxl345 id (got %x vs %x)"
% (dev_id, ADXL345_DEV_ID))
self.set_reg(REG_DATA_FORMAT, 0x0B)
def _build_config(self):
self.query_adxl345_cmd = self.mcu.lookup_command(
"query_adxl345 oid=%c clock=%u rest_ticks=%u",
@ -170,23 +198,35 @@ class ADXL345:
if sequence < self.last_sequence:
sequence += 0x10000
return sequence
def start_measurements(self, rate=None):
rate = rate or self.data_rate
# Verify chip connectivity
params = self.spi.spi_transfer([REG_DEVID | REG_MOD_READ, 0x00])
def read_reg(self, reg):
params = self.spi.spi_transfer([reg | REG_MOD_READ, 0x00])
response = bytearray(params['response'])
if response[1] != 0xe5:
raise self.printer.command_error("Invalid adxl345 id (got %x vs %x)"
% (response[1], 0xe5))
return response[1]
def set_reg(self, reg, val, minclock=0):
self.spi.spi_send([reg, val & 0xFF], minclock=minclock)
stored_val = self.read_reg(reg)
if stored_val != val:
raise self.printer.command_error(
"Failed to set ADXL345 register [0x%x] to 0x%x: got 0x%x. "
"This is generally indicative of connection problems "
"(e.g. faulty wiring) or a faulty adxl345 chip." % (
reg, val, stored_val))
def is_measuring(self):
return self.query_rate > 0
def start_measurements(self, rate=None):
if self.is_measuring():
return
rate = rate or self.data_rate
if not self.is_initialized():
self.initialize()
# Setup chip in requested query rate
clock = 0
if self.last_tx_time:
clock = self.mcu.print_time_to_clock(self.last_tx_time)
self.spi.spi_send([REG_POWER_CTL, 0x00], minclock=clock)
self.spi.spi_send([REG_FIFO_CTL, 0x00])
self.spi.spi_send([REG_DATA_FORMAT, 0x0B])
self.spi.spi_send([REG_BW_RATE, QUERY_RATES[rate]])
self.spi.spi_send([REG_FIFO_CTL, 0x80])
self.set_reg(REG_POWER_CTL, 0x00, minclock=clock)
self.set_reg(REG_FIFO_CTL, 0x00)
self.set_reg(REG_BW_RATE, QUERY_RATES[rate])
self.set_reg(REG_FIFO_CTL, 0x80)
# Setup samples
print_time = self.printer.lookup_object('toolhead').get_last_move_time()
self.raw_samples = []
@ -200,8 +240,7 @@ class ADXL345:
self.query_adxl345_cmd.send([self.oid, reqclock, rest_ticks],
reqclock=reqclock)
def finish_measurements(self):
query_rate = self.query_rate
if not query_rate:
if not self.is_measuring():
return ADXL345Results()
# Halt bulk reading
print_time = self.printer.lookup_object('toolhead').get_last_move_time()
@ -224,8 +263,8 @@ class ADXL345:
logging.info("ADXL345 finished %d measurements: %s",
res.total_count, res.get_stats())
return res
def end_query(self, name):
if not self.query_rate:
def end_query(self, name, gcmd):
if not self.is_measuring():
return
res = self.finish_measurements()
# Write data to file
@ -234,13 +273,15 @@ class ADXL345:
else:
filename = "/tmp/adxl345-%s-%s.csv" % (self.name, name,)
res.write_to_file(filename)
gcmd.respond_info(
"Writing raw accelerometer data to %s file" % (filename,))
cmd_ACCELEROMETER_MEASURE_help = "Start/stop accelerometer"
def cmd_ACCELEROMETER_MEASURE(self, gcmd):
if self.query_rate:
if self.is_measuring():
name = gcmd.get("NAME", time.strftime("%Y%m%d_%H%M%S"))
if not name.replace('-', '').replace('_', '').isalnum():
raise gcmd.error("Invalid adxl345 NAME parameter")
self.end_query(name)
self.end_query(name, gcmd)
gcmd.respond_info("adxl345 measurements stopped")
else:
rate = gcmd.get_int("RATE", self.data_rate)
@ -250,7 +291,7 @@ class ADXL345:
gcmd.respond_info("adxl345 measurements started")
cmd_ACCELEROMETER_QUERY_help = "Query accelerometer for the current values"
def cmd_ACCELEROMETER_QUERY(self, gcmd):
if self.query_rate:
if self.is_measuring():
raise gcmd.error("adxl345 measurements in progress")
self.start_measurements()
reactor = self.printer.get_reactor()
@ -266,6 +307,20 @@ class ADXL345:
_, accel_x, accel_y, accel_z = values[-1]
gcmd.respond_info("adxl345 values (x, y, z): %.6f, %.6f, %.6f" % (
accel_x, accel_y, accel_z))
cmd_ADXL345_DEBUG_READ_help = "Query accelerometer register (for debugging)"
def cmd_ADXL345_DEBUG_READ(self, gcmd):
if self.is_measuring():
raise gcmd.error("adxl345 measurements in progress")
reg = gcmd.get("REG", minval=29, maxval=57, parser=lambda x: int(x, 0))
val = self.read_reg(reg)
gcmd.respond_info("ADXL345 REG[0x%x] = 0x%x" % (reg, val))
cmd_ADXL345_DEBUG_WRITE_help = "Set accelerometer register (for debugging)"
def cmd_ADXL345_DEBUG_WRITE(self, gcmd):
if self.is_measuring():
raise gcmd.error("adxl345 measurements in progress")
reg = gcmd.get("REG", minval=29, maxval=57, parser=lambda x: int(x, 0))
val = gcmd.get("VAL", minval=0, maxval=255, parser=lambda x: int(x, 0))
self.set_reg(reg, val)
def load_config(config):
return ADXL345(config)