Add CRC monitoring over ADC registers
This commit is contained in:
@@ -43,6 +43,7 @@
|
||||
#include <stm-periph/rcc-manager.h>
|
||||
#include <reflow-controller/temp-converter.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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
Reference in New Issue
Block a user