Add CRC monitoring over ADC registers

This commit is contained in:
Mario Hüttel 2021-07-23 20:06:09 +02:00
parent 6e89c0e098
commit e4ebf9ec3f
5 changed files with 208 additions and 1 deletions

View File

@ -82,6 +82,8 @@ static inline void adc_pt1000_disable_adc(void)
ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON; ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON;
DMA2_Stream0->CR = 0; 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_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
safety_controller_enable_timing_mon(ERR_TIMING_MEAS_ADC, false); safety_controller_enable_timing_mon(ERR_TIMING_MEAS_ADC, false);
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN)); 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; streaming_flag_ptr = NULL;
adc_watchdog_counter = 0UL; adc_watchdog_counter = 0UL;
stream_buffer = NULL; 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) void adc_pt1000_set_moving_average_filter_param(float alpha)

View File

@ -58,6 +58,8 @@ enum safety_flag {
ERR_FLAG_OVERTEMP = (1<<18), ERR_FLAG_OVERTEMP = (1<<18),
ERR_FLAG_FLASH_CRC_CODE = (1<<19), ERR_FLAG_FLASH_CRC_CODE = (1<<19),
ERR_FLAG_FLASH_CRC_DATA = (1<<20), 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), 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. * @brief Enum Type representing analog value monitors.
* *
@ -146,6 +154,16 @@ enum analog_value_monitor {
*/ */
#define SAFETY_CONTROLLER_ADC_DELAY_MS 250 #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 * @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_AMON_SUPPLY_VOLT, false), \
ERR_FLAG_PERSIST_ENTRY(ERR_FLAG_OVERTEMP, 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_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 * @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_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_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_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__ */ #endif /* __SAFETY_CONFIG_H__ */

View File

@ -274,6 +274,14 @@ float safety_controller_get_overtemp_limit(void);
*/ */
int safety_controller_trigger_flash_crc_check(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__ */ #endif /* __SAFETY_CONTROLLER_H__ */
/** @} */ /** @} */

View File

@ -28,6 +28,7 @@
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <reflow-controller/hw-version-detect.h> #include <reflow-controller/hw-version-detect.h>
#include <reflow-controller/safety/safety-controller.h>
static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS}; static const uint8_t safety_adc_channels[SAFETY_ADC_NUM_OF_CHANNELS] = {SAFETY_ADC_CHANNELS};
static volatile uint8_t safety_adc_conversion_complete; static volatile uint8_t safety_adc_conversion_complete;
@ -86,7 +87,9 @@ void safety_adc_init(void)
NVIC_EnableIRQ(DMA2_Stream4_IRQn); NVIC_EnableIRQ(DMA2_Stream4_IRQn);
/* Enable ADC */ /* 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_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->CR1 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->CR2 = 0UL;
SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL; SAFETY_ADC_ADC_PERIPHERAL->SMPR1 = 0UL;
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN)); rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
DMA2_Stream4->CR = 0; DMA2_Stream4->CR = 0;
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(RCC_AHB1ENR_DMA2EN)); 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) float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)

View File

@ -43,6 +43,7 @@
#include <stm-periph/rcc-manager.h> #include <stm-periph/rcc-manager.h>
#include <reflow-controller/temp-converter.h> #include <reflow-controller/temp-converter.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/periph-config/safety-adc-hwcfg.h>
/** /**
* @brief Macro that checks if a given @ref error_flag is persistent * @brief Macro that checks if a given @ref error_flag is persistent
@ -162,6 +163,28 @@ struct flash_crcs {
uint32_t end_magic; 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. * @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_OVERTEMP),
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_CODE), ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_CODE),
ERR_FLAG_ENTRY(ERR_FLAG_FLASH_CRC_DATA), 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 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 * @brief Configure the overtemperature flag's settings
* @param over_temperature Temperature to set the limit to. * @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; 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 = &registers[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 * @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); safety_controller_report_error(ERR_FLAG_OVERTEMP);
} }
(void)safety_controller_check_crc_monitors();
safety_controller_process_active_timing_mons(); safety_controller_process_active_timing_mons();
} }
@ -1406,4 +1547,31 @@ int safety_controller_trigger_flash_crc_check()
return ret; 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;
}
/** @} */ /** @} */