Further rewrite safety handling

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

View File

@ -36,4 +36,6 @@
#define ABS(a) ((a) < 0 ? (-1*(a)) : (a)) #define ABS(a) ((a) < 0 ? (-1*(a)) : (a))
#define is_power_of_two(num) ((num) && !((num) & ((num) - 1)))
#endif /* __HELPER_MACROS_H__ */ #endif /* __HELPER_MACROS_H__ */

View File

@ -25,32 +25,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <reflow-controller/pid-controller.h> #include <reflow-controller/pid-controller.h>
enum oven_pid_error_report { enum oven_pid_status {OVEN_PID_DEACTIVATED,
OVEN_PID_NO_ERROR = 0, OVEN_PID_RUNNING,
OVEN_PID_ERR_PT1000_ADC_WATCHDOG = (1<<0), OVEN_PID_ABORTED};
OVEN_PID_ERR_PT1000_ADC_OFF = (1<<1),
OVEN_PID_ERR_PT1000_OTHER = (1<<2),
OVEN_PID_ERR_VREF_TOL = (1<<3),
OVEN_PID_ERR_OVERTEMP = (1<<4),
};
struct oven_pid_errors {
bool generic_error;
bool pt1000_adc_watchdog;
bool pt1000_adc_off;
bool pt1000_other;
bool vref_tol;
bool controller_overtemp;
};
struct oven_pid_status {
bool active;
bool error_set;
struct oven_pid_errors error_flags;
float target_temp;
float current_temp;
uint64_t timestamp_last_run;
};
void oven_driver_init(void); void oven_driver_init(void);
@ -66,8 +43,8 @@ void oven_pid_handle(float target_temp);
void oven_pid_stop(); void oven_pid_stop();
void oven_pid_report_error(enum oven_pid_error_report report); void oven_driver_apply_power_level(void);
const struct oven_pid_status *oven_pid_get_status(void); enum oven_pid_status oven_pid_get_status(void);
#endif /* __OVEN_DRIVER_H__ */ #endif /* __OVEN_DRIVER_H__ */

View File

@ -29,26 +29,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#define SAFETY_ADC_VREF_MVOLT (2500.0f)
#define SAFETY_ADC_VREF_TOL_MVOLT (100.0f)
#define SAFETY_ADC_TEMP_LOW_LIM (0.0f)
#define SAFETY_ADC_TEMP_HIGH_LIM (65.0f)
enum safety_adc_meas_channel {SAFETY_ADC_MEAS_VREF, SAFETY_ADC_MEAS_TEMP}; enum safety_adc_meas_channel {SAFETY_ADC_MEAS_VREF, SAFETY_ADC_MEAS_TEMP};
enum safety_adc_check_result {
SAFETY_ADC_CHECK_OK = 0UL,
SAFETY_ADC_CHECK_VREF_LOW = (1U<<0),
SAFETY_ADC_CHECK_VREF_HIGH = (1U<<1),
SAFETY_ADC_CHECK_TEMP_LOW = (1U<<2),
SAFETY_ADC_CHECK_TEMP_HIGH = (1U<<3),
SAFETY_ADC_INTERNAL_ERROR = (1U<<4),
};
extern enum safety_adc_check_result global_safety_adc_status;
enum safety_adc_check_result safety_adc_get_errors();
void safety_adc_clear_errors(void);
void safety_adc_init(); void safety_adc_init();
@ -63,14 +44,9 @@ void safety_adc_trigger_meas(enum safety_adc_meas_channel measurement);
*/ */
int safety_adc_poll_result(uint16_t *adc_result); int safety_adc_poll_result(uint16_t *adc_result);
enum safety_adc_check_result safety_adc_check_results(uint16_t vref_result, uint16_t temp_result,
float *vref_calculated, float *temp_calculated);
enum safety_adc_check_result handle_safety_adc(); enum safety_adc_check_result handle_safety_adc();
float safety_adc_get_temp(); float safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value);
float safety_adc_get_vref();
#endif /* __SAFETY_ADC_H__ */ #endif /* __SAFETY_ADC_H__ */

View File

