From a5c9350835447103ea02e2cb564e93d2b031a063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 26 Jan 2021 21:26:58 +0100 Subject: [PATCH 1/6] Fix typo --- stm-firmware/adc-meas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stm-firmware/adc-meas.c b/stm-firmware/adc-meas.c index e4d0fa2..aa33e3e 100644 --- a/stm-firmware/adc-meas.c +++ b/stm-firmware/adc-meas.c @@ -395,7 +395,7 @@ void DMA2_Stream0_IRQHandler(void) DMA2->LIFCR = lisr; if (lisr & DMA_LISR_TCIF0) { - /* Samples Transfered */ + /* Samples transferred */ adc_val = adc_pt1000_dma_avg_pre_filter(); adc_pt1000_raw_reading_hf = adc_val; From 67b079fe330b2ada56a42771174ac79b51f2778f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 26 Jan 2021 21:46:33 +0100 Subject: [PATCH 2/6] Improve rport error function of safety controller --- stm-firmware/safety/safety-controller.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index 35a3250..17affc0 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -582,6 +582,10 @@ static int report_error(enum safety_flag flag, uint32_t key, bool prevent_error_ } else { ret = 0; } + + flag &= ~flags[i].flag; + if (!flag) + break; } } From 20a65fd7f9d670446edc44dbe731e45c7b9936f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 26 Jan 2021 21:46:44 +0100 Subject: [PATCH 3/6] Issue #24: Implement new handling for Unstable flag. * Unstable flag will now be set, whenever the output of the moving average filter differs more than 10 Ohms from the measured prefilterd input. --- stm-firmware/adc-meas.c | 22 ++++++++++--------- .../include/reflow-controller/adc-meas.h | 11 +++++----- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/stm-firmware/adc-meas.c b/stm-firmware/adc-meas.c index aa33e3e..3aef6b9 100644 --- a/stm-firmware/adc-meas.c +++ b/stm-firmware/adc-meas.c @@ -45,7 +45,6 @@ static float IN_SECTION(.ccm.bss) filter_alpha; static volatile float IN_SECTION(.ccm.bss) pt1000_res_raw_lf; static volatile int * volatile streaming_flag_ptr; -static uint32_t IN_SECTION(.ccm.bss) filter_startup_cnt; static volatile float IN_SECTION(.ccm.bss) adc_pt1000_raw_reading_hf; static volatile uint16_t dma_sample_buffer[ADC_PT1000_DMA_AVG_SAMPLES]; static volatile uint32_t IN_SECTION(.ccm.bss) adc_watchdog_counter; @@ -188,7 +187,6 @@ void adc_pt1000_set_moving_average_filter_param(float alpha) { filter_alpha = alpha; safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); - filter_startup_cnt = ADC_FILTER_STARTUP_CYCLES; } void adc_pt1000_set_resistance_calibration(float offset, float sensitivity_deviation, bool active) @@ -305,18 +303,22 @@ static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_p { float alpha; float res; - - if (filter_startup_cnt > 0) { - filter_startup_cnt--; - if (filter_startup_cnt == 0) - safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); - } + static uint8_t old_state = 0; res = ADC_TO_RES(adc_prefiltered_value); - if (ABS(res - pt1000_res_raw_lf) > 20) + if (ABS(res - pt1000_res_raw_lf) >= ADC_PT1000_FILTER_UNSTABLE_DIFF) { alpha = ADC_PT1000_FILTER_WEIGHT_FAST; - else + if (old_state != 1) { + safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); + old_state = 1; + } + } else { alpha = filter_alpha; + if (old_state != 2) { + safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); + old_state = 2; + } + } pt1000_res_raw_lf = (1.0f - alpha) * pt1000_res_raw_lf + alpha * res; diff --git a/stm-firmware/include/reflow-controller/adc-meas.h b/stm-firmware/include/reflow-controller/adc-meas.h index 073977a..9e96b81 100644 --- a/stm-firmware/include/reflow-controller/adc-meas.h +++ b/stm-firmware/include/reflow-controller/adc-meas.h @@ -44,6 +44,11 @@ */ #define ADC_PT1000_FILTER_WEIGHT_FAST 0.05 +/** + * @brief Difference in Ohm between filter input and output that determines if the filter is stable or unstable. + */ +#define ADC_PT1000_FILTER_UNSTABLE_DIFF 10 + /** * @brief ADC channel number of PT1000 sensor input */ @@ -64,12 +69,6 @@ */ #define ADC_PT1000_PIN 2U -/** - * @brief The cycle count the moving average filter is labeled 'instable' after startup of the measurement or changing - * the alpha value @ref ADC_PT1000_FILTER_WEIGHT - */ -#define ADC_FILTER_STARTUP_CYCLES 800U - /** * @brief The delay value programmed into the sample timer */ From 4c1797aa24128ab4eb029728e10ed4edce4741d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 26 Jan 2021 21:59:41 +0100 Subject: [PATCH 4/6] Issue #24: Make UNSTABLE flag only go away, if the PT1000 value stays within the stable region for a given amount of samples --- stm-firmware/adc-meas.c | 11 ++++++++--- stm-firmware/include/reflow-controller/adc-meas.h | 6 ++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/stm-firmware/adc-meas.c b/stm-firmware/adc-meas.c index 3aef6b9..c598e42 100644 --- a/stm-firmware/adc-meas.c +++ b/stm-firmware/adc-meas.c @@ -214,7 +214,7 @@ void adc_pt1000_get_resistance_calibration(float *offset, float *sensitivity_dev static inline float adc_pt1000_apply_calibration(float raw_resistance) { if (calibration_active) - return (raw_resistance - pt1000_offset) * (1.0f + pt1000_sens_dev); + return (raw_resistance - pt1000_offset) * (1.0f + pt1000_sens_dev); else return raw_resistance; @@ -304,9 +304,11 @@ static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_p float alpha; float res; static uint8_t old_state = 0; + static uint32_t stable_sample_counter = 0; res = ADC_TO_RES(adc_prefiltered_value); if (ABS(res - pt1000_res_raw_lf) >= ADC_PT1000_FILTER_UNSTABLE_DIFF) { + stable_sample_counter = 0; alpha = ADC_PT1000_FILTER_WEIGHT_FAST; if (old_state != 1) { safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); @@ -315,8 +317,11 @@ static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_p } else { alpha = filter_alpha; if (old_state != 2) { - safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); - old_state = 2; + stable_sample_counter++; + if (stable_sample_counter >= ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT) { + safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY); + old_state = 2; + } } } diff --git a/stm-firmware/include/reflow-controller/adc-meas.h b/stm-firmware/include/reflow-controller/adc-meas.h index 9e96b81..b7e8b35 100644 --- a/stm-firmware/include/reflow-controller/adc-meas.h +++ b/stm-firmware/include/reflow-controller/adc-meas.h @@ -49,6 +49,12 @@ */ #define ADC_PT1000_FILTER_UNSTABLE_DIFF 10 +/** + * @brief Sample count, the moving average filter has to be within @ref ADC_PT1000_FILTER_UNSTABLE_DIFF for the filter + * to be considered stable + */ +#define ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT 200 + /** * @brief ADC channel number of PT1000 sensor input */ From 125b41de447a491b0c0ef82b17210c7e2290b9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 26 Jan 2021 22:46:44 +0100 Subject: [PATCH 5/6] Fix Doxyfile --- doc/source/Doxyfile.in | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/doc/source/Doxyfile.in b/doc/source/Doxyfile.in index 510ce67..ac12e1e 100644 --- a/doc/source/Doxyfile.in +++ b/doc/source/Doxyfile.in @@ -873,34 +873,7 @@ FILE_PATTERNS = *.c \ *.hxx \ *.hpp \ *.h++ \ - *.cs \ - *.d \ - *.php \ - *.php4 \ - *.php5 \ - *.phtml \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.doc \ - *.txt \ - *.py \ - *.pyw \ - *.f90 \ - *.f95 \ - *.f03 \ - *.f08 \ - *.f18 \ - *.f \ - *.for \ - *.vhd \ - *.vhdl \ - *.ucf \ - *.qsf \ - *.ice + *.dox # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. From e7aa714976206458242e8bd86ff8cd0637da8ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Tue, 26 Jan 2021 22:48:19 +0100 Subject: [PATCH 6/6] Update documentation regarding Unstable flag --- doc/source/firmware/pt1000-processing.rst | 11 +++++++++-- doc/source/firmware/pt1000.drawio | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/source/firmware/pt1000-processing.rst b/doc/source/firmware/pt1000-processing.rst index d254c49..2f017e8 100644 --- a/doc/source/firmware/pt1000-processing.rst +++ b/doc/source/firmware/pt1000-processing.rst @@ -87,9 +87,16 @@ and can be changed in code using .. doxygenfunction:: adc_pt1000_set_moving_average_filter_param -After initial startup and after each change of the filter constant, the filter will set the :ref:`safety_flags_adc_unstable` flag for a defined sample count of: +The moving average filter is considered unstable, if the input to output difference is greater than -.. doxygendefine:: ADC_FILTER_STARTUP_CYCLES +.. doxygendefine:: ADC_PT1000_FILTER_UNSTABLE_DIFF + +In this case, the :ref:`safety_flags_adc_unstable` flag will be set until the filter output converges within the range for at least + +.. doxygendefine:: ADC_PT1000_FILTER_STABLE_SAMPLE_COUNT + +samples. +If the input value keeps changing or oscillating, the error flag will be permanently set. The moving average filter's output signal is the Low Frequency (LF) PT1000 resistance signal used for internal PT1000 measurements. diff --git a/doc/source/firmware/pt1000.drawio b/doc/source/firmware/pt1000.drawio index f0b84f2..b0398c3 100644 --- a/doc/source/firmware/pt1000.drawio +++ b/doc/source/firmware/pt1000.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file