From 0dbfa915de5495662102d17c7a11cea219354b91 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Mon, 2 Jul 2018 13:47:22 -0400 Subject: [PATCH] adccmds: Add support for min/max temperature check filtering Extend the ADC out of range check so that it is possible to sample multiple times before going into a shutdown state. This reduces the chance that measurement noise will cause an error. In an actual over temperature (or under temperature event) it is expected that the sensor will consistently report the problem, so extra checks for an additional second or two should not substantially increase risk. Signed-off-by: Kevin O'Connor --- klippy/extras/adc_temperature.py | 4 +++- klippy/extras/thermistor.py | 4 +++- klippy/mcu.py | 11 +++++++---- src/adccmds.c | 15 ++++++++++++--- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/klippy/extras/adc_temperature.py b/klippy/extras/adc_temperature.py index 31c1ecce..1aea908b 100644 --- a/klippy/extras/adc_temperature.py +++ b/klippy/extras/adc_temperature.py @@ -8,6 +8,7 @@ import logging, bisect SAMPLE_TIME = 0.001 SAMPLE_COUNT = 8 REPORT_TIME = 0.300 +RANGE_CHECK_COUNT = 4 # Linear style conversion chips calibrated with two temp measurements class Linear: @@ -50,7 +51,8 @@ class Linear: def setup_minmax(self, min_temp, max_temp): adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)] self.mcu_adc.setup_minmax(SAMPLE_TIME, SAMPLE_COUNT, - minval=min(adc_range), maxval=max(adc_range)) + minval=min(adc_range), maxval=max(adc_range), + range_check_count=RANGE_CHECK_COUNT) def setup_callback(self, temperature_callback): self.temperature_callback = temperature_callback def get_report_time_delta(self): diff --git a/klippy/extras/thermistor.py b/klippy/extras/thermistor.py index 3f96066d..c39ae66e 100644 --- a/klippy/extras/thermistor.py +++ b/klippy/extras/thermistor.py @@ -9,6 +9,7 @@ KELVIN_TO_CELCIUS = -273.15 SAMPLE_TIME = 0.001 SAMPLE_COUNT = 8 REPORT_TIME = 0.300 +RANGE_CHECK_COUNT = 4 # Analog voltage to temperature converter for thermistors class Thermistor: @@ -59,7 +60,8 @@ class Thermistor: def setup_minmax(self, min_temp, max_temp): adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)] self.mcu_adc.setup_minmax(SAMPLE_TIME, SAMPLE_COUNT, - minval=min(adc_range), maxval=max(adc_range)) + minval=min(adc_range), maxval=max(adc_range), + range_check_count=RANGE_CHECK_COUNT) def setup_callback(self, temperature_callback): self.temperature_callback = temperature_callback def get_report_time_delta(self): diff --git a/klippy/mcu.py b/klippy/mcu.py index 8d7e86cb..56c28b4b 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -350,17 +350,19 @@ class MCU_adc: self._pin = pin_params['pin'] self._min_sample = self._max_sample = 0. self._sample_time = self._report_time = 0. - self._sample_count = 0 + self._sample_count = self._range_check_count = 0 self._report_clock = 0 self._oid = self._callback = None self._inv_max_adc = 0. def get_mcu(self): return self._mcu - def setup_minmax(self, sample_time, sample_count, minval=0., maxval=1.): + def setup_minmax(self, sample_time, sample_count, + minval=0., maxval=1., range_check_count=0): self._sample_time = sample_time self._sample_count = sample_count self._min_sample = minval self._max_sample = maxval + self._range_check_count = range_check_count def setup_adc_callback(self, report_time, callback): self._report_time = report_time self._callback = callback @@ -381,9 +383,10 @@ class MCU_adc: math.ceil(self._max_sample * max_adc)))) self._mcu.add_config_cmd( "query_analog_in oid=%d clock=%d sample_ticks=%d sample_count=%d" - " rest_ticks=%d min_value=%d max_value=%d" % ( + " rest_ticks=%d min_value=%d max_value=%d range_check_count=%d" % ( self._oid, clock, sample_ticks, self._sample_count, - self._report_clock, min_sample, max_sample), is_init=True) + self._report_clock, min_sample, max_sample, + self._range_check_count), is_init=True) self._mcu.register_msg(self._handle_analog_in_state, "analog_in_state" , self._oid) def _handle_analog_in_state(self, params): diff --git a/src/adccmds.c b/src/adccmds.c index 41247a54..09db9b9d 100644 --- a/src/adccmds.c +++ b/src/adccmds.c @@ -15,6 +15,7 @@ struct analog_in { uint32_t rest_time, sample_time, next_begin_time; uint16_t value, min_value, max_value; struct gpio_adc pin; + uint8_t invalid_count, range_check_count; uint8_t state, sample_count; }; @@ -42,8 +43,15 @@ analog_in_event(struct timer *timer) a->timer.waketime += a->sample_time; return SF_RESCHEDULE; } - if (a->value < a->min_value || a->value > a->max_value) - try_shutdown("ADC out of range"); + if (likely(a->value >= a->min_value && a->value <= a->max_value)) { + a->invalid_count = 0; + } else { + a->invalid_count++; + if (a->invalid_count >= a->range_check_count) { + try_shutdown("ADC out of range"); + a->invalid_count = 0; + } + } sched_wake_task(&analog_wake); a->next_begin_time += a->rest_time; a->timer.waketime = a->next_begin_time; @@ -75,13 +83,14 @@ command_query_analog_in(uint32_t *args) a->rest_time = args[4]; a->min_value = args[5]; a->max_value = args[6]; + a->range_check_count = args[7]; if (! a->sample_count) return; sched_add_timer(&a->timer); } DECL_COMMAND(command_query_analog_in, "query_analog_in oid=%c clock=%u sample_ticks=%u sample_count=%c" - " rest_ticks=%u min_value=%hu max_value=%hu"); + " rest_ticks=%u min_value=%hu max_value=%hu range_check_count=%c"); void analog_in_task(void)