@ -68,4 +68,9 @@ enum analog_value_monitor {
#define HALTING_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP) #define HALTING_CAREMASK (ERR_FLAG_STACK | ERR_FLAG_AMON_UC_TEMP)
#define SAFETY_ADC_VREF_MVOLT (2500.0f)
#define SAFETY_ADC_VREF_TOL_MVOLT (100.0f)
#define SAFETY_ADC_TEMP_LOW_LIM (0.0f)
#define SAFETY_ADC_TEMP_HIGH_LIM (65.0f)
#endif /* __SAFETY_CONFIG_H__ */ #endif /* __SAFETY_CONFIG_H__ */

View File

@ -30,6 +30,12 @@
#include <reflow-controller/safety/safety-config.h> #include <reflow-controller/safety/safety-config.h>
#include <stdbool.h> #include <stdbool.h>
enum analog_monitor_status {ANALOG_MONITOR_OK = 0,
ANALOG_MONITOR_ERROR,
ANALOG_MONITOR_INACTIVE,
ANALOG_MONITOR_OVER,
ANALOG_MONITOR_UNDER};
/** /**
* @brief Initialize the safety controller * @brief Initialize the safety controller
* *
@ -50,8 +56,14 @@ int safety_controller_report_error(enum safety_flag flag);
void safety_controller_report_timing(enum timing_monitor monitor); void safety_controller_report_timing(enum timing_monitor monitor);
void safety_controller_report_analog_value(enum analog_value_monitor monitor, float value);
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable); int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable);
enum analog_monitor_status safety_controller_get_analog_mon_value(enum analog_value_monitor monitor, float *value);
bool safety_controller_get_flag(enum safety_flag);
#endif /* __SAFETY_CONTROLLER_H__ */ #endif /* __SAFETY_CONTROLLER_H__ */
/** @} */ /** @} */

View File

@ -41,9 +41,9 @@
#include <stm-periph/uart.h> #include <stm-periph/uart.h>
#include <reflow-controller/shell-uart-config.h> #include <reflow-controller/shell-uart-config.h>
#include <reflow-controller/oven-driver.h> #include <reflow-controller/oven-driver.h>
#include <reflow-controller/safety/safety-adc.h>
#include <fatfs/ff.h> #include <fatfs/ff.h>
#include <reflow-controller/reflow-menu.h> #include <reflow-controller/reflow-menu.h>
#include <reflow-controller/safety/safety-controller.h>
bool global_error_state; bool global_error_state;
@ -154,12 +154,14 @@ static inline void setup_system(void)
led_setup(); led_setup();
loudspeaker_setup(); loudspeaker_setup();
reflow_menu_init(); reflow_menu_init();
safety_adc_init();
uart_gpio_config(); uart_gpio_config();
setup_shell_uart(&shell_uart); setup_shell_uart(&shell_uart);
setup_unused_pins(); setup_unused_pins();
} }
static void handle_shell_uart_input(shellmatta_handle_t shell_handle) static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
@ -188,39 +190,12 @@ static void zero_ccm_ram(void)
ptr[i] = 0UL; ptr[i] = 0UL;
} }
/**
* @brief This function sets the appropriate error flags in the oven PID controller
* depending on the Safety ADC measurements.
* The PID controller's error flags have to be cleared via the GUI by either starting a new RUN or explicitly
* ack'ing these errors.
*/
static void propagate_safety_adc_error_to_oven_pid(void)
{
enum safety_adc_check_result safety_adc_result;
safety_adc_result = safety_adc_get_errors();
if (safety_adc_result & SAFETY_ADC_CHECK_TEMP_LOW ||
safety_adc_result & SAFETY_ADC_CHECK_TEMP_HIGH)
oven_pid_report_error(OVEN_PID_ERR_OVERTEMP);
if (safety_adc_result & SAFETY_ADC_CHECK_VREF_LOW ||
safety_adc_result & SAFETY_ADC_CHECK_VREF_HIGH)
oven_pid_report_error(OVEN_PID_ERR_VREF_TOL);
if (safety_adc_result & SAFETY_ADC_INTERNAL_ERROR)
oven_pid_report_error(0);
}
int main(void) int main(void)
{ {
bool sd_card_mounted = false; bool sd_card_mounted = false;
shellmatta_handle_t shell_handle; shellmatta_handle_t shell_handle;
int menu_wait_request; int menu_wait_request;
uint64_t quarter_sec_timestamp = 0ULL; uint64_t quarter_sec_timestamp = 0ULL;
const struct oven_pid_status *pid_status;
enum adc_pt1000_error pt1000_status;
zero_ccm_ram(); zero_ccm_ram();
setup_system(); setup_system();
@ -232,31 +207,20 @@ int main(void)
while (1) { while (1) {
sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted); sd_card_mounted = mount_sd_card_if_avail(sd_card_mounted);
pid_status = oven_pid_get_status();
if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) { if (systick_ticks_have_passed(quarter_sec_timestamp, 250)) {
quarter_sec_timestamp = systick_get_global_tick(); quarter_sec_timestamp = systick_get_global_tick();
(void)handle_safety_adc(); if (0)
propagate_safety_adc_error_to_oven_pid();
if (global_error_state)
led_set(0, !led_get(0)); led_set(0, !led_get(0));
else else
led_set(0, 0); led_set(0, 0);
} }
pt1000_status = adc_pt1000_check_error();
global_error_state = pid_status->error_set || !!safety_adc_get_errors() || !!pt1000_status;
menu_wait_request = reflow_menu_handle(); menu_wait_request = reflow_menu_handle();
/* Deactivate oven output in case of error! */
if (!pid_status->active || global_error_state)
oven_driver_set_power(0U);
handle_shell_uart_input(shell_handle); handle_shell_uart_input(shell_handle);
oven_driver_apply_power_level();
if (menu_wait_request) if (menu_wait_request)
__WFI(); __WFI();
else else

View File

@ -24,16 +24,12 @@
#include <reflow-controller/systick.h> #include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/temp-converter.h> #include <reflow-controller/temp-converter.h>
#include <reflow-controller/safety/safety-controller.h>
static struct pid_controller oven_pid; static struct pid_controller oven_pid;
static bool oven_pid_running = false;
static struct oven_pid_status oven_pid_current_status = { static bool oven_pid_aborted = false;
.active = false, static uint8_t oven_driver_power_level = 0U;
.error_set = false,
.target_temp = 0.0f,
.current_temp = 0.0f,
.timestamp_last_run = 0ULL
};
void oven_driver_init() void oven_driver_init()
{ {
@ -60,7 +56,12 @@ void oven_driver_set_power(uint8_t power)
if (power > 100U) if (power > 100U)
power = 100U; power = 100U;
OVEN_CONTROLLER_PWM_TIMER->CCR3 = power * 10; oven_driver_power_level = power;
}
void oven_driver_apply_power_level(void)
{
OVEN_CONTROLLER_PWM_TIMER->CCR3 = oven_driver_power_level * 10;
} }
void oven_driver_disable() void oven_driver_disable()
@ -71,93 +72,52 @@ void oven_driver_disable()
rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_TIM_RCC_MASK)); rcc_manager_disable_clock(&RCC->APB1ENR, BITMASK_TO_BITNO(OVEN_CONTROLLER_TIM_RCC_MASK));
} }
void oven_pid_ack_errors(void)
{
oven_pid_current_status.error_set = false;
oven_pid_current_status.error_flags.vref_tol = false;
oven_pid_current_status.error_flags.pt1000_other = false;
oven_pid_current_status.error_flags.generic_error = false;
oven_pid_current_status.error_flags.pt1000_adc_off = false;
oven_pid_current_status.error_flags.controller_overtemp = false;
oven_pid_current_status.error_flags.pt1000_adc_watchdog = false;
}
void oven_pid_init(struct pid_controller *controller_to_copy) void oven_pid_init(struct pid_controller *controller_to_copy)
{ {
pid_copy(&oven_pid, controller_to_copy); pid_copy(&oven_pid, controller_to_copy);
oven_pid.output_sat_min = 0.0f; oven_pid.output_sat_min = 0.0f;
oven_pid.output_sat_max = 100.0f; oven_pid.output_sat_max = 100.0f;
oven_pid_current_status.timestamp_last_run = 0ULL;
oven_pid_current_status.active = true; oven_pid_running = true;
oven_pid_ack_errors(); oven_pid_aborted = false;
safety_controller_report_timing(ERR_TIMING_PID);
} }
void oven_pid_handle(float target_temp) void oven_pid_handle(float target_temp)
{ {
float pid_out; float pid_out;
float current_temp; float current_temp;
int resistance_status; static uint64_t timestamp_last_run;
enum adc_pt1000_error pt1000_error;
if (oven_pid_current_status.active && !oven_pid_current_status.error_set) {
if (systick_ticks_have_passed(oven_pid_current_status.timestamp_last_run,
(uint64_t)(oven_pid.sample_period * 1000))) {
resistance_status = adc_pt1000_get_current_resistance(&current_temp);
if (resistance_status < 0) {
oven_driver_set_power(0);
pt1000_error = adc_pt1000_check_error();
if (pt1000_error & ADC_PT1000_WATCHDOG_ERROR)
oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_WATCHDOG);
if (pt1000_error & ADC_PT1000_INACTIVE)
oven_pid_report_error(OVEN_PID_ERR_PT1000_ADC_OFF);
if (pt1000_error & ADC_PT1000_OVERFLOW)
oven_pid_report_error(OVEN_PID_ERR_PT1000_OTHER);
return;
}
if (oven_pid_running && !oven_pid_aborted) {
if (systick_ticks_have_passed(timestamp_last_run, (uint64_t)(oven_pid.sample_period * 1000))) {
/* No need to check. Safety controller will monitor this */
(void)adc_pt1000_get_current_resistance(&current_temp);
(void)temp_converter_convert_resistance_to_temp(current_temp, &current_temp); (void)temp_converter_convert_resistance_to_temp(current_temp, &current_temp);
pid_out = pid_sample(&oven_pid, target_temp - current_temp); pid_out = pid_sample(&oven_pid, target_temp - current_temp);
oven_driver_set_power((uint8_t)pid_out); oven_driver_set_power((uint8_t)pid_out);
oven_pid_current_status.timestamp_last_run = systick_get_global_tick(); timestamp_last_run = systick_get_global_tick();
oven_pid_current_status.target_temp = target_temp;
oven_pid_current_status.current_temp = current_temp; safety_controller_report_timing(ERR_TIMING_PID);
} }
} }
} }
void oven_pid_report_error(enum oven_pid_error_report report)
{
struct oven_pid_errors *e = &oven_pid_current_status.error_flags;
oven_pid_current_status.active = false;
oven_pid_current_status.error_set = true;
if (report == 0) {
e->generic_error = true;
}
if (report & OVEN_PID_ERR_OVERTEMP)
e->controller_overtemp = true;
if (report & OVEN_PID_ERR_VREF_TOL)
e->controller_overtemp = true;
if (report & OVEN_PID_ERR_PT1000_OTHER)
e->pt1000_other = true;
if (report & OVEN_PID_ERR_PT1000_ADC_OFF)
e->pt1000_adc_off = true;
if (report & OVEN_PID_ERR_PT1000_ADC_WATCHDOG)
e->pt1000_adc_watchdog = true;
}
const struct oven_pid_status *oven_pid_get_status()
{
return &oven_pid_current_status;
}
void oven_pid_stop() void oven_pid_stop()
{ {
oven_pid_current_status.active = false; oven_pid_running = false;
oven_pid_current_status.target_temp = 0.0f; safety_controller_enable_timing_mon(ERR_TIMING_PID, false);
oven_pid_current_status.current_temp = 0.0f; }
enum oven_pid_status oven_pid_get_status(void)
{
enum oven_pid_status ret = OVEN_PID_ABORTED;
if (oven_pid_running && !oven_pid_aborted)
ret = OVEN_PID_RUNNING;
else if (!oven_pid_running && !oven_pid_aborted)
ret = OVEN_PID_DEACTIVATED;
return ret;
} }

