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 <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-07-02 13:47:22 -04:00
parent 5b3444c060
commit 0dbfa915de
4 changed files with 25 additions and 9 deletions

View File

@ -8,6 +8,7 @@ import logging, bisect
SAMPLE_TIME = 0.001 SAMPLE_TIME = 0.001
SAMPLE_COUNT = 8 SAMPLE_COUNT = 8
REPORT_TIME = 0.300 REPORT_TIME = 0.300
RANGE_CHECK_COUNT = 4
# Linear style conversion chips calibrated with two temp measurements # Linear style conversion chips calibrated with two temp measurements
class Linear: class Linear:
@ -50,7 +51,8 @@ class Linear:
def setup_minmax(self, min_temp, max_temp): def setup_minmax(self, min_temp, max_temp):
adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)] adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)]
self.mcu_adc.setup_minmax(SAMPLE_TIME, SAMPLE_COUNT, 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): 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

@ -9,6 +9,7 @@ KELVIN_TO_CELCIUS = -273.15
SAMPLE_TIME = 0.001 SAMPLE_TIME = 0.001
SAMPLE_COUNT = 8 SAMPLE_COUNT = 8
REPORT_TIME = 0.300 REPORT_TIME = 0.300
RANGE_CHECK_COUNT = 4
# Analog voltage to temperature converter for thermistors # Analog voltage to temperature converter for thermistors
class Thermistor: class Thermistor:
@ -59,7 +60,8 @@ class Thermistor:
def setup_minmax(self, min_temp, max_temp): def setup_minmax(self, min_temp, max_temp):
adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)] adc_range = [self.calc_adc(min_temp), self.calc_adc(max_temp)]
self.mcu_adc.setup_minmax(SAMPLE_TIME, SAMPLE_COUNT, 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): 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

@ -350,17 +350,19 @@ class MCU_adc:
self._pin = pin_params['pin'] self._pin = pin_params['pin']
self._min_sample = self._max_sample = 0. self._min_sample = self._max_sample = 0.
self._sample_time = self._report_time = 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._report_clock = 0
self._oid = self._callback = None self._oid = self._callback = None
self._inv_max_adc = 0. self._inv_max_adc = 0.
def get_mcu(self): def get_mcu(self):
return self._mcu 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_time = sample_time
self._sample_count = sample_count self._sample_count = sample_count
self._min_sample = minval self._min_sample = minval
self._max_sample = maxval self._max_sample = maxval
self._range_check_count = range_check_count
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
@ -381,9 +383,10 @@ class MCU_adc:
math.ceil(self._max_sample * max_adc)))) math.ceil(self._max_sample * max_adc))))
self._mcu.add_config_cmd( self._mcu.add_config_cmd(
"query_analog_in oid=%d clock=%d sample_ticks=%d sample_count=%d" "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._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._mcu.register_msg(self._handle_analog_in_state, "analog_in_state"
, self._oid) , self._oid)
def _handle_analog_in_state(self, params): def _handle_analog_in_state(self, params):

View File

@ -15,6 +15,7 @@ struct analog_in {
uint32_t rest_time, sample_time, next_begin_time; uint32_t rest_time, sample_time, next_begin_time;
uint16_t value, min_value, max_value; uint16_t value, min_value, max_value;
struct gpio_adc pin; struct gpio_adc pin;
uint8_t invalid_count, range_check_count;
uint8_t state, sample_count; uint8_t state, sample_count;
}; };
@ -42,8 +43,15 @@ analog_in_event(struct timer *timer)
a->timer.waketime += a->sample_time; a->timer.waketime += a->sample_time;
return SF_RESCHEDULE; return SF_RESCHEDULE;
} }
if (a->value < a->min_value || a->value > a->max_value) 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"); try_shutdown("ADC out of range");
a->invalid_count = 0;
}
}
sched_wake_task(&analog_wake); sched_wake_task(&analog_wake);
a->next_begin_time += a->rest_time; a->next_begin_time += a->rest_time;
a->timer.waketime = a->next_begin_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->rest_time = args[4];
a->min_value = args[5]; a->min_value = args[5];
a->max_value = args[6]; a->max_value = args[6];
a->range_check_count = args[7];
if (! a->sample_count) if (! a->sample_count)
return; return;
sched_add_timer(&a->timer); sched_add_timer(&a->timer);
} }
DECL_COMMAND(command_query_analog_in, DECL_COMMAND(command_query_analog_in,
"query_analog_in oid=%c clock=%u sample_ticks=%u sample_count=%c" "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 void
analog_in_task(void) analog_in_task(void)