From a04e894518527551007e7ae71d7b77be4ddfabba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sun, 26 Jul 2020 21:40:09 +0200 Subject: [PATCH] Further work on safety controller --- .../reflow-controller/safety/safety-config.h | 6 + .../safety/safety-controller.h | 4 +- stm-firmware/safety/safety-controller.c | 155 +++++++++++++++++- 3 files changed, 159 insertions(+), 6 deletions(-) diff --git a/stm-firmware/include/reflow-controller/safety/safety-config.h b/stm-firmware/include/reflow-controller/safety/safety-config.h index b15ddcf..4e88316 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-config.h +++ b/stm-firmware/include/reflow-controller/safety/safety-config.h @@ -32,6 +32,8 @@ enum safety_flag { ERR_FLAG_AMON_VREF = (1<<6), ERR_FLAG_AMON_UC_TEMP = (1<<7), ERR_FLAG_STACK = (1<<8), + ERR_FLAG_SAFETY_ADC = (1<<9), + ERR_FLAG_SYSTICK = (1<<10), }; enum timing_monitor { @@ -51,12 +53,16 @@ enum analog_value_monitor { */ #define WATCHDOG_MAGIC_KEY 0x1a2c56F4 +#ifdef DEBUGBUILD /** * @brief If one, the watchdog is halted whenever the core is halted by the debugger. * * This is only applicable in a debug build. In release mode, the watchdog stays always enabled */ #define WATCHDOG_HALT_DEBUG (1) +#else +#define WATCHDOG_HALT_DEBUG (0) +#endif #define WATCHDOG_PRESCALER 4 diff --git a/stm-firmware/include/reflow-controller/safety/safety-controller.h b/stm-firmware/include/reflow-controller/safety/safety-controller.h index 8a31b3b..36be0f0 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-controller.h +++ b/stm-firmware/include/reflow-controller/safety/safety-controller.h @@ -62,7 +62,9 @@ int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable enum analog_monitor_status safety_controller_get_analog_mon_value(enum analog_value_monitor monitor, float *value); -bool safety_controller_get_flag(enum safety_flag); +int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack); + +int safety_controller_ack_flag(enum safety_flag flag); #endif /* __SAFETY_CONTROLLER_H__ */ diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index 112dd35..4881927 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -81,16 +82,21 @@ static struct error_flag flags[] = { ERR_FLAG_ENTRY(ERR_FLAG_AMON_UC_TEMP, true), ERR_FLAG_ENTRY(ERR_FLAG_AMON_VREF, false), ERR_FLAG_ENTRY(ERR_FLAG_STACK, true), + ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_ADC, true), + ERR_FLAG_ENTRY(ERR_FLAG_SYSTICK, true), }; static struct timing_mon timings[] = { TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800, ERR_FLAG_TIMING_PID), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50, ERR_FLAG_TIMING_MEAS_ADC), + TIM_MON_ENTRY(ERR_TIMING_SAFETY_ADC, 1, 250, ERR_FLAG_SAFETY_ADC), }; static struct analog_mon analog_mons[] = { - ANA_MON_ENTRY(ERR_AMON_VREF, 2480.0f, 2520.0f, ERR_FLAG_AMON_VREF), - ANA_MON_ENTRY(ERR_AMON_UC_TEMP, 0.0f, 55.0f, ERR_FLAG_AMON_UC_TEMP), + ANA_MON_ENTRY(ERR_AMON_VREF, SAFETY_ADC_VREF_MVOLT - SAFETY_ADC_VREF_TOL_MVOLT, + SAFETY_ADC_VREF_MVOLT + SAFETY_ADC_VREF_TOL_MVOLT, ERR_FLAG_AMON_VREF), + ANA_MON_ENTRY(ERR_AMON_UC_TEMP, SAFETY_ADC_TEMP_LOW_LIM, SAFETY_ADC_TEMP_HIGH_LIM, + ERR_FLAG_AMON_UC_TEMP), }; static struct analog_mon *find_analog_mon(enum analog_value_monitor mon) @@ -132,9 +138,49 @@ static struct error_flag *find_error_flag(enum safety_flag flag) return ret; } +static void safety_controller_process_active_timing_mons() +{ + uint32_t i; + struct timing_mon *current_mon; + + for (i = 0; i < COUNT_OF(timings); i++) { + current_mon = &timings[i]; + if (current_mon->enabled) { + if (systick_ticks_have_passed(current_mon->last, current_mon->max_delta)) + safety_controller_report_error(current_mon->associated_flag); + } + } +} + static void safety_controller_process_checks() { - // TODO: Implement + static bool startup_completed = false; + static uint64_t last_systick = 0; + enum analog_monitor_status amon_state; + float amon_value; + uint64_t systick; + + systick = systick_get_global_tick(); + if (systick == last_systick) { + safety_controller_report_error(ERR_FLAG_SYSTICK); + } + + if (systick >= 1000) { + startup_completed = true; + } + + if (startup_completed) { + amon_state = safety_controller_get_analog_mon_value(ERR_AMON_VREF, &amon_value); + if (amon_state != ANALOG_MONITOR_OK) + safety_controller_report_error(ERR_FLAG_AMON_VREF); + amon_state = safety_controller_get_analog_mon_value(ERR_AMON_UC_TEMP, &amon_value); + if (amon_state != ANALOG_MONITOR_OK) + safety_controller_report_error(ERR_FLAG_AMON_UC_TEMP); + + } + + safety_controller_process_active_timing_mons(); + } int safety_controller_report_error(enum safety_flag flag) @@ -156,7 +202,6 @@ int safety_controller_report_error(enum safety_flag flag) void safety_controller_report_timing(enum timing_monitor monitor) { - uint32_t i; struct timing_mon *tim; uint64_t timestamp; @@ -164,6 +209,12 @@ void safety_controller_report_timing(enum timing_monitor monitor) tim = find_timing_mon(monitor); if (tim) { + if (tim->enabled) { + if (!systick_ticks_have_passed(tim->last, tim->min_delta)) { + safety_controller_report_error(tim->associated_flag); + } + } + tim->last = timestamp; tim->enabled = true; } @@ -193,13 +244,65 @@ void safety_controller_init() watchdog_setup(WATCHDOG_PRESCALER); } +static void safety_controller_check_stack() +{ + int32_t free_stack; + + free_stack = stack_check_get_free(); + if (free_stack < SAFETY_MIN_STACK_FREE) + safety_controller_report_error(ERR_FLAG_STACK); +} + +static void safety_controller_handle_safety_adc() +{ + static enum safety_adc_meas_channel current_channel = SAFETY_ADC_MEAS_TEMP; + int poll_result; + uint16_t result; + float analog_value; + + poll_result = safety_adc_poll_result(&result); + if (poll_result) { + if (poll_result == -1) { + switch (current_channel) { + case SAFETY_ADC_MEAS_TEMP: + current_channel = SAFETY_ADC_MEAS_VREF; + break; + case SAFETY_ADC_MEAS_VREF: + /* Expected fallthru */ + default: + current_channel = SAFETY_ADC_MEAS_TEMP; + break; + } + + safety_adc_trigger_meas(current_channel); + } else if (poll_result == 1) { + analog_value = safety_adc_convert_channel(current_channel, result); + safety_controller_report_timing(ERR_TIMING_SAFETY_ADC); + switch (current_channel) { + case SAFETY_ADC_MEAS_TEMP: + safety_controller_report_analog_value(ERR_AMON_UC_TEMP, analog_value); + break; + case SAFETY_ADC_MEAS_VREF: + safety_controller_report_analog_value(ERR_AMON_VREF, analog_value); + break; + default: + safety_controller_report_error(ERR_FLAG_SAFETY_ADC); + break; + } + } + } +} + int safety_controller_handle() { static int ret = 0; - /* TODO: Handle safety ADC */ + safety_controller_check_stack(); + safety_controller_handle_safety_adc(); + + safety_controller_process_checks(); /* TODO: Check flags for PID and HALT */ @@ -255,4 +358,46 @@ go_out: return ret; } +int safety_controller_get_flag(enum safety_flag flag, bool *status, bool try_ack) +{ + struct error_flag *found_flag; + int ret = -1; + + if (!status) + return -1002; + if (!is_power_of_two(flag)) + return -1001; + + found_flag = find_error_flag(flag); + if (found_flag) { + *status = found_flag->error_state; + if (try_ack && !found_flag->persistent) + found_flag->error_state = false; + } + + return ret; +} + +int safety_controller_ack_flag(enum safety_flag flag) +{ + int ret = -1; + struct error_flag *found_flag; + + if (!is_power_of_two(flag)) { + return -1001; + } + + found_flag = find_error_flag(flag); + if (found_flag) { + if (!found_flag->persistent) { + found_flag->error_state = false; + ret = 0; + } else { + ret = -2; + } + } + + return ret; +} + /** @} */