View File

@ -24,7 +24,7 @@
#include <reflow-controller/rotary-encoder.h> #include <reflow-controller/rotary-encoder.h>
#include <reflow-controller/systick.h> #include <reflow-controller/systick.h>
#include <reflow-controller/adc-meas.h> #include <reflow-controller/adc-meas.h>
#include <reflow-controller/safety/safety-adc.h> #include <reflow-controller/safety/safety-controller.h>
#include <reflow-controller/temp-converter.h> #include <reflow-controller/temp-converter.h>
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/unique-id.h> #include <stm-periph/unique-id.h>
@ -90,11 +90,11 @@ static void reflow_menu_monitor(struct lcd_menu *menu, enum menu_entry_func_entr
snprintf(line, sizeof(line), "Temp: %s%.1f " LCD_DEGREE_SYMBOL_STRING "C", prefix, tmp); snprintf(line, sizeof(line), "Temp: %s%.1f " LCD_DEGREE_SYMBOL_STRING "C", prefix, tmp);
menu->update_display(1, line); menu->update_display(1, line);
tmp = safety_adc_get_temp(); (void)safety_controller_get_analog_mon_value(ERR_AMON_UC_TEMP, &tmp);
snprintf(line, sizeof(line), "Tj: %.1f " LCD_DEGREE_SYMBOL_STRING "C", tmp); snprintf(line, sizeof(line), "Tj: %.1f " LCD_DEGREE_SYMBOL_STRING "C", tmp);
menu->update_display(2, line); menu->update_display(2, line);
tmp = safety_adc_get_vref(); (void)safety_controller_get_analog_mon_value(ERR_AMON_VREF, &tmp);
snprintf(line, sizeof(line), "Vref: %.1f mV", tmp); snprintf(line, sizeof(line), "Vref: %.1f mV", tmp);
menu->update_display(3, line); menu->update_display(3, line);
} }

