From ef8e6231ffc795c378ddba6404d2edff73915a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Mon, 30 Nov 2020 21:43:38 +0100 Subject: [PATCH] Issue #4: Implement Constant temperature function in GUI. This is useful to verify the oven parameters --- .../include/reflow-controller/oven-driver.h | 4 +- .../periph-config/safety-adc-hwcfg.h | 5 +- .../reflow-controller/pid-controller.h | 1 + stm-firmware/main.c | 7 +- stm-firmware/oven-driver.c | 12 ++- stm-firmware/safety/safety-controller.c | 17 +++- stm-firmware/ui/gui.c | 98 ++++++++++++++++++- stm-firmware/ui/menu.c | 2 + 8 files changed, 134 insertions(+), 12 deletions(-) diff --git a/stm-firmware/include/reflow-controller/oven-driver.h b/stm-firmware/include/reflow-controller/oven-driver.h index a77e489..5d56021 100644 --- a/stm-firmware/include/reflow-controller/oven-driver.h +++ b/stm-firmware/include/reflow-controller/oven-driver.h @@ -39,12 +39,14 @@ void oven_pid_ack_errors(void); void oven_pid_init(struct pid_controller *controller_to_copy); -void oven_pid_handle(float target_temp); +void oven_pid_handle(void); void oven_pid_stop(void); void oven_pid_abort(void); +void oven_pid_set_target_temperature(float temp); + void oven_driver_apply_power_level(void); enum oven_pid_status oven_pid_get_status(void); diff --git a/stm-firmware/include/reflow-controller/periph-config/safety-adc-hwcfg.h b/stm-firmware/include/reflow-controller/periph-config/safety-adc-hwcfg.h index 4b362d6..a1523dc 100644 --- a/stm-firmware/include/reflow-controller/periph-config/safety-adc-hwcfg.h +++ b/stm-firmware/include/reflow-controller/periph-config/safety-adc-hwcfg.h @@ -34,8 +34,9 @@ #define SAFETY_ADC_TEMP_NOM_MV 760.0f #define SAFETY_ADC_TEMP_MV_SLOPE 2.5f -#define SAFETY_ADC_NUM_OF_CHANNELS 2 -#define SAFETY_ADC_CHANNELS TEMP_CHANNEL_NUM, INT_REF_CHANNEL_NUM +#define SAFETY_ADC_NUM_OF_CHANNELS 8 +#define SAFETY_ADC_CHANNELS TEMP_CHANNEL_NUM, TEMP_CHANNEL_NUM, TEMP_CHANNEL_NUM, TEMP_CHANNEL_NUM, \ + INT_REF_CHANNEL_NUM, INT_REF_CHANNEL_NUM, INT_REF_CHANNEL_NUM, INT_REF_CHANNEL_NUM #endif /* __SAFETY_ADC_HWCFG_H__ */ diff --git a/stm-firmware/include/reflow-controller/pid-controller.h b/stm-firmware/include/reflow-controller/pid-controller.h index 87abd5a..16af242 100644 --- a/stm-firmware/include/reflow-controller/pid-controller.h +++ b/stm-firmware/include/reflow-controller/pid-controller.h @@ -27,6 +27,7 @@ struct pid_controller { float k_p; float k_int_t; float k_deriv_t; + float k_inv_deriv_t; float output_sat_max; float output_sat_min; float integral_max; diff --git a/stm-firmware/main.c b/stm-firmware/main.c index cb055ec..3b37283 100644 --- a/stm-firmware/main.c +++ b/stm-firmware/main.c @@ -55,6 +55,7 @@ static void setup_nvic_priorities(void) NVIC_SetPriority(DMA2_Stream0_IRQn, 1); /* Shelmatta UART TX */ NVIC_SetPriority(DMA2_Stream7_IRQn, 3); + NVIC_SetPriority(DMA2_Stream4_IRQn, 2); } FATFS fs; @@ -208,8 +209,10 @@ int main(void) handle_shell_uart_input(shell_handle); safety_controller_handle(); - /* Todo: Remove this */ - oven_driver_set_power(0); + if (oven_pid_get_status() == OVEN_PID_RUNNING) { + oven_pid_handle(); + } + oven_driver_apply_power_level(); safety_controller_report_timing(ERR_TIMING_MAIN_LOOP); diff --git a/stm-firmware/oven-driver.c b/stm-firmware/oven-driver.c index bca6446..588966c 100644 --- a/stm-firmware/oven-driver.c +++ b/stm-firmware/oven-driver.c @@ -31,6 +31,8 @@ static struct pid_controller IN_SECTION(.ccm.bss) oven_pid; static bool oven_pid_running; static bool oven_pid_aborted; static uint8_t IN_SECTION(.ccm.bss) oven_driver_power_level; +static float IN_SECTION(.ccm.bss) target_temp; +static uint64_t IN_SECTION(.ccm.bss) timestamp_last_run; void oven_driver_init(void) { @@ -56,6 +58,7 @@ void oven_driver_init(void) oven_pid_running = false; oven_driver_set_power(0U); + oven_driver_apply_power_level(); } void oven_driver_set_power(uint8_t power) @@ -88,13 +91,18 @@ void oven_pid_init(struct pid_controller *controller_to_copy) oven_pid_running = true; oven_pid_aborted = false; safety_controller_report_timing(ERR_TIMING_PID); + timestamp_last_run = systick_get_global_tick(); } -void oven_pid_handle(float target_temp) +void oven_pid_set_target_temperature(float temp) +{ + target_temp = temp; +} + +void oven_pid_handle(void) { float pid_out; float current_temp; - static uint64_t timestamp_last_run; if (oven_pid_running && !oven_pid_aborted) { if (systick_ticks_have_passed(timestamp_last_run, (uint64_t)(oven_pid.sample_period * 1000))) { diff --git a/stm-firmware/safety/safety-controller.c b/stm-firmware/safety/safety-controller.c index 25ffa6c..0d7f60b 100644 --- a/stm-firmware/safety/safety-controller.c +++ b/stm-firmware/safety/safety-controller.c @@ -112,7 +112,7 @@ static volatile struct error_flag IN_SECTION(.ccm.data) flags[] = { }; static volatile struct timing_mon IN_SECTION(.ccm.data) timings[] = { - TIM_MON_ENTRY(ERR_TIMING_PID, 2, 1000, ERR_FLAG_TIMING_PID), + TIM_MON_ENTRY(ERR_TIMING_PID, 2, 5000, ERR_FLAG_TIMING_PID), TIM_MON_ENTRY(ERR_TIMING_MEAS_ADC, 0, 50, ERR_FLAG_TIMING_MEAS_ADC), TIM_MON_ENTRY(ERR_TIMING_SAFETY_ADC, 10, SAFETY_CONTROLLER_ADC_DELAY_MS + 1000, ERR_FLAG_SAFETY_ADC), TIM_MON_ENTRY(ERR_TIMING_MAIN_LOOP, 0, 1000, ERR_FLAG_TIMING_MAIN_LOOP), @@ -538,6 +538,7 @@ static void safety_controller_handle_safety_adc() { static uint64_t last_result_timestamp = 0; const uint16_t *channels; + uint32_t sum; int poll_result; float analog_value; @@ -546,9 +547,19 @@ static void safety_controller_handle_safety_adc() if (poll_result == 1) { /* Data available */ channels = safety_adc_get_values(); - analog_value = safety_adc_convert_channel(SAFETY_ADC_MEAS_TEMP, channels[0]); + + /* Compute average of temp readings */ + sum = channels[0] + channels[1] + channels[2] + channels[3]; + sum /= 4; + + analog_value = safety_adc_convert_channel(SAFETY_ADC_MEAS_TEMP, (uint16_t)sum); safety_controller_report_analog_value(ERR_AMON_UC_TEMP, analog_value); - analog_value = safety_adc_convert_channel(SAFETY_ADC_MEAS_VREF, channels[1]); + + /* Average VREF readings */ + sum = channels[4] + channels[5] + channels[6] + channels[7]; + sum /= 4; + + analog_value = safety_adc_convert_channel(SAFETY_ADC_MEAS_VREF, (uint16_t)sum); safety_controller_report_analog_value(ERR_AMON_VREF, analog_value); last_result_timestamp = systick_get_global_tick(); safety_controller_report_timing(ERR_TIMING_SAFETY_ADC); diff --git a/stm-firmware/ui/gui.c b/stm-firmware/ui/gui.c index 6342484..dddedbc 100644 --- a/stm-firmware/ui/gui.c +++ b/stm-firmware/ui/gui.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include static char IN_SECTION(.ccm.bss) display_buffer[4][21] = {0}; static struct lcd_menu IN_SECTION(.ccm.bss) reflow_menu; @@ -297,21 +299,113 @@ static void gui_menu_err_flags(struct lcd_menu *menu, enum menu_entry_func_entry timestamp = systick_get_global_tick(); } +static void gui_menu_constant_temperature_driver(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent) +{ + static void IN_SECTION(.ccm.bss) *my_parent; + static int16_t IN_SECTION(.ccm.bss) temperature; + static bool IN_SECTION(.ccm.bss) fine; + enum button_state button; + int16_t rot; + int16_t temp_old; + + if (entry_type == MENU_ENTRY_FIRST_ENTER) { + my_parent = parent; + temperature = 30; + menu_display_clear(menu); + menu_lcd_outputf(menu, 0, "Temp Controller"); + temp_old = 0; + } else { + temp_old = temperature; + } + if (menu_get_button_ready_state(menu)) { + button = menu_get_button_state(menu); + rot = menu_get_rotary_delta(menu); + if (rot >= 4 || rot <= -4) { + menu_ack_rotary_delta(menu); + if (rot > 0) + temperature += (fine ? 1 : 10); + else + temperature -= (fine ? 1 : 10); + if (temperature > 300) + temperature = 300; + else if (temperature < 0) + temperature = 0; + } + + switch (button) { + case BUTTON_SHORT_RELEASED: + fine = !fine; + break; + case BUTTON_LONG: + oven_pid_stop(); + menu_entry_dropback(menu, my_parent); + break; + default: + break; + } + } + if (oven_pid_get_status() != OVEN_PID_RUNNING) { + menu_lcd_output(menu, 1, "PID stopped!"); + menu_lcd_output(menu, 2, "Check Flags!"); + } else { + if (temperature != temp_old) { + oven_pid_set_target_temperature((float)temperature); + menu_lcd_outputf(menu, 1, "Temp: %d " LCD_DEGREE_SYMBOL_STRING "C", (int)temperature); + } + } + +} + +static void gui_menu_constant_temperature_driver_setup(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent) +{ + static void IN_SECTION(.ccm.bss) *my_parent; + struct oven_pid_settings pid_settings; + enum button_state button; + struct pid_controller pid_controller; + + if (entry_type == MENU_ENTRY_FIRST_ENTER) { + my_parent = parent; + + /* Try loading PID parameters */ + if (settings_load_pid_oven_parameters(&pid_settings)) { + menu_display_clear(menu); + menu_lcd_output(menu, 0, "Could not load"); + menu_lcd_output(menu, 1, "PID parameters"); + } else { + pid_init(&pid_controller, pid_settings.kd, pid_settings.ki, pid_settings.kp, 0, 100, + pid_settings.max_integral, pid_settings.t_sample); + oven_pid_init(&pid_controller); + menu_entry_enter(menu, gui_menu_constant_temperature_driver, true); + } + } else if (entry_type == MENU_ENTRY_DROPBACK) { + menu_entry_dropback(menu, my_parent); + } + + if (menu_get_button_ready_state(menu)) { + button = menu_get_button_state(menu); + if (button == BUTTON_SHORT_RELEASED || button == BUTTON_LONG) { + menu_entry_dropback(menu, my_parent); + } + } +} + static void gui_menu_root_entry(struct lcd_menu *menu, enum menu_entry_func_entry entry_type, void *parent) { (void)parent; static struct menu_list list; bool menu_changed = false; static const char * const root_entry_names[] = { - "About", + "Constant Temp", "Monitoring", "Error Flags", + "About", NULL }; static const menu_func_t root_entry_funcs[] = { - gui_menu_about, + gui_menu_constant_temperature_driver_setup, gui_menu_monitor, gui_menu_err_flags, + gui_menu_about, }; enum button_state push_button; int16_t rot_delta; diff --git a/stm-firmware/ui/menu.c b/stm-firmware/ui/menu.c index 2ee69e9..002c0d8 100644 --- a/stm-firmware/ui/menu.c +++ b/stm-firmware/ui/menu.c @@ -81,6 +81,8 @@ void menu_entry_dropback(struct lcd_menu *menu, menu_func_t parent_func) else menu->active_entry = menu->root_entry; + menu_ack_rotary_delta(menu); + menu->active_entry_type = MENU_ENTRY_DROPBACK; }