Further rewrite safety handling

This commit is contained in:
2020-07-09 22:31:42 +02:00
parent 5eb51f08b6
commit 9136dc196c
11 changed files with 209 additions and 318 deletions

View File

@@ -28,24 +28,10 @@
#include <helper-macros/helper-macros.h>
#include <stm-periph/clock-enable-manager.h>
enum safety_adc_check_result global_safety_adc_status;
enum safety_adc_check_result safety_adc_get_errors()
{
return global_safety_adc_status;
}
void safety_adc_clear_errors(void)
{
global_safety_adc_status = SAFETY_ADC_CHECK_OK;
}
void safety_adc_init()
{
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
safety_adc_clear_errors();
/* Enable temperature and VREFINT measurement */
ADC->CCR |= ADC_CCR_TSVREFE;
@@ -65,38 +51,27 @@ void safety_adc_deinit()
rcc_manager_enable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC2EN));
}
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
float *vref_calculated, float *temp_calculated)
float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
{
enum safety_adc_check_result res = SAFETY_ADC_CHECK_OK;
float vref;
float temp;
float converted_val;
vref = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result;
if (vref_calculated) {
*vref_calculated = vref;
switch (channel) {
case SAFETY_ADC_MEAS_TEMP:
converted_val = (((float)channel / 4095.0f * 2500.0f - SAFETY_ADC_TEMP_NOM_MV) /
SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
break;
case SAFETY_ADC_MEAS_VREF:
converted_val = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)analog_value;
break;
default:
/* Generate NaN value as default return */
converted_val = 0.0f / 0.0f;
break;
}
temp = (((float)temp_result / 4095.0f * 2500.0f -
SAFETY_ADC_TEMP_NOM_MV) / SAFETY_ADC_TEMP_MV_SLOPE) + SAFETY_ADC_TEMP_NOM;
if (temp_calculated) {
*temp_calculated = temp;
}
if (ABS(vref - SAFETY_ADC_VREF_MVOLT) > SAFETY_ADC_VREF_TOL_MVOLT) {
if (vref > SAFETY_ADC_VREF_MVOLT)
res |= SAFETY_ADC_CHECK_VREF_HIGH;
else
res |= SAFETY_ADC_CHECK_VREF_LOW;
}
if (temp < SAFETY_ADC_TEMP_LOW_LIM)
res |= SAFETY_ADC_CHECK_TEMP_LOW;
else if (temp < SAFETY_ADC_CHECK_TEMP_HIGH)
res |= SAFETY_ADC_CHECK_TEMP_HIGH;
return res;
return converted_val;
}
int safety_adc_poll_result(uint16_t *adc_result)
@@ -136,60 +111,5 @@ void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement)
SAFETY_ADC_ADC_PERIPHERAL->CR2 |= ADC_CR2_SWSTART;
}
static uint16_t safety_vref_meas_raw;
static bool safety_vref_valid = false;
static uint16_t safety_temp_meas_raw;
static bool safety_temp_valid = false;
static float safety_vref;
static float safety_temp;
enum safety_adc_check_result handle_safety_adc()
{
static enum safety_adc_meas_channel safety_meas_channel = SAFETY_ADC_MEAS_VREF;
enum safety_adc_check_result check_result;
uint16_t result;
int poll_status;
poll_status = safety_adc_poll_result(&result);
if (poll_status < 0) {
safety_adc_trigger_meas(safety_meas_channel);
} else if (poll_status > 0) {
switch (safety_meas_channel) {
case SAFETY_ADC_MEAS_TEMP:
safety_temp_meas_raw = result;
safety_temp_valid = true;
safety_meas_channel = SAFETY_ADC_MEAS_VREF;
break;
case SAFETY_ADC_MEAS_VREF:
safety_vref_meas_raw = result;
safety_vref_valid = true;
safety_meas_channel = SAFETY_ADC_MEAS_TEMP;
break;
default:
safety_meas_channel = SAFETY_ADC_MEAS_VREF;
return SAFETY_ADC_INTERNAL_ERROR;
}
}
if (safety_temp_valid && safety_vref_valid) {
check_result = safety_adc_check_results(safety_vref_meas_raw, safety_temp_meas_raw, &safety_vref, &safety_temp);
global_safety_adc_status |= check_result;
} else {
check_result = SAFETY_ADC_CHECK_OK;
}
return check_result;
}
float safety_adc_get_temp()
{
return safety_temp;
}
float safety_adc_get_vref()
{
return safety_vref;
}
/** @} */

View File