View File

@ -28,24 +28,10 @@
#include <helper-macros/helper-macros.h> #include <helper-macros/helper-macros.h>
#include <stm-periph/clock-enable-manager.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() void safety_adc_init()
{ {
rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK)); rcc_manager_enable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(SAFETY_ADC_ADC_RCC_MASK));
safety_adc_clear_errors();
/* Enable temperature and VREFINT measurement */ /* Enable temperature and VREFINT measurement */
ADC->CCR |= ADC_CCR_TSVREFE; 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)); 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 safety_adc_convert_channel(enum safety_adc_meas_channel channel, uint16_t analog_value)
float *vref_calculated, float *temp_calculated)
{ {
enum safety_adc_check_result res = SAFETY_ADC_CHECK_OK; float converted_val;
float vref;
float temp;
vref = (SAFETY_ADC_INT_REF_MV * 4095.0f) / (float)vref_result;
if (vref_calculated) { switch (channel) {
*vref_calculated = vref; 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 - return converted_val;
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;
} }
int safety_adc_poll_result(uint16_t *adc_result) 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; 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-controller.h>
#include <reflow-controller/safety/safety-config.h> #include <reflow-controller/safety/safety-config.h>
#include <reflow-controller/safety/watchdog.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 <reflow-controller/systick.h>
#include <stdbool.h> #include <stdbool.h>
@ -42,6 +44,7 @@ struct error_flag {
struct timing_mon { struct timing_mon {
const char *name; const char *name;
enum timing_monitor monitor; enum timing_monitor monitor;
enum safety_flag associated_flag;
uint64_t min_delta; uint64_t min_delta;
uint64_t max_delta; uint64_t max_delta;
uint64_t last; uint64_t last;
@ -51,6 +54,7 @@ struct timing_mon {
struct analog_mon { struct analog_mon {
const char *name; const char *name;
enum analog_value_monitor monitor; enum analog_value_monitor monitor;
enum safety_flag associated_flag;
float min; float min;
float max; float max;
float value; 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 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 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 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) {.name=#mon, .monitor = (mon), .min = (min_value), .max = (max_value), .value = 0.0f, .valid = 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[] = { static struct error_flag flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false), ERR_FLAG_ENTRY(ERR_FLAG_MEAS_ADC_OFF, false),
@ -80,16 +84,59 @@ static struct error_flag flags[] = {
}; };
static struct timing_mon timings[] = { static struct timing_mon timings[] = {
TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800), TIM_MON_ENTRY(ERR_TIMING_PID, 1, 800, ERR_FLAG_TIMING_PID),
TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 1, 50, ERR_FLAG_TIMING_MEAS_ADC),
TIM_MON_ENTRY(ERR_TIMING_SAFETY_ADC, 220, 500),
}; };
static struct analog_mon analog_mons[] = { static struct analog_mon analog_mons[] = {
ANA_MON_ENTRY(ERR_AMON_VREF, 2480.0f, 2520.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), 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) int safety_controller_report_error(enum safety_flag flag)
{ {
uint32_t i; uint32_t i;
@ -102,11 +149,11 @@ int safety_controller_report_error(enum safety_flag flag)
} }
} }
safety_controller_process_checks();
return ret; return ret;
} }
/** @} */
void safety_controller_report_timing(enum timing_monitor monitor) void safety_controller_report_timing(enum timing_monitor monitor)
{ {
uint32_t i; uint32_t i;
@ -115,22 +162,41 @@ void safety_controller_report_timing(enum timing_monitor monitor)
timestamp = systick_get_global_tick(); timestamp = systick_get_global_tick();
for (i = 0; i < COUNT_OF(timings); i++) { tim = find_timing_mon(monitor);
tim = &timings[i]; if (tim) {
if (tim->monitor & monitor) { tim->last = timestamp;
tim->enabled = true; tim->enabled = true;
tim->last = timestamp;
}
} }
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() void safety_controller_init()
{ {
safety_adc_init();
watchdog_setup(WATCHDOG_PRESCALER); watchdog_setup(WATCHDOG_PRESCALER);
} }
int safety_controller_handle() int safety_controller_handle()
{ {
static
int ret = 0; int ret = 0;
/* TODO: Handle safety ADC */ /* TODO: Handle safety ADC */
@ -144,19 +210,49 @@ int safety_controller_handle()
int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable) int safety_controller_enable_timing_mon(enum timing_monitor monitor, bool enable)
{ {
uint32_t i;
struct timing_mon *tim; struct timing_mon *tim;
if (enable) { if (enable) {
safety_controller_report_timing(monitor); safety_controller_report_timing(monitor);
} else { } else {
for (i = 0; i < COUNT_OF(timings); i++) { tim = find_timing_mon(monitor);
tim = &timings[i]; if (!tim)
if (tim->monitor & monitor) { return -1;
tim->enabled = false; tim->enabled = false;
}
}
} }
return 0; 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;
}
/** @} */

View File

@ -358,22 +358,10 @@ static shellmatta_retCode_t shell_cmd_safety_adc(const shellmatta_handle_t handl
(void)length; (void)length;
(void)arguments; (void)arguments;
shellmatta_printf(handle, "VREF:\t%8.2f\tmV\r\n", safety_adc_get_vref()); shellmatta_printf(handle, "VREF:\t%8.2f\tmV\r\n", 2500.0f);
shellmatta_printf(handle, "TEMP:\t%8.2f\tdeg. Celsius\r\n", safety_adc_get_temp()); shellmatta_printf(handle, "TEMP:\t%8.2f\tdeg. Celsius\r\n", 25.0f);
shellmatta_printf(handle, "Errors:\t%X", safety_adc_get_errors()); shellmatta_printf(handle, "Errors:\t%X", 0);
return SHELLMATTA_OK;
}
static shellmatta_retCode_t shell_cmd_safety_adc_clear_error(const shellmatta_handle_t handle, const char *arguments,
uint32_t length)
{
(void)length;
(void)arguments;
(void)handle;
safety_adc_clear_errors();
return SHELLMATTA_OK; return SHELLMATTA_OK;
} }
@ -388,7 +376,7 @@ static shellmatta_retCode_t shell_cmd_safety_adc_clear_error(const shellmatta_ha
// struct shellmatta_cmd *next; /**< pointer to next command or NULL */ // struct shellmatta_cmd *next; /**< pointer to next command or NULL */
//} shellmatta_cmd_t; //} shellmatta_cmd_t;
static shellmatta_cmd_t cmd[15] = { static shellmatta_cmd_t cmd[14] = {
{ {
.cmd = "version", .cmd = "version",
.cmdAlias = "ver", .cmdAlias = "ver",
@ -499,17 +487,8 @@ static shellmatta_cmd_t cmd[15] = {
.helpText = "", .helpText = "",
.usageText = "", .usageText = "",
.cmdFct = shell_cmd_safety_adc, .cmdFct = shell_cmd_safety_adc,
.next = &cmd[14],
},
{
.cmd = "safety-adc-clear-error",
.cmdAlias = NULL,
.helpText = "",
.usageText = "",
.cmdFct = shell_cmd_safety_adc_clear_error,
.next = NULL, .next = NULL,
}, },
}; };
shellmatta_handle_t shell_init(shellmatta_write_t write_func) shellmatta_handle_t shell_init(shellmatta_write_t write_func)