diff --git a/config/example-extras.cfg b/config/example-extras.cfg index ce981c7e..8ea8413b 100644 --- a/config/example-extras.cfg +++ b/config/example-extras.cfg @@ -2222,6 +2222,23 @@ # communication. The pin must have a valid pinmux configuration # for the given SERCOM peripheral. This parameter must be provided. +# Duet2 Maestro analog scaling by vref and vssa readings. Defining an +# adc_scaled section enables virtual adc pins (such as "my_name:PB0") +# that are automatically adjusted by the board's vref and vssa +# monitoring pins. Be sure to define this config section above any +# config sections that use one these virtual pins. +#[adc_scaled my_name] +#vref_pin: +# The ADC pin to use for VREF monitoring. This parameter must be +# provided. +#vssa_pin: +# The ADC pin to use for VSSA monitoring. This parameter must be +# provided. +#smooth_time: 2.0 +# A time value (in seconds) over which the vref and vssa +# measurements will be smoothed to reduce the impact of measurement +# noise. The default is 2 seconds. + # Replicape support - see the generic-replicape.cfg file for further # details. #[replicape] diff --git a/config/generic-duet2-maestro.cfg b/config/generic-duet2-maestro.cfg index 6715c87e..a5c6bbea 100644 --- a/config/generic-duet2-maestro.cfg +++ b/config/generic-duet2-maestro.cfg @@ -59,6 +59,11 @@ microsteps: 16 run_current: 0.800 stealthchop_threshold: 30 +# Support analog sensor adjustments using VREF/VSSA pins +[adc_scaled vref_scaled] +vref_pin: PA17 +vssa_pin: PA19 + [extruder] step_pin: PC4 dir_pin: PB7 @@ -69,7 +74,7 @@ filament_diameter: 1.750 heater_pin: !PC1 sensor_type: EPCOS 100K B57560G104F pullup_resistor: 2200 -sensor_pin: PB0 +sensor_pin: vref_scaled:PB0 control: pid pid_Kp: 22.2 pid_Ki: 1.08 @@ -110,7 +115,7 @@ stealthchop_threshold: 5 heater_pin: !PC0 sensor_type: EPCOS 100K B57560G104F pullup_resistor: 2200 -sensor_pin: PA20 +sensor_pin: vref_scaled:PA20 control: watermark min_temp: 0 max_temp: 130 diff --git a/klippy/extras/adc_scaled.py b/klippy/extras/adc_scaled.py new file mode 100644 index 00000000..c2d2cb87 --- /dev/null +++ b/klippy/extras/adc_scaled.py @@ -0,0 +1,79 @@ +# Support for scaling ADC values based on measured VREF and VSSA +# +# Copyright (C) 2020 Kevin O'Connor +# +# This file may be distributed under the terms of the GNU GPLv3 license. + +SAMPLE_TIME = 0.001 +SAMPLE_COUNT = 8 +REPORT_TIME = 0.300 +RANGE_CHECK_COUNT = 4 + +class MCU_scaled_adc: + def __init__(self, main, pin_params): + self._main = main + self._last_state = (0., 0.) + self._mcu_adc = main.mcu.setup_pin('adc', pin_params) + query_adc = main.printer.lookup_object('query_adc') + qname = main.name + ":" + pin_params['pin'] + query_adc.register_adc(qname, self._mcu_adc) + self._callback = None + self.setup_minmax = self._mcu_adc.setup_minmax + self.get_mcu = self._mcu_adc.get_mcu + def _handle_callback(self, read_time, read_value): + max_adc = self._main.last_vref[1] + min_adc = self._main.last_vssa[1] + scaled_val = (read_value - min_adc) / (max_adc - min_adc) + self._last_state = (scaled_val, read_time) + self._callback(read_time, scaled_val) + def setup_adc_callback(self, report_time, callback): + self._callback = callback + self._mcu_adc.setup_adc_callback(report_time, self._handle_callback) + def get_last_value(self): + return self._last_state + +class PrinterADCScaled: + def __init__(self, config): + self.printer = config.get_printer() + self.name = config.get_name().split()[1] + self.last_vref = (0., 0.) + self.last_vssa = (0., 0.) + # Configure vref and vssa pins + self.mcu_vref = self._config_pin(config, 'vref', self.vref_callback) + self.mcu_vssa = self._config_pin(config, 'vssa', self.vssa_callback) + smooth_time = config.getfloat('smooth_time', 2., above=0.) + self.inv_smooth_time = 1. / smooth_time + self.mcu = self.mcu_vref.get_mcu() + if self.mcu is not self.mcu_vssa.get_mcu(): + raise config.error("vref and vssa must be on same mcu") + # Register setup_pin + ppins = self.printer.lookup_object('pins') + ppins.register_chip(self.name, self) + def _config_pin(self, config, name, callback): + pin_name = config.get(name + '_pin') + ppins = self.printer.lookup_object('pins') + mcu_adc = ppins.setup_pin('adc', pin_name) + mcu_adc.setup_adc_callback(REPORT_TIME, callback) + mcu_adc.setup_minmax(SAMPLE_TIME, SAMPLE_COUNT, minval=0., maxval=1., + range_check_count=RANGE_CHECK_COUNT) + query_adc = config.get_printer().load_object(config, 'query_adc') + query_adc.register_adc(self.name + ":" + name, mcu_adc) + return mcu_adc + def setup_pin(self, pin_type, pin_params): + if pin_type != 'adc': + raise self.printer.config_error("adc_scaled only supports adc pins") + return MCU_scaled_adc(self, pin_params) + def calc_smooth(self, read_time, read_value, last): + last_time, last_value = last + time_diff = read_time - last_time + value_diff = read_value - last_value + adj_time = min(time_diff * self.inv_smooth_time, 1.) + smoothed_value = last_value + value_diff * adj_time + return (read_time, smoothed_value) + def vref_callback(self, read_time, read_value): + self.last_vref = self.calc_smooth(read_time, read_value, self.last_vref) + def vssa_callback(self, read_time, read_value): + self.last_vssa = self.calc_smooth(read_time, read_value, self.last_vssa) + +def load_config_prefix(config): + return PrinterADCScaled(config)