From 9880c701b1fb89d6065b6676eeb8c1a8d9711f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sun, 6 Sep 2020 19:52:44 +0200 Subject: [PATCH 1/2] Issue #15: Introduce safety weigths --- .../include/reflow-controller/safety/safety-memory.h | 12 ++++++++++++ stm-firmware/safety/safety-controller.c | 12 +++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/stm-firmware/include/reflow-controller/safety/safety-memory.h b/stm-firmware/include/reflow-controller/safety/safety-memory.h index 18946ac..6e360bd 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-memory.h +++ b/stm-firmware/include/reflow-controller/safety/safety-memory.h @@ -103,6 +103,18 @@ enum config_override_entry_type { SAFETY_MEMORY_CONFIG_OVERRIDE_PERSISTANCE = 2, }; +/** + * @brief Weights of error flags. + */ +enum config_override_weight { + SAFETY_MEMORY_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */ + SAFETY_MEMORY_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */ + SAFETY_MEMORY_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */ +}; + +/** + * @brief representation of a config override memory entry + */ struct config_override { enum config_override_entry_type type; union { diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index f38aa2e..8a8e5cc 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include s struct error_flag { const char *name; @@ -69,6 +69,11 @@ struct analog_mon { uint64_t timestamp; }; +struct safety_weight { + enum config_override_weight weight; + enum safety_flag flag; +}; + #ifdef COUNT_OF #undef COUNT_OF #endif @@ -78,6 +83,7 @@ struct analog_mon { #define ERR_FLAG_ENTRY(errflag, persistency) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .persistent = (persistency), .key = 0UL} #define TIM_MON_ENTRY(mon, min, max, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false} #define ANA_MON_ENTRY(mon, min_value, max_value, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false} +#define ERR_FLAG_WEIGTH() static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), @@ -112,6 +118,10 @@ static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = { ERR_FLAG_AMON_UC_TEMP), }; +static volatile struct safety_weight IN_SECTION(.ccm.data) flag_weigths[] = { + +} + static bool error_flag_get_status(const volatile struct error_flag *flag) { if (flag->error_state == flag->error_state_inv) { From 403786e0c67885be4f6acae70020fad0fd2e29c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sun, 6 Sep 2020 21:05:00 +0200 Subject: [PATCH 2/2] Issue #15: Implement safety weight table * CRC protected flag weight table. * Currently only filled with dummy values. Has to be finished in issue #5 * Config overrides from safety memor ynot yet implemented --- .../include/helper-macros/helper-macros.h | 1 + .../reflow-controller/safety/safety-memory.h | 10 +- stm-firmware/safety/safety-controller.c | 146 +++++++++++++----- stm-firmware/safety/safety-memory.c | 3 +- 4 files changed, 118 insertions(+), 42 deletions(-) diff --git a/stm-firmware/include/helper-macros/helper-macros.h b/stm-firmware/include/helper-macros/helper-macros.h index bafdc91..eafc4b6 100644 --- a/stm-firmware/include/helper-macros/helper-macros.h +++ b/stm-firmware/include/helper-macros/helper-macros.h @@ -30,6 +30,7 @@ #define CONCAT(x,y) x##y #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#define wordsize_of(x) ((sizeof(x) / 4U) / ((sizeof(x) % 4U) ? 0U : 1U)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) diff --git a/stm-firmware/include/reflow-controller/safety/safety-memory.h b/stm-firmware/include/reflow-controller/safety/safety-memory.h index 4c960ce..303d8ca 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-memory.h +++ b/stm-firmware/include/reflow-controller/safety/safety-memory.h @@ -124,10 +124,10 @@ enum config_override_entry_type { /** * @brief Weights of error flags. */ -enum config_override_weight { - SAFETY_MEMORY_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */ - SAFETY_MEMORY_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */ - SAFETY_MEMORY_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */ +enum config_weight { + SAFETY_FLAG_CONFIG_WEIGHT_NONE = 0, /**< @brief This flag has no global error consequence, but might be respected by certain software modules. */ + SAFETY_FLAG_CONFIG_WEIGHT_PID = 1, /**< @brief This flag will force a stop of the temperature PID controller */ + SAFETY_FLAG_CONFIG_WEIGHT_PANIC = 2, /**< @brief This flag will trigger the panic mode */ }; /** @@ -138,7 +138,7 @@ struct config_override { union { struct { uint8_t flag; - enum config_override_weight weight; + enum config_weight weight; } weight_override; struct { uint8_t flag; diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index 74371d5..42396ba 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ #include #include #include -#include s +#include struct error_flag { const char *name; @@ -70,20 +71,17 @@ struct analog_mon { }; struct safety_weight { - enum config_override_weight weight; + uint32_t start_dummy; + enum config_weight weight; enum safety_flag flag; + volatile struct error_flag *flag_ptr; + uint32_t end_dummy; }; -#ifdef COUNT_OF -#undef COUNT_OF -#endif - -#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) - #define ERR_FLAG_ENTRY(errflag, persistency) {.name=#errflag, .flag = (errflag), .error_state = false, .error_state_inv = true, .persistent = (persistency), .key = 0UL} #define TIM_MON_ENTRY(mon, min, max, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false} #define ANA_MON_ENTRY(mon, min_value, max_value, flag) {.name=#mon, .monitor = (mon), .associated_flag=(flag), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false} -#define ERR_FLAG_WEIGTH() +#define ERR_FLAG_WEIGHT_ENTRY(_flag, _weight) {.flag = (_flag), .flag_ptr = NULL, .weight = (_weight), .start_dummy = 0x11823344, .end_dummy = 0xAABBCCFD} static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), @@ -118,8 +116,73 @@ static volatile struct analog_mon IN_SECTION(.ccm.data) analog_mons[] = { ERR_FLAG_AMON_UC_TEMP), }; -static volatile struct safety_weight IN_SECTION(.ccm.data) flag_weigths[] = { +static const struct safety_weight default_flag_weights[] = { + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OFF, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_WATCHDOG, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_UNSTABLE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_MEAS_ADC_OVERFLOW, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_PID, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_UC_TEMP, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_AMON_VREF, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_STACK, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SYSTICK, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_WTCHDG_FIRED, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_UNCAL, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_DEBUG, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_TIMING_MAIN_LOOP, SAFETY_FLAG_CONFIG_WEIGHT_NONE), + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_SAFETY_MEM_CORRUPT, SAFETY_FLAG_CONFIG_WEIGHT_NONE), +}; +static volatile struct safety_weight IN_SECTION(.ccm.bss) flag_weights[COUNT_OF(default_flag_weights)]; +static uint32_t IN_SECTION(.ccm.data) flag_weight_crc; + +static int flag_weight_table_crc_check(void) +{ + /* Check the flag weight table */ + crc_unit_reset(); + crc_unit_input_array((uint32_t *)flag_weights, wordsize_of(flag_weights)); + + if (crc_unit_get_crc() != flag_weight_crc) + return -1; + + return 0; +} + +static volatile struct error_flag *find_error_flag(enum safety_flag flag) +{ + uint32_t i; + volatile struct error_flag *ret = NULL; + + for (i = 0; i < COUNT_OF(flags); i++) { + if (flags[i].flag == flag) + ret = &flags[i]; + } + + return ret; +} + +/** + * @brief This function copies the safety weigths from flash ro RAM and computes the CRC + */ +static void init_safety_flag_weight_table_from_default(void) +{ + uint32_t index; + volatile struct safety_weight *current_weight; + + /* Copy the table */ + memcpy((void *)flag_weights, default_flag_weights, wordsize_of(flag_weights)); + + /* Fill in the flag pointers */ + for (index = 0; index < COUNT_OF(flag_weights); index++) { + current_weight = &flag_weights[index]; + current_weight->flag_ptr = find_error_flag(current_weight->flag); + } + + crc_unit_reset(); + crc_unit_input_array((uint32_t*)flag_weights, wordsize_of(flag_weights)); + flag_weight_crc = crc_unit_get_crc(); } static bool error_flag_get_status(const volatile struct error_flag *flag) @@ -157,19 +220,6 @@ static volatile struct timing_mon *find_timing_mon(enum timing_monitor mon) return ret; } -static volatile struct error_flag *find_error_flag(enum safety_flag flag) -{ - uint32_t i; - volatile struct error_flag *ret = NULL; - - for (i = 0; i < COUNT_OF(flags); i++) { - if (flags[i].flag == flag) - ret = &flags[i]; - } - - return ret; -} - static void safety_controller_process_active_timing_mons() { uint32_t i; @@ -188,7 +238,7 @@ static void safety_controller_process_active_timing_mons() } } -static void safety_controller_process_checks() +static void safety_controller_process_monitor_checks() { static bool startup_completed = false; enum analog_monitor_status amon_state; @@ -293,6 +343,12 @@ void safety_controller_init() /* Trigger panic mode! */ panic_mode(); } + + /* This is usually done by the safety memory already. But, since this module also uses the CRC... */ + crc_unit_init(); + + init_safety_flag_weight_table_from_default(); + if (found_memory_state == SAFETY_MEMORY_INIT_CORRUPTED) safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); @@ -364,35 +420,39 @@ static void safety_controller_handle_safety_adc() } } -static void safety_controller_handle_safety_memory_check(void) +/** + * @brief Check the memory structures. + * @return 0 if okay, != 0 when an error was detected. PANIC mode shall be entered in this case. + */ +static int safety_controller_handle_memory_checks(void) { static uint64_t ts = 0; enum safety_memory_state found_state; + int panic_request = 0; - if (systick_ticks_have_passed(ts, 5000)) { + if (systick_ticks_have_passed(ts, 1000)) { ts = systick_get_global_tick(); + /* Check the safety memory */ if (safety_memory_check()) { - safety_memory_reinit(&found_state); + (void)safety_memory_reinit(&found_state); if (found_state != SAFETY_MEMORY_INIT_VALID_MEMORY) { safety_controller_report_error(ERR_FLAG_SAFETY_MEM_CORRUPT); } } + + panic_request = flag_weight_table_crc_check(); } + + return panic_request; } -int safety_controller_handle() +static void safety_controller_do_systick_checking() { static uint64_t last_systick; static uint32_t same_systick_cnt = 0UL; uint64_t systick; - int ret = 0; - - safety_controller_check_stack(); - safety_controller_handle_safety_adc(); - safety_controller_handle_safety_memory_check(); - systick = systick_get_global_tick(); if (systick == last_systick) { same_systick_cnt++; @@ -402,8 +462,24 @@ int safety_controller_handle() same_systick_cnt = 0UL; } last_systick = systick; +} - safety_controller_process_checks(); +int safety_controller_handle() +{ + int panic_requested; + int ret = 0; + + safety_controller_check_stack(); + safety_controller_handle_safety_adc(); + panic_requested = safety_controller_handle_memory_checks(); + + /* Panic here. If our internal structures are broken, we cannot be sure of anything anymore */ + if (panic_requested) + panic_mode(); + + safety_controller_do_systick_checking(); + + safety_controller_process_monitor_checks(); /* TODO: Check flags for PID and HALT */ ret |= watchdog_ack(WATCHDOG_MAGIC_KEY); diff --git a/stm-firmware/safety/safety-memory.c b/stm-firmware/safety/safety-memory.c index 6b21b63..4076c73 100644 --- a/stm-firmware/safety/safety-memory.c +++ b/stm-firmware/safety/safety-memory.c @@ -19,11 +19,10 @@ */ #include +#include #include #include -#define wordsize_of(x) ((sizeof(x) / 4U) / ((sizeof(x) % 4U) ? 0U : 1U)) - static int word_to_error_memory_entry(uint32_t entry_data, struct error_memory_entry *out) { int ret = 0;