From cbd28f9a12aa2e75f6fa9877a08780fa1b6a1687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sun, 14 Jun 2020 19:09:59 +0200 Subject: [PATCH] Add safety management in PID handler and main loop --- .../include/reflow-controller/oven-driver.h | 23 ++++++++- .../include/reflow-controller/safety-adc.h | 9 ++-- stm-firmware/main.c | 40 ++++++++++++++- stm-firmware/oven-driver.c | 51 +++++++++++++++++-- stm-firmware/safety-adc.c | 24 +++++++-- 5 files changed, 129 insertions(+), 18 deletions(-) diff --git a/stm-firmware/include/reflow-controller/oven-driver.h b/stm-firmware/include/reflow-controller/oven-driver.h index 7df463c..8a9ac41 100644 --- a/stm-firmware/include/reflow-controller/oven-driver.h +++ b/stm-firmware/include/reflow-controller/oven-driver.h @@ -25,9 +25,28 @@ #include #include +enum oven_pid_error_report { + OVEN_PID_NO_ERROR = 0, + OVEN_PID_ERR_PT1000_ADC_WATCHDOG = (1<<0), + OVEN_PID_ERR_PT1000_ADC_OFF = (1<<1), + OVEN_PID_ERR_PT1000_OTHER = (1<<2), + OVEN_PID_ERR_VREF_TOL = (1<<3), + OVEN_PID_ERR_OVERTEMP = (1<<4), +}; + +struct oven_pid_errors { + bool generic_error; + bool pt1000_adc_watchdog; + bool pt1000_adc_off; + bool pt1000_other; + bool vref_tol; + bool controller_overtemp; +}; + struct oven_pid_status { bool active; bool aborted; + struct oven_pid_errors error_flags; float target_temp; float current_temp; uint64_t timestamp_last_run; @@ -41,11 +60,11 @@ void oven_driver_disable(void); void oven_pid_init(struct pid_controller *controller_to_copy); -void oven_pid_handle(float target_temp, float current_temp); +void oven_pid_handle(float target_temp); void oven_pid_stop(); -void oven_pid_report_error(void); +void oven_pid_report_error(enum oven_pid_error_report report); const struct oven_pid_status *oven_pid_get_status(void); diff --git a/stm-firmware/include/reflow-controller/safety-adc.h b/stm-firmware/include/reflow-controller/safety-adc.h index 9a893fa..8c87f10 100644 --- a/stm-firmware/include/reflow-controller/safety-adc.h +++ b/stm-firmware/include/reflow-controller/safety-adc.h @@ -24,11 +24,10 @@ #include #include -#define SAFETY_ADC_FRAC_BITS (8) -#define SAFETY_ADC_VREF_VOLT (2.5) -#define SAFETY_ADC_VREF_TOL (0.25) -#define SAFETY_ADC_VREF_INT () - +#define SAFETY_ADC_VREF_MVOLT (2500.0f) +#define SAFETY_ADC_VREF_TOL_MVOLT (100.0f) +#define SAFETY_ADC_TEMP_LOW_LIM (0.0f) +#define SAFETY_ADC_TEMP_HIGH_LIM (65.0f) enum safety_adc_meas_channel {SAFETY_ADC_MEAS_VREF, SAFETY_ADC_MEAS_TEMP}; enum safety_adc_check_result { diff --git a/stm-firmware/main.c b/stm-firmware/main.c index ab80078..b39c1b9 100644 --- a/stm-firmware/main.c +++ b/stm-firmware/main.c @@ -198,13 +198,17 @@ static void zero_ccm_ram(void) ptr[i] = 0UL; } +volatile bool error_state = false; +volatile enum safety_adc_check_result safety_adc_status = SAFETY_ADC_CHECK_OK; + int main() { bool sd_card_mounted = false; shellmatta_handle_t shell_handle; int menu_wait_request; uint64_t quarter_sec_timestamp = 0ULL; - enum safety_adc_check_result safety_adc_status; + const struct oven_pid_status *pid_status; + enum adc_pt1000_error pt1000_status; zero_ccm_ram(); setup_system(); @@ -215,14 +219,46 @@ int main() while (1) { sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted); + pid_status = oven_pid_get_status(); + if(systick_ticks_have_passed(quarter_sec_timestamp, 250)) { safety_adc_status = handle_safety_adc(); quarter_sec_timestamp = systick_get_global_tick(); + + if (safety_adc_status & SAFETY_ADC_CHECK_TEMP_LOW || safety_adc_status & SAFETY_ADC_CHECK_TEMP_HIGH) { + oven_pid_report_error(OVEN_PID_ERR_OVERTEMP); + } + + if (safety_adc_status & SAFETY_ADC_CHECK_VREF_LOW || safety_adc_status & SAFETY_ADC_CHECK_VREF_HIGH) { + oven_pid_report_error(OVEN_PID_ERR_VREF_TOL); + } + + if (safety_adc_status & SAFETY_ADC_INTERNAL_ERROR) { + oven_pid_report_error(0); + } + + if (error_state) { + led_set(1, !led_get(1)); + } else { + led_set(1, 0); + } + + pt1000_status = adc_pt1000_check_error(); + + } + + error_state = pid_status->aborted | !!safety_adc_status | !!pt1000_status; + + menu_wait_request = reflow_menu_handle(); + + /* Deactivate oven output in case of error! */ + if (!pid_status->active || pid_status->aborted || error_state) { + oven_pid_stop(); + oven_driver_set_power(0U); } handle_shell_uart_input(shell_handle); - menu_wait_request = reflow_menu_handle(); if (menu_wait_request) __WFI(); diff --git a/stm-firmware/oven-driver.c b/stm-firmware/oven-driver.c index 4084b59..6eb08e2 100644 --- a/stm-firmware/oven-driver.c +++ b/stm-firmware/oven-driver.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include static struct pid_controller oven_pid; @@ -76,29 +78,70 @@ void oven_pid_init(struct pid_controller *controller_to_copy) oven_pid.output_sat_max = 100.0f; oven_pid_current_status.timestamp_last_run = 0ULL; oven_pid_current_status.active = true; + oven_pid_current_status.error_flags.vref_tol = false; + oven_pid_current_status.error_flags.pt1000_other = false; + oven_pid_current_status.error_flags.generic_error = false; + oven_pid_current_status.error_flags.pt1000_adc_off = false; + oven_pid_current_status.error_flags.controller_overtemp = false; + oven_pid_current_status.error_flags.pt1000_adc_watchdog = false; } -void oven_pid_handle(float target_temp, float current_temp) +void oven_pid_handle(float target_temp) { float pid_out; + float current_temp; + int resistance_status; + enum adc_pt1000_error pt1000_error; - if (oven_pid_current_status.active) { + if (oven_pid_current_status.active && !oven_pid_current_status.aborted) { if (systick_ticks_have_passed(oven_pid_current_status.timestamp_last_run, (uint64_t)(oven_pid.sample_period * 1000))) { + + resistance_status = adc_pt1000_get_current_resistance(¤t_temp); + if (resistance_status < 0) { + oven_driver_set_power(0); + pt1000_error = adc_pt1000_check_error(); + if (pt1000_error & ADC_PT1000_WATCHDOG_ERROR) + oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_WATCHDOG); + if (pt1000_error & ADC_PT1000_INACTIVE) + oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_OFF); + if (pt1000_error & ADC_PT1000_OVERFLOW) + oven_pid_report_error(OVEN_PID_ERR_PT1000_OTHER); + + return; + } + + (void)temp_converter_convert_resistance_to_temp(current_temp, ¤t_temp); + pid_out = pid_sample(&oven_pid, target_temp - current_temp); oven_driver_set_power((uint8_t)pid_out); oven_pid_current_status.timestamp_last_run = systick_get_global_tick(); - oven_pid_current_status.active = true; oven_pid_current_status.target_temp = target_temp; oven_pid_current_status.current_temp = current_temp; } } } -void oven_pid_report_error() +void oven_pid_report_error(enum oven_pid_error_report report) { + struct oven_pid_errors *e = &oven_pid_current_status.error_flags; + oven_pid_current_status.active = false; oven_pid_current_status.aborted = true; + + if (report == 0) { + e->generic_error = true; + } + if (report & OVEN_PID_ERR_OVERTEMP) + e->controller_overtemp = true; + if (report & OVEN_PID_ERR_VREF_TOL) + e->controller_overtemp = true; + if (report & OVEN_PID_ERR_PT1000_OTHER) + e->pt1000_other = true; + if (report & OVEN_PID_ERR_PT1000_ADC_OFF) + e->pt1000_adc_off = true; + if (report & OVEN_PID_ERR_PT1000_ADC_WATCHDOG) + e->pt1000_adc_watchdog = true; } const struct oven_pid_status *oven_pid_get_status() diff --git a/stm-firmware/safety-adc.c b/stm-firmware/safety-adc.c index aac2c55..42beb32 100644 --- a/stm-firmware/safety-adc.c +++ b/stm-firmware/safety-adc.c @@ -20,7 +20,7 @@ #include #include - +#include #include void safety_adc_init() @@ -50,18 +50,32 @@ enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint float *vref_calculated, float *temp_calculated) { enum safety_adc_check_result res = SAFETY_ADC_CHECK_OK; + float vref; + float temp; + vref = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result; if (vref_calculated) { - *vref_calculated = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result; + *vref_calculated = vref; } + temp = (((float)temp_result / 4095.0f * 2500.0f - + SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM; if (temp_calculated) { - *temp_calculated = (((float)temp_result / 4095.0f * 2500.0f - - SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM; + *temp_calculated = temp; } - /* TODO: Implement safety ADC checking */ + if (ABS(vref - SAFETY_ADC_VREF_MVOLT) > SAFETY_ADC_VREF_TOL_MVOLT) { + if (vref > SAFETY_ADC_VREF_MVOLT) + res |= SAFETY_ADC_CHECK_VREF_HIGH; + else + res |= SAFETY_ADC_CHECK_VREF_LOW; + } + + if (temp < SAFETY_ADC_TEMP_LOW_LIM) + res |= SAFETY_ADC_CHECK_TEMP_LOW; + else if (temp < SAFETY_ADC_CHECK_TEMP_HIGH) + res |= SAFETY_ADC_CHECK_TEMP_HIGH; return res; }