query_adc: Add a new module to help query and debug analog pins

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2019-11-07 19:23:20 -05:00
parent 124ba12485
commit 0bfb655f66
5 changed files with 50 additions and 0 deletions

View File

@ -101,6 +101,11 @@ The following standard commands are supported:
- `QUERY_ENDSTOPS`: Probe the axis endstops and report if they are - `QUERY_ENDSTOPS`: Probe the axis endstops and report if they are
"triggered" or in an "open" state. This command is typically used to "triggered" or in an "open" state. This command is typically used to
verify that an endstop is working correctly. verify that an endstop is working correctly.
- `QUERY_ADC [NAME=<config_name>] [PULLUP=<value>]`: Report the last
analog value received for a configured analog pin. If NAME is not
provided, the list of available adc names are reported. If PULLUP is
provided (as a value in Ohms), the raw analog value along with the
equivalent resistance given that pullup is reported.
- `GET_POSITION`: Return information on the current location of the - `GET_POSITION`: Return information on the current location of the
toolhead. toolhead.
- `SET_GCODE_OFFSET [X=<pos>|X_ADJUST=<adjust>] - `SET_GCODE_OFFSET [X=<pos>|X_ADJUST=<adjust>]

View File

@ -22,6 +22,8 @@ class PrinterADCtoTemperature:
ppins = config.get_printer().lookup_object('pins') ppins = config.get_printer().lookup_object('pins')
self.mcu_adc = ppins.setup_pin('adc', config.get('sensor_pin')) self.mcu_adc = ppins.setup_pin('adc', config.get('sensor_pin'))
self.mcu_adc.setup_adc_callback(REPORT_TIME, self.adc_callback) self.mcu_adc.setup_adc_callback(REPORT_TIME, self.adc_callback)
query_adc = config.get_printer().try_load_module(config, 'query_adc')
query_adc.register_adc(config.get_name(), self.mcu_adc)
def setup_callback(self, temperature_callback): def setup_callback(self, temperature_callback):
self.temperature_callback = temperature_callback self.temperature_callback = temperature_callback
def get_report_time_delta(self): def get_report_time_delta(self):

View File

@ -107,6 +107,8 @@ class MCU_ADC_buttons:
self.mcu_adc = ppins.setup_pin('adc', self.pin) self.mcu_adc = ppins.setup_pin('adc', self.pin)
self.mcu_adc.setup_minmax(ADC_SAMPLE_TIME, ADC_SAMPLE_COUNT) self.mcu_adc.setup_minmax(ADC_SAMPLE_TIME, ADC_SAMPLE_COUNT)
self.mcu_adc.setup_adc_callback(ADC_REPORT_TIME, self.adc_callback) self.mcu_adc.setup_adc_callback(ADC_REPORT_TIME, self.adc_callback)
query_adc = printer.lookup_object('query_adc')
query_adc.register_adc('adc_button:' + pin.strip(), self.mcu_adc)
def setup_button(self, min_value, max_value, callback): def setup_button(self, min_value, max_value, callback):
self.min_value = min(self.min_value, min_value) self.min_value = min(self.min_value, min_value)
@ -205,6 +207,7 @@ class RotaryEncoder:
class PrinterButtons: class PrinterButtons:
def __init__(self, config): def __init__(self, config):
self.printer = config.get_printer() self.printer = config.get_printer()
self.printer.try_load_module(config, 'query_adc')
self.mcu_buttons = {} self.mcu_buttons = {}
self.adc_buttons = {} self.adc_buttons = {}
def register_adc_button(self, pin, min_val, max_val, pullup, callback): def register_adc_button(self, pin, min_val, max_val, pullup, callback):

View File

@ -0,0 +1,36 @@
# Utility for querying the current state of adc pins
#
# Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
class QueryADC:
def __init__(self, config):
self.printer = config.get_printer()
self.adc = {}
gcode = self.printer.lookup_object('gcode')
gcode.register_command("QUERY_ADC", self.cmd_QUERY_ADC,
desc=self.cmd_QUERY_ADC_help)
def register_adc(self, name, mcu_adc):
self.adc[name] = mcu_adc
cmd_QUERY_ADC_help = "Report the last value of an analog pin"
def cmd_QUERY_ADC(self, params):
gcode = self.printer.lookup_object('gcode')
name = gcode.get_str('NAME', params, None)
if name not in self.adc:
objs = ['"%s"' % (n,) for n in sorted(self.adc.keys())]
msg = "Available ADC objects: %s" % (', '.join(objs),)
gcode.respond_info(msg)
return
value, timestamp = self.adc[name].get_last_value()
msg = 'ADC object "%s" has value %.6f (timestamp %.3f)' % (
name, value, timestamp)
pullup = gcode.get_float('PULLUP', params, None, above=0.)
if pullup is not None:
v = max(.00001, min(.99999, value))
r = pullup * v / (1.0 - v)
msg += "\n resistance %.3f (with %.0f pullup)" % (r, pullup)
gcode.respond_info(msg)
def load_config(config):
return QueryADC(config)

View File

@ -392,6 +392,7 @@ class MCU_adc:
self._sample_time = self._report_time = 0. self._sample_time = self._report_time = 0.
self._sample_count = self._range_check_count = 0 self._sample_count = self._range_check_count = 0
self._report_clock = 0 self._report_clock = 0
self._last_state = (0., 0.)
self._oid = self._callback = None self._oid = self._callback = None
self._mcu.register_config_callback(self._build_config) self._mcu.register_config_callback(self._build_config)
self._inv_max_adc = 0. self._inv_max_adc = 0.
@ -407,6 +408,8 @@ class MCU_adc:
def setup_adc_callback(self, report_time, callback): def setup_adc_callback(self, report_time, callback):
self._report_time = report_time self._report_time = report_time
self._callback = callback self._callback = callback
def get_last_value(self):
return self._last_state
def _build_config(self): def _build_config(self):
if not self._sample_count: if not self._sample_count:
return return
@ -435,6 +438,7 @@ class MCU_adc:
next_clock = self._mcu.clock32_to_clock64(params['next_clock']) next_clock = self._mcu.clock32_to_clock64(params['next_clock'])
last_read_clock = next_clock - self._report_clock last_read_clock = next_clock - self._report_clock
last_read_time = self._mcu.clock_to_print_time(last_read_clock) last_read_time = self._mcu.clock_to_print_time(last_read_clock)
self._last_state = (last_value, last_read_time)
if self._callback is not None: if self._callback is not None:
self._callback(last_read_time, last_value) self._callback(last_read_time, last_value)