@@ -26,6 +26,8 @@
#include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/safety/safety-config.h>
#include <reflow-controller/safety/watchdog.h>
#include <reflow-controller/safety/safety-adc.h>
#include <helper-macros/helper-macros.h>
#include <reflow-controller/systick.h>
#include <stdbool.h>
@@ -42,6 +44,7 @@ struct error_flag {
struct timing_mon {
const char *name;
enum timing_monitor monitor;
enum safety_flag associated_flag;
uint64_t min_delta;
uint64_t max_delta;
uint64_t last;
@@ -51,6 +54,7 @@ struct timing_mon {
struct analog_mon {
const char *name;
enum analog_value_monitor monitor;
enum safety_flag associated_flag;
float min;
float max;
float value;
@@ -64,8 +68,8 @@ struct analog_mon {
#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, .persistent = (persistency)}
#define TIM_MON_ENTRY(mon, min, max) {.name=#mon, .monitor = (mon), .min_delta = (min), .max_delta = (max), .last = 0ULL, .enabled= false}
#define ANA_MON_ENTRY(mon, min_value, max_value) {.name=#mon, .monitor = (mon), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = false}
#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}
static struct error_flag flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false),
@@ -80,16 +84,59 @@ static struct error_flag flags[] = {
};
static struct timing_mon timings[] = {
TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800),
TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50),
TIM_MON_ENTRY(ERR_TIMING_SAFETY_ADC, 220, 500),
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),
};
static struct analog_mon analog_mons[] = {
ANA_MON_ENTRY(ERR_AMON_VREF, 2480.0f, 2520.0f),
ANA_MON_ENTRY(ERR_AMON_UC_TEMP, 0.0f, 55.0f),
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),
};
static struct analog_mon *find_analog_mon(enum analog_value_monitor mon)
{
uint32_t i;
struct analog_mon *ret = NULL;
for (i = 0; i < COUNT_OF(analog_mons); i++) {
if (analog_mons[i].monitor == mon)
ret = &analog_mons[i];
}
return ret;
}
static struct timing_mon *find_timing_mon(enum timing_monitor mon)
{
uint32_t i;
struct timing_mon *ret = NULL;
for (i = 0; i < COUNT_OF(timings); i++) {
if (timings[i].monitor == mon)
ret = &timings[i];
}
return ret;
}
static struct error_flag *find_error_flag(enum safety_flag flag)
{
uint32_t i;
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_checks()
{
// TODO: Implement
}
int safety_controller_report_error(enum safety_flag flag)
{
uint32_t i;
@@ -102,11 +149,11 @@ int safety_controller_report_error(enum safety_flag flag)
}
}
safety_controller_process_checks();
return ret;
}
/** @} */
void safety_controller_report_timing(enum timing_monitor monitor)
{
uint32_t i;
@@ -115,22 +162,41 @@ void safety_controller_report_timing(enum timing_monitor monitor)
timestamp = systick_get_global_tick();
for (i = 0; i < COUNT_OF(timings); i++) {
tim = &timings[i];
if (tim->monitor & monitor) {
tim->enabled = true;
tim->last = timestamp;
}
tim = find_timing_mon(monitor);
if (tim) {
tim->last = timestamp;
tim->enabled = true;
}
safety_controller_process_checks();
}
void safety_controller_report_analog_value(enum analog_value_monitor monitor, float value)
{
struct analog_mon *ana;
/* Return if not a power of two */
if (!is_power_of_two(monitor))
return;
ana = find_analog_mon(monitor);
if (ana) {
ana->valid = true;
ana->value = value;
}
safety_controller_process_checks();
}
void safety_controller_init()
{
safety_adc_init();
watchdog_setup(WATCHDOG_PRESCALER);
}
int safety_controller_handle()
{
static
int ret = 0;
/* TODO: Handle safety ADC */
@@ -144,19 +210,49 @@ int safety_controller_handle()
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable)
{
uint32_t i;
struct timing_mon *tim;
if (enable) {
safety_controller_report_timing(monitor);
} else {
for (i = 0; i < COUNT_OF(timings); i++) {
tim = &timings[i];
if (tim->monitor & monitor) {
tim->enabled = false;
}
}
tim = find_timing_mon(monitor);
if (!tim)
return -1;
tim->enabled = false;
}
return 0;
}
enum analog_monitor_status safety_controller_get_analog_mon_value(enum analog_value_monitor monitor, float *value)
{
struct analog_mon *mon;
int ret = ANALOG_MONITOR_ERROR;
if (!is_power_of_two(monitor))
goto go_out;
if (!value)
goto go_out;
mon = find_analog_mon(monitor);
if (mon) {
if (!mon->valid) {
ret = ANALOG_MONITOR_INACTIVE;
goto go_out;
}
*value = mon->value;
if (mon->value < mon->min)
ret = ANALOG_MONITOR_UNDER;
else if (mon->value > mon->max)
ret = ANALOG_MONITOR_OVER;
else
ret = ANALOG_MONITOR_OK;
}
go_out:
return ret;
}
/** @} */