From e4ebf9ec3f158b96dc6c42a60bab40a527ab0338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Fri, 23 Jul 2021 20:06:09 +0200 Subject: [PATCH] Add CRC monitoring over ADC registers --- stm-firmware/adc-meas.c | 4 + .../reflow-controller/safety/safety-config.h | 24 ++- .../safety/safety-controller.h | 8 + stm-firmware/safety/safety-adc.c | 5 + stm-firmware/safety/safety-controller.c | 168 ++++++++++++++++++ 5 files changed, 208 insertions(+), 1 deletion(-) diff --git a/stm-firmware/adc-meas.c b/stm-firmware/adc-meas.c index 10cf853..b98b4a2 100644 --- a/stm-firmware/adc-meas.c +++ b/stm-firmware/adc-meas.c @@ -82,6 +82,8 @@ static inline void adc_pt1000_disable_adc(void) ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON; DMA2_Stream0->CR = 0; + safety_controller_set_crc_monitor(ERR_CRC_MON_MEAS_ADC, SAFETY_CRC_MON_MEAS_ADC_PW); + safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY); safety_controller_enable_timing_mon(ERR_TIMING_MEAS_ADC, false); rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN)); @@ -181,6 +183,8 @@ void adc_pt1000_setup_meas(void) streaming_flag_ptr = NULL; adc_watchdog_counter = 0UL; stream_buffer = NULL; + + safety_controller_set_crc_monitor(ERR_CRC_MON_MEAS_ADC, SAFETY_CRC_MON_MEAS_ADC_PW); } void adc_pt1000_set_moving_average_filter_param(float alpha) diff --git a/stm-firmware/include/reflow-controller/safety/safety-config.h b/stm-firmware/include/reflow-controller/safety/safety-config.h index e64a957..1afd24e 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-config.h +++ b/stm-firmware/include/reflow-controller/safety/safety-config.h @@ -58,6 +58,8 @@ enum safety_flag { ERR_FLAG_OVERTEMP = (1<<18), ERR_FLAG_FLASH_CRC_CODE = (1<<19), ERR_FLAG_FLASH_CRC_DATA = (1<<20), + ERR_FLAG_CFG_CRC_MEAS_ADC = (1<<21), + ERR_FLAG_CFG_CRC_SAFETY_ADC = (1<<22), }; /** @@ -73,6 +75,12 @@ enum timing_monitor { ERR_TIMING_MAIN_LOOP = (1<<3), }; +enum crc_monitor { + ERR_CRC_MON_MEAS_ADC = 0, + ERR_CRC_MON_SAFETY_ADC, + N_ERR_CRC_MON +}; + /** * @brief Enum Type representing analog value monitors. * @@ -146,6 +154,16 @@ enum analog_value_monitor { */ #define SAFETY_CONTROLLER_ADC_DELAY_MS 250 +/** + * @brief Password for resetting ERR_CRC_MON_MEAS_ADC + */ +#define SAFETY_CRC_MON_MEAS_ADC_PW 0xD96254A2 + +/** + * @brief Password for resetting ERR_CRC_MON_SAFETY_ADC + */ +#define SAFETY_CRC_MON_SAFETY_ADC_PW 0xA8DF2368 + /** * @brief Default persistence of safety flags. These values are loaded into the safety tables on startup */ @@ -169,7 +187,9 @@ enum analog_value_monitor { ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_AMON_SUPPLY_VOLT, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_OVERTEMP, false), \ ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_CODE, true), \ - ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true) + ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_FLASH_CRC_DATA, true), \ + ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, true), \ + ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, true), \ /** * @brief Default config weights of safety flags. These values are loaded into the safety tables on startup */ @@ -194,5 +214,7 @@ enum analog_value_monitor { ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_OVERTEMP, SAFETY_FLAG_CONFIG_WEIGHT_PID), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_CODE, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_FLASH_CRC_DATA, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ + ERR_FLAG_WEIGHT_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC, SAFETY_FLAG_CONFIG_WEIGHT_NONE), \ #endif /* __SAFETY_CONFIG_H__ */ diff --git a/stm-firmware/include/reflow-controller/safety/safety-controller.h b/stm-firmware/include/reflow-controller/safety/safety-controller.h index 55883bc..a882d69 100644 --- a/stm-firmware/include/reflow-controller/safety/safety-controller.h +++ b/stm-firmware/include/reflow-controller/safety/safety-controller.h @@ -274,6 +274,14 @@ float safety_controller_get_overtemp_limit(void); */ int safety_controller_trigger_flash_crc_check(void); +/** + * @brief Recalculate the CRC of a given CRC Monitor. This has to be done once the supervised registers update + * @param mon Monitor to recalculate + * @param password Password + * @return 0 if successful + */ +int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password); + #endif /* __SAFETY_CONTROLLER_H__ */ /** @} */ diff --git a/stm-firmware/safety/safety-adc.c b/stm-firmware/safety/safety-adc.c index 04e4f3d..be10bbb 100644 --- a/stm-firmware/safety/safety-adc.c +++ b/stm-firmware/safety/safety-adc.c @@ -28,6 +28,7 @@ #include #include #include +#include static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS}; static volatile uint8_t safety_adc_conversion_complete; @@ -86,7 +87,9 @@ void safety_adc_init(void) NVIC_EnableIRQ(DMA2_Stream4_IRQn); /* Enable ADC */ + SAFETY_ADC_ADC_PERIPHERAL->CR1 |= ADC_CR1_SCAN; SAFETY_ADC_ADC_PERIPHERAL->CR2 = ADC_CR2_ADON | ADC_CR2_DMA | ADC_CR2_DDS; + safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW); } @@ -95,9 +98,11 @@ void safety_adc_deinit(void) SAFETY_ADC_ADC_PERIPHERAL->CR1 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL; + rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN)); DMA2_Stream4->CR = 0; rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN)); + safety_controller_set_crc_monitor(ERR_CRC_MON_SAFETY_ADC, SAFETY_CRC_MON_SAFETY_ADC_PW); } float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value) diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index 58cd1dd..84c02d4 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -43,6 +43,7 @@ #include #include #include +#include /** * @brief Macro that checks if a given @ref error_flag is persistent @@ -162,6 +163,28 @@ struct flash_crcs { uint32_t end_magic; }; +struct crc_monitor_register { + const volatile void *reg_addr; + uint32_t mask; + uint8_t size; +}; + +#define CRC_MON_REGISTER_ENTRY(_addr, _mask, _size) {.reg_addr = &(_addr), .mask = (_mask), .size = (_size)} + +struct crc_mon { + /** + * @brief Array of registers to monitor. Terminated by NULL sentinel! + */ + const struct crc_monitor_register *registers; + const enum crc_monitor monitor; + const uint32_t pw; + const enum safety_flag flag_to_set; + uint32_t expected_crc; + uint32_t expected_crc_inv; + uint32_t last_crc; + bool active; +}; + /** * @brief All safety error flags. */ @@ -187,6 +210,8 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { ERR_FLAG_ENTRY(ERR_FLAG_OVERTEMP), ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_CODE), ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA), + ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_MEAS_ADC), + ERR_FLAG_ENTRY(ERR_FLAG_CFG_CRC_SAFETY_ADC), }; /** @@ -259,6 +284,64 @@ static uint32_t IN_SECTION(.ccm.bss) flag_weight_crc; */ static struct overtemp_config IN_SECTION(.ccm.bss) safety_controller_overtemp_config; +static const struct crc_monitor_register meas_adc_crc_regs[] = { + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->CR1, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->CR2, ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_ALIGN | + ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_EOCS | ADC_CR2_EXTEN | ADC_CR2_EXTSEL, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SMPR1, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SMPR2, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->HTR, ADC_HTR_HT, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->LTR, ADC_LTR_LT, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR1, ADC_SQR1_L | + ADC_SQR1_SQ16 | ADC_SQR1_SQ15 | ADC_SQR1_SQ14 | ADC_SQR1_SQ13, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR2, + ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 | + ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4), + CRC_MON_REGISTER_ENTRY(ADC_PT1000_PERIPH->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 | + ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), + {NULL, 0, 0} +}; + +static const struct crc_monitor_register safety_adc_crc_regs[] = { + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->CR1, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->CR2, ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_ALIGN | + ADC_CR2_DMA | ADC_CR2_DDS | ADC_CR2_EOCS | ADC_CR2_EXTEN | ADC_CR2_EXTSEL, 4), + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SMPR1, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SMPR2, 0xFFFFFFFF, 4), + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR1, ADC_SQR1_L | + ADC_SQR1_SQ16 | ADC_SQR1_SQ15 | ADC_SQR1_SQ14 | ADC_SQR1_SQ13, 4), + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR2, + ADC_SQR2_SQ12 | ADC_SQR2_SQ11 | ADC_SQR2_SQ10 | ADC_SQR2_SQ9 | + ADC_SQR2_SQ8 | ADC_SQR2_SQ7, 4), + CRC_MON_REGISTER_ENTRY(SAFETY_ADC_ADC_PERIPHERAL->SQR3, ADC_SQR3_SQ6 | ADC_SQR3_SQ5 | ADC_SQR3_SQ4 | + ADC_SQR3_SQ3| ADC_SQR3_SQ2 | ADC_SQR3_SQ1, 4), + {NULL, 0, 0} +}; + +static struct crc_mon IN_SECTION(.ccm.data) crc_monitors[] = +{ + { + .registers = meas_adc_crc_regs, + .monitor = ERR_CRC_MON_MEAS_ADC, + .pw = SAFETY_CRC_MON_MEAS_ADC_PW, + .flag_to_set = ERR_FLAG_CFG_CRC_MEAS_ADC, + .expected_crc = 0UL, + .expected_crc_inv = ~0UL, + .last_crc = 0UL, + .active = false, + }, + { + .registers = safety_adc_crc_regs, + .monitor = ERR_CRC_MON_SAFETY_ADC, + .pw = SAFETY_CRC_MON_SAFETY_ADC_PW, + .flag_to_set = ERR_FLAG_CFG_CRC_SAFETY_ADC, + .expected_crc = 0UL, + .expected_crc_inv = ~0UL, + .last_crc = 0UL, + .active = false, + }, +}; + /** * @brief Configure the overtemperature flag's settings * @param over_temperature Temperature to set the limit to. @@ -389,6 +472,62 @@ static volatile struct error_flag *find_error_flag(enum safety_flag flag) return ret; } +static int crc_monitor_calculate_crc(const struct crc_monitor_register *registers, uint32_t *crc_out) +{ + const struct crc_monitor_register *reg; + uint32_t i; + uint32_t reg_val; + + if (!registers || !crc_out) + return -1000; + + crc_unit_reset(); + for (i = 0; registers[i].reg_addr != NULL; i++) { + reg = ®isters[i]; + switch (reg->size) { + case 1: + reg_val = *((volatile uint8_t *)reg->reg_addr); + break; + case 2: + reg_val = *((volatile uint16_t *)reg->reg_addr); + break; + case 4: /* FALLTHRU */ + default: + reg_val = *((volatile uint32_t *)reg->reg_addr); + break; + } + + reg_val &= reg->mask; + crc_unit_input(reg_val); + } + + *crc_out = crc_unit_get_crc(); + + return 0; +} + +static int safety_controller_check_crc_monitors(void) +{ + uint32_t i; + struct crc_mon *mon; + uint32_t crc; + + for (i = 0; i < COUNT_OF(crc_monitors); i++) { + mon = &crc_monitors[i]; + if (!mon->active) + continue; + + if (crc_monitor_calculate_crc(mon->registers, &crc)) + return -1; + if (mon->expected_crc != crc || ~mon->expected_crc_inv != crc) { + safety_controller_report_error(mon->flag_to_set); + } + mon->last_crc = crc; + } + + return 0; +} + /** * @brief This function copies the safety weigths from flash ro RAM and computes the CRC */ @@ -608,6 +747,8 @@ static void safety_controller_process_monitor_checks(void) safety_controller_report_error(ERR_FLAG_OVERTEMP); } + (void)safety_controller_check_crc_monitors(); + safety_controller_process_active_timing_mons(); } @@ -1406,4 +1547,31 @@ int safety_controller_trigger_flash_crc_check() return ret; } +int safety_controller_set_crc_monitor(enum crc_monitor mon, uint32_t password) +{ + uint32_t i; + struct crc_mon *monitor; + uint32_t crc; + + for (i = 0; i < COUNT_OF(crc_monitors); i++) { + monitor = &crc_monitors[i]; + if (monitor->monitor != mon) + continue; + + monitor->active = true; + + if (password != monitor->pw) + return -1002; + + (void)crc_monitor_calculate_crc(monitor->registers, &crc); + monitor->expected_crc = crc; + monitor->expected_crc_inv = ~crc; + monitor->last_crc = crc; + + return 0; + } + + return -1001; +} + /** @} */