Reworked measurement ADC to use safety controller

This commit is contained in:
Mario Hüttel 2020-07-27 22:15:01 +02:00
parent a9e300bf5b
commit da96daa767
8 changed files with 94 additions and 84 deletions

View File

@ -24,14 +24,13 @@
#include <stm-periph/stm32-gpio-macros.h>
#include <stdlib.h>
#include <stm-periph/clock-enable-manager.h>
#include <reflow-controller/safety/safety-controller.h>
static float pt1000_offset;
static float pt1000_sens_dev;
static bool calibration_active;
static float filter_alpha;
static volatile float pt1000_res_raw_lf;
static volatile bool filter_ready;
static volatile enum adc_pt1000_error pt1000_error = ADC_PT1000_INACTIVE;
static volatile int * volatile streaming_flag_ptr = NULL;
static uint32_t filter_startup_cnt;
static volatile float adc_pt1000_raw_reading_hf;
@ -73,7 +72,7 @@ static inline void adc_pt1000_disable_adc()
ADC_PT1000_PERIPH->CR2 &= ~ADC_CR2_ADON;
DMA2_Stream0->CR = 0;
pt1000_error |= ADC_PT1000_INACTIVE;
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
rcc_manager_disable_clock(&RCC->APB2ENR, BITMASK_TO_BITNO(RCC_APB2ENR_ADC3EN));
rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(ADC_PT1000_PORT_RCC_MASK));
@ -166,13 +165,13 @@ void adc_pt1000_setup_meas()
adc_pt1000_setup_sample_frequency_timer();
pt1000_error &= ~ADC_PT1000_INACTIVE;
safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_OFF, MEAS_ADC_SAFETY_FLAG_KEY);
}
void adc_pt1000_set_moving_average_filter_param(float alpha)
{
filter_alpha = alpha;
filter_ready = false;
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY);
filter_startup_cnt = ADC_FILTER_STARTUP_CYCLES;
}
@ -181,6 +180,12 @@ void adc_pt1000_set_resistance_calibration(float offset, float sensitivity_devia
pt1000_offset = offset;
pt1000_sens_dev = sensitivity_deviation;
calibration_active = active;
if (calibration_active) {
safety_controller_report_error_with_key(ERR_FLAG_UNCAL, MEAS_ADC_SAFETY_FLAG_KEY);
} else {
safety_controller_ack_flag_with_key(ERR_FLAG_UNCAL, MEAS_ADC_SAFETY_FLAG_KEY);
}
}
void adc_pt1000_get_resistance_calibration(float *offset, float *sensitivity_deviation, bool *active)
@ -205,18 +210,23 @@ static inline float adc_pt1000_apply_calibration(float raw_resistance)
int adc_pt1000_get_current_resistance(float *resistance)
{
int ret_val = 0;
bool flag = true;
if (!resistance)
return -1001;
*resistance = adc_pt1000_apply_calibration(pt1000_res_raw_lf);
if (adc_pt1000_check_error()) {
if (safety_controller_get_flags_by_mask(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_OVERFLOW |
ERR_FLAG_MEAS_ADC_WATCHDOG)) {
ret_val = -100;
goto return_value;
}
if (!filter_ready) {
(void)safety_controller_get_flag(ERR_FLAG_MEAS_ADC_UNSTABLE, &flag, false);
if (flag) {
ret_val = 2;
goto return_value;
}
@ -260,25 +270,15 @@ void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, fl
resistance_dest[i] = ADC_TO_RES(raw_source[i]);
}
enum adc_pt1000_error adc_pt1000_check_error()
{
return pt1000_error;
}
void adc_pt1000_clear_error()
{
pt1000_error &= ~ADC_PT1000_OVERFLOW & ~ADC_PT1000_WATCHDOG_ERROR;
}
void adc_pt1000_disable()
{
adc_pt1000_disable_adc();
adc_pt1000_stop_sample_frequency_timer();
adc_pt1000_disable_dma_stream();
filter_ready = false;
pt1000_res_raw_lf = 0.0f;
pt1000_error |= ADC_PT1000_INACTIVE;
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_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY);
if (streaming_flag_ptr) {
*streaming_flag_ptr = -3;
@ -288,8 +288,12 @@ void adc_pt1000_disable()
static inline __attribute__((optimize("O3"))) void adc_pt1000_filter(float adc_prefiltered_value)
{
if (!filter_ready && --filter_startup_cnt <= 0)
filter_ready = true;
if (filter_startup_cnt > 0) {
filter_startup_cnt--;
if (filter_startup_cnt == 0) {
safety_controller_ack_flag_with_key(ERR_FLAG_MEAS_ADC_UNSTABLE, MEAS_ADC_SAFETY_FLAG_KEY);
}
}
pt1000_res_raw_lf = (1.0f-filter_alpha) * pt1000_res_raw_lf + filter_alpha * ADC_TO_RES(adc_prefiltered_value);
}
@ -328,7 +332,7 @@ void ADC_IRQHandler(void)
if (adc1_sr & ADC_SR_OVR) {
ADC_PT1000_PERIPH->SR &= ~ADC_SR_OVR;
pt1000_error |= ADC_PT1000_OVERFLOW;
safety_controller_report_error(ERR_FLAG_MEAS_ADC_OVERFLOW);
/* Disable ADC in case of overrrun*/
adc_pt1000_disable();
}
@ -337,7 +341,7 @@ void ADC_IRQHandler(void)
ADC_PT1000_PERIPH->SR &= ~ADC_SR_AWD;
adc_watchdog_counter++;
if (adc_watchdog_counter >= ADC_PT1000_WATCHDOG_SAMPLE_COUNT)
pt1000_error |= ADC_PT1000_WATCHDOG_ERROR;
safety_controller_report_error(ERR_FLAG_MEAS_ADC_WATCHDOG);
}
}

View File

@ -26,6 +26,7 @@
#include <arm_math.h>
#include <stdlib.h>
#include <float.h>
#include <reflow-controller/safety/safety-controller.h>
enum calibration_shell_state {CAL_START = 0, CAL_WAIT_RES1, CAL_MEAS_RES1, CAL_WAIT_RES2, CAL_MEAS_RES2};
@ -121,6 +122,8 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
{
(void)arg;
(void)len;
bool error_occured;
const enum safety_flag meas_adc_err_mask = ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_WATCHDOG;
/* This stores the current state of the calibration process */
static enum calibration_shell_state cal_state = CAL_START;
@ -139,7 +142,7 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
switch (cal_state) {
case CAL_START:
/* Clear errors of PT1000 reading */
adc_pt1000_clear_error();
safety_controller_ack_flag(ERR_FLAG_MEAS_ADC_WATCHDOG);
shellmatta_printf(shell, "Starting calibration: Insert 1000 Ohm calibration resistor and press ENTER\r\n");
cal_state = CAL_WAIT_RES1;
ret_val = SHELLMATTA_CONTINUE;
@ -154,7 +157,7 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
cal_state = CAL_MEAS_RES1;
ret_val = SHELLMATTA_BUSY;
shellmatta_printf(shell, "Measurement...\r\n");
adc_pt1000_clear_error();
safety_controller_ack_flag(ERR_FLAG_MEAS_ADC_WATCHDOG);
data_buffer = calibration_acquire_data_start(512UL, &flag);
break;
} else if (stdin_data[i] == '\x03') {
@ -179,8 +182,9 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
cal_state = CAL_MEAS_RES1;
} else if (res == 0) {
shellmatta_printf(shell, "R=%.2f, Noise peak-peak: %.2f\r\n", mu, dev);
if (adc_pt1000_check_error() != ADC_PT1000_NO_ERR) {
shellmatta_printf(shell, "Error in resistance measurement: %d", adc_pt1000_check_error());
error_occured = safety_controller_get_flags_by_mask(meas_adc_err_mask);
if (error_occured) {
shellmatta_printf(shell, "Error in resistance measurement");
ret_val = SHELLMATTA_OK;
cal_state = CAL_START;
} else {
@ -189,7 +193,7 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
cal_state = CAL_WAIT_RES2;
}
} else {
shellmatta_printf(shell, "Error in resistance measurement: %d", adc_pt1000_check_error());
shellmatta_printf(shell, "Error in resistance measurement");
ret_val = SHELLMATTA_OK;
cal_state = CAL_START;
}
@ -204,7 +208,7 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
cal_state = CAL_MEAS_RES2;
ret_val = SHELLMATTA_BUSY;
shellmatta_printf(shell, "Measurement...\r\n");
adc_pt1000_clear_error();
safety_controller_ack_flag(ERR_FLAG_MEAS_ADC_WATCHDOG);
data_buffer = calibration_acquire_data_start(512UL, &flag);
break;
} else if (stdin_data[i] == '\x03') {
@ -229,8 +233,9 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
cal_state = CAL_MEAS_RES2;
} else if (res == 0) {
shellmatta_printf(shell, "R=%.2f, Noise peak-peak: %.2f\r\n", mu2, dev2);
if (adc_pt1000_check_error() != ADC_PT1000_NO_ERR) {
shellmatta_printf(shell, "Error in resistance measurement: %d", adc_pt1000_check_error());
error_occured = safety_controller_get_flags_by_mask(meas_adc_err_mask);
if (error_occured) {
shellmatta_printf(shell, "Error in resistance measurement");
ret_val = SHELLMATTA_OK;
cal_state = CAL_START;
} else {
@ -250,7 +255,7 @@ shellmatta_retCode_t calibration_sequence_shell_cmd(shellmatta_handle_t shell, c
adc_pt1000_set_resistance_calibration(offset, sens_dev, true);
}
} else {
shellmatta_printf(shell, "Error in resistance measurement: %d", adc_pt1000_check_error());
shellmatta_printf(shell, "Error in resistance measurement");
ret_val = SHELLMATTA_OK;
cal_state = CAL_START;
}

View File

@ -90,8 +90,6 @@
*/
#define ADC_PT1000_WATCHDOG_SAMPLE_COUNT 25U
enum adc_pt1000_error {ADC_PT1000_NO_ERR= 0, ADC_PT1000_WATCHDOG_ERROR=(1UL<<0), ADC_PT1000_OVERFLOW=(1UL<<1), ADC_PT1000_INACTIVE = (1UL<<2)};
/**
* @brief This function sets up the ADC measurement fo the external PT1000 temperature sensor
*
@ -162,18 +160,6 @@ int adc_pt1000_stream_raw_value_to_memory(volatile float *adc_array, uint32_t le
void adc_pt1000_convert_raw_value_array_to_resistance(float *resistance_dest, float *raw_source, uint32_t count);
/**
* @brief Check if the ADC measurement experienced any kind of error (DMA, Analog Watchdog, etc...)
*
* In case of an error, it may be necessary to call adc_pt1000_setup_meas() again in order to recover from the error
*/
enum adc_pt1000_error adc_pt1000_check_error();
/**
* @brief Clear the error status of the PT1000 measurement
*/
void adc_pt1000_clear_error();
/**
* @brief Disable the PT1000 measurement
*/

View File

@ -35,6 +35,7 @@ enum safety_flag {
ERR_FLAG_SAFETY_ADC = (1<<9),
ERR_FLAG_SYSTICK = (1<<10),
ERR_FLAG_WTCHDG_FIRED = (1<<11),
ERR_FLAG_UNCAL = (1<<12),
};
enum timing_monitor {
@ -80,4 +81,10 @@ enum analog_value_monitor {
#define SAFETY_ADC_TEMP_LOW_LIM (0.0f)
#define SAFETY_ADC_TEMP_HIGH_LIM (65.0f)
/**
* @brief Key used to lock the safefety flags from external ack'ing
*/
#define MEAS_ADC_SAFETY_FLAG_KEY 0xe554dac3UL
#endif /* __SAFETY_CONFIG_H__ */

View File

@ -55,6 +55,8 @@ int safety_controller_handle();
int safety_controller_report_error(enum safety_flag flag);
int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key);
void safety_controller_report_timing(enum timing_monitor monitor);
void safety_controller_report_analog_value(enum analog_value_monitor monitor, float value);
@ -69,6 +71,8 @@ int safety_controller_ack_flag(enum safety_flag flag);
int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key);
bool safety_controller_get_flags_by_mask(enum safety_flag mask);
#endif /* __SAFETY_CONTROLLER_H__ */
/** @} */

View File

@ -161,7 +161,7 @@ static inline void setup_system(void)
setup_unused_pins();
safety_controller_init();
}
static void handle_shell_uart_input(shellmatta_handle_t shell_handle)
@ -219,6 +219,8 @@ int main(void)
menu_wait_request = reflow_menu_handle();
handle_shell_uart_input(shell_handle);
safety_controller_handle();
oven_driver_apply_power_level();
if (menu_wait_request)

View File

@ -83,6 +83,7 @@ static volatile struct error_flag flags[] = {
ERR_FLAG_ENTRY(ERR_FLAG_SAFETY_ADC, true),
ERR_FLAG_ENTRY(ERR_FLAG_SYSTICK, true),
ERR_FLAG_ENTRY(ERR_FLAG_WTCHDG_FIRED, true),
ERR_FLAG_ENTRY(ERR_FLAG_UNCAL, false),
};
static volatile struct timing_mon timings[] = {
@ -183,6 +184,11 @@ static void safety_controller_process_checks()
}
int safety_controller_report_error(enum safety_flag flag)
{
return safety_controller_report_error_with_key(flag, 0x0UL);
}
int safety_controller_report_error_with_key(enum safety_flag flag, uint32_t key)
{
uint32_t i;
int ret = -1;
@ -190,6 +196,7 @@ int safety_controller_report_error(enum safety_flag flag)
for (i = 0; i < COUNT_OF(flags); i++) {
if (flags[i].flag & flag) {
flags[i].error_state = true;
flags[i].key = key;
ret = 0;
}
}
@ -239,8 +246,14 @@ void safety_controller_report_analog_value(enum analog_value_monitor monitor, fl
void safety_controller_init()
{
/* Init default flag states */
safety_controller_report_error_with_key(ERR_FLAG_MEAS_ADC_OFF | ERR_FLAG_MEAS_ADC_UNSTABLE,
MEAS_ADC_SAFETY_FLAG_KEY);
safety_adc_init();
watchdog_setup(WATCHDOG_PRESCALER);
}
static void safety_controller_check_stack()
@ -400,7 +413,7 @@ int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key)
found_flag = find_error_flag(flag);
if (found_flag) {
if (!found_flag->persistent && found_flag->key == key) {
if (!found_flag->persistent && (found_flag->key == key || !key)) {
found_flag->error_state = false;
ret = 0;
} else {
@ -411,4 +424,19 @@ int safety_controller_ack_flag_with_key(enum safety_flag flag, uint32_t key)
return ret;
}
bool safety_controller_get_flags_by_mask(enum safety_flag mask)
{
uint32_t i;
bool ret = false;
for (i = 0; i < COUNT_OF(flags); i++) {
if (flags[i].flag & mask) {
ret = true;
break;
}
}
return ret;
}
/** @} */

View File

@ -128,7 +128,6 @@ static shellmatta_retCode_t shell_cmd_pt1000_res(const shellmatta_handle_t han
(void)length;
float resistance;
int pt1000_status;
enum adc_pt1000_error pt1000_flags;
char display_status[100];
float temp;
int temp_conv_status;
@ -141,13 +140,7 @@ static shellmatta_retCode_t shell_cmd_pt1000_res(const shellmatta_handle_t han
if (pt1000_status == 2) {
strcat(display_status, " UNSTABLE ");
} else if (pt1000_status) {
pt1000_flags = adc_pt1000_check_error();
if (pt1000_flags & ADC_PT1000_INACTIVE)
strcat(display_status, " DEACTIVATED ");
else if (pt1000_flags & ADC_PT1000_WATCHDOG_ERROR)
strcat(display_status, " WATCHDOG ");
else if (pt1000_flags & ADC_PT1000_OVERFLOW)
strcat(display_status, " OVERFLOW ");
strcpy(display_status, "ERROR");
} else {
strcpy(display_status, "VALID");
}
@ -171,17 +164,6 @@ static shellmatta_retCode_t shell_cmd_pt1000_res(const shellmatta_handle_t han
return SHELLMATTA_OK;
}
static shellmatta_retCode_t shell_cmd_clear_error_status(const shellmatta_handle_t handle, const char *arguments,
uint32_t length)
{
(void)arguments;
(void)length;
(void)handle;
adc_pt1000_clear_error();
return SHELLMATTA_OK;
}
static shellmatta_retCode_t shell_cmd_uptime(const shellmatta_handle_t handle,
const char *arguments,
@ -401,21 +383,13 @@ static shellmatta_cmd_t cmd[14] = {
.cmdFct = shell_cmd_pt1000_res_loop,
.next = &cmd[3],
},
{
.cmd = "pt1000-clear-error",
.cmdAlias = "pt-clear",
.helpText = "Clear error status of PT1000 reading",
.usageText = NULL,
.cmdFct = shell_cmd_clear_error_status,
.next = &cmd[4],
},
{
.cmd = "digio-get",
.cmdAlias = "dg",
.helpText = "Read all digital input/output ports",
.usageText = NULL,
.cmdFct = shell_cmd_digio_get,
.next = &cmd[5],
.next = &cmd[4],
},
{
.cmd = "digio-set",
@ -423,7 +397,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Set DIGIO Port",
.usageText = "digio-set <num> <state>",
.cmdFct = shell_cmd_digio_set,
.next = &cmd[6],
.next = &cmd[5],
},
{
.cmd = "uptime",
@ -431,7 +405,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Get uptime in seconds",
.usageText = "",
.cmdFct = shell_cmd_uptime,
.next = &cmd[7],
.next = &cmd[6],
},
{
.cmd = "calibrate",
@ -439,7 +413,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Calibrate resistance measurement",
.usageText = "",
.cmdFct = shell_cmd_cal,
.next = &cmd[8],
.next = &cmd[7],
},
{
.cmd = "meminfo",
@ -447,7 +421,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Get information about memory usage",
.usageText = "",
.cmdFct = shell_meminfo,
.next = &cmd[9],
.next = &cmd[8],
},
{
.cmd = "rotary-encoder",
@ -455,7 +429,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Get current rotary encoder value",
.usageText = "",
.cmdFct = shell_cmd_rot,
.next = &cmd[10],
.next = &cmd[9],
},
{
.cmd = "ls",
@ -463,7 +437,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "List filesystem contents",
.usageText = "",
.cmdFct = shell_cmd_ls,
.next = &cmd[11],
.next = &cmd[10],
},
{
.cmd = "reset",
@ -471,7 +445,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Reset controller",
.usageText = "reset",
.cmdFct = shell_cmd_reset,
.next = &cmd[12],
.next = &cmd[11],
},
{
.cmd = "cat",
@ -479,7 +453,7 @@ static shellmatta_cmd_t cmd[14] = {
.helpText = "Print file contents",
.usageText = "cat <path>",
.cmdFct = shell_cmd_cat,
.next = &cmd[13],
.next = &cmd[12],
},
{
.cmd = "safety-adc",