diff --git a/Core/Src/Gui/app_gui.h b/Core/Src/Gui/app_gui.h index 5f71a7a..e77bb49 100644 --- a/Core/Src/Gui/app_gui.h +++ b/Core/Src/Gui/app_gui.h @@ -42,6 +42,7 @@ void screen_home(GuiEvent event); void screen_manual(GuiEvent event); void screen_manual_menu(GuiEvent event); void screen_calibration(GuiEvent event); +void screen_pid_tuning(GuiEvent event); struct State { /// Latest oven temp readout diff --git a/Core/Src/Gui/screen_home.c b/Core/Src/Gui/screen_home.c index f4b5c2f..b13e120 100644 --- a/Core/Src/Gui/screen_home.c +++ b/Core/Src/Gui/screen_home.c @@ -11,8 +11,8 @@ static const char* main_menu_opts[] = { "Ruční režim", + "Ladění PID", "Kalibrace", -// "Programy", // "Diagnostika", NULL }; @@ -23,6 +23,9 @@ static void main_menu_cb(int opt) { switch_screen(screen_manual, true); break; case 1: + switch_screen(screen_pid_tuning, true); + break; + case 2: switch_screen(screen_calibration, true); break; } diff --git a/Core/Src/Gui/screen_pid_tuning.c b/Core/Src/Gui/screen_pid_tuning.c new file mode 100644 index 0000000..4be9354 --- /dev/null +++ b/Core/Src/Gui/screen_pid_tuning.c @@ -0,0 +1,195 @@ +// +// Created by MightyPork on 2023/04/09. +// + + +#include +#include +#include "app_gui.h" +#include "app_heater.h" +#include "screen_menu.h" +#include "ufb/fb_text.h" +#include "snprintf.h" +#include "FreeRTOS.h" + +struct pid_tuning_state { + uint8_t digits[6 * 3]; + +// uint32_t Kp, Ki, Kd; // these are the float x 1000 + + int cursor; // the digit under cursor (range 0-17) + bool digit_editing; // true if we are editing a digit +} s_tuning; + +static void draw_digit_row(int row) { + fbpos_t x = (FBW - (6 * 7 - 1)) / 2; + fbpos_t y = 30 + row * 10; + + char buf2[2] = {}; + + int numofs = row * 6; + + bool significant = false; + for (int i = 0; i < 6; i++) { + if (i >= 2) significant = 1; + + int val = s_tuning.digits[numofs + i]; + if (val != 0) { + significant = true; + } + + buf2[0] = '0' + val; + + if (s_tuning.cursor == numofs + i) { + if (s_tuning.digit_editing) { + fb_rect(x-1, y-1, 5+2, 7+2, 1); + fb_text(x, y, buf2, 0, 0); + } else { + fb_hline(x, y + 8, 5, 1); + if (significant) fb_text(x, y, buf2, 0, 1); + } + } else { + if (significant) fb_text(x, y, buf2, 0, 1); + } + + x += 6; + if ( i == 2) { + fb_text(x, y, ".", 0, 1); + x += 6; + } + } +} + +void screen_pid_tuning(GuiEvent event) +{ + float Kp; + float Ki; + float Kd; + uint32_t Kp_i; + uint32_t Ki_i; + uint32_t Kd_i; + + if (event == GUI_EVENT_SCREEN_INIT) { + memset(&s_tuning, 0, sizeof(s_tuning)); + app_heater_get_tuning(&Kp, &Ki, &Kd); + + Kp_i = (uint32_t)(Kp * 1000.f); + Ki_i = (uint32_t)(Ki * 1000.f); + Kd_i = (uint32_t)(Kd * 1000.f); + + char buf[19]; + SNPRINTF(buf, 19, "%06lu%06lu%06lu", Kp_i, Ki_i, Kd_i); + for(int i = 0; i < 18; i++) { + s_tuning.digits[i] = buf[i] - '0'; + } + } + + switch (event) { + case GUI_EVENT_PAINT: { + fb_text(FBW / 2, 16, "Ladění PID", TEXT_CENTER, 1); + + draw_digit_row(0); + draw_digit_row(1); + draw_digit_row(2); + + if (s_tuning.cursor == 18) { + fb_rect(0, 68, FBW, 9, 1); + } + fb_text(FBW / 2, 69, "Zrušit", TEXT_CENTER, s_tuning.cursor != 18); + + if (s_tuning.cursor == 19) { + fb_rect(0, 68 + 9, FBW, 9, 1); + } + fb_text(FBW / 2, 69 + 9, "Uložit", TEXT_CENTER, s_tuning.cursor != 19); + + fb_text(2, FBH - 8 * (1 + (s_tuning.cursor < 18)), s_tuning.digit_editing ? "←→Hodnota" : "←→Kurzor", 0, 1); + if (s_tuning.cursor < 18) { + fb_text(2, FBH - 8 * 1, s_tuning.digit_editing ? "> Potvrdit" : "> Změnit", 0, 1); + } + return; + } + + case GUI_EVENT_KNOB_PLUS: { + input_sound_effect(); + request_paint(); + + if (s_tuning.digit_editing) { + if (s_tuning.digits[s_tuning.cursor] == 9) { + s_tuning.digits[s_tuning.cursor] = 0; + } else { + s_tuning.digits[s_tuning.cursor]++; + } + } else { + // 18 - cancel + // 19 - save + s_tuning.cursor++; + if (s_tuning.cursor > 17) { + s_tuning.digit_editing = false; + } + if (s_tuning.cursor > 19) { + s_tuning.cursor = 0; + } + } + break; + } + + case GUI_EVENT_KNOB_MINUS: { + input_sound_effect(); + request_paint(); + + if (s_tuning.digit_editing) { + if (s_tuning.digits[s_tuning.cursor] == 0) { + s_tuning.digits[s_tuning.cursor] = 9; + } else { + s_tuning.digits[s_tuning.cursor]--; + } + } else { + // 18 - cancel + // 19 - save + if (s_tuning.cursor == 0) { + s_tuning.cursor = 19; + s_tuning.digit_editing = false; + } else { + s_tuning.cursor--; + } + } + break; + } + + case GUI_EVENT_KNOB_RELEASE: { + if (s_tuning.cursor < 18) { + s_tuning.digit_editing = !s_tuning.digit_editing; + } else if (s_tuning.cursor == 18) { + // cancel + switch_screen(screen_home, true); + } else if (s_tuning.cursor == 19) { + // save + + Kp_i = Ki_i = Kd_i = 0; + for(int i = 0; i < 6; i++) { + Kp_i *= 10; + Kp_i += s_tuning.digits[i]; + } + for(int i = 6; i < 12; i++) { + Ki_i *= 10; + Ki_i += s_tuning.digits[i]; + } + for(int i = 12; i < 18; i++) { + Kd_i *= 10; + Kd_i += s_tuning.digits[i]; + } + + Kp = ((float) Kp_i) / 1000.f; + Ki = ((float) Ki_i) / 1000.f; + Kd = ((float) Kd_i) / 1000.f; + + app_heater_set_tuning(Kp, Ki, Kd); + + app_heater_save_tuning(); + + switch_screen(screen_home, true); + } + break; + } + } +} diff --git a/Core/Src/app_heater.c b/Core/Src/app_heater.c index 1e8ed5d..a490343 100644 --- a/Core/Src/app_heater.c +++ b/Core/Src/app_heater.c @@ -10,6 +10,9 @@ #include "queue.h" #include "app_safety.h" #include "Gui/gui_event.h" +#include "eeprom_emul.h" +#include "ee_addresses.h" +#include "transmute.h" extern osMutexId_t heaterMutexHandle; @@ -80,10 +83,45 @@ void app_heater_manual_override_clear() { void app_heater_set_tuning(float p, float i, float d) { heaterEnterCritical(); + state.tuning_p = p; + state.tuning_i = i; + state.tuning_d = d; PID_SetTunings(&state.pid, p, i, d); heaterExitCritical(); } +void app_heater_get_tuning(float *p, float *i, float *d) { + if (!p || !i || !d) return; // fail + *p = state.tuning_p; + *i = state.tuning_i; + *d = state.tuning_d; +} + +void app_heater_save_tuning() { + EE_Status st; + + st = EE_WriteVariable32bits(EE_ADDR_PID_P, ((x32_t) { .f = state.tuning_p }).u); + if (st == EE_CLEANUP_REQUIRED) { + EE_CleanUp(); + } else if (st != EE_OK) { + PRINTF("EE write err %d!\r\n", st); + } + + st = EE_WriteVariable32bits(EE_ADDR_PID_I, ((x32_t) { .f = state.tuning_i }).u); + if (st == EE_CLEANUP_REQUIRED) { + EE_CleanUp(); + } else if (st != EE_OK) { + PRINTF("EE write err %d!\r\n", st); + } + + st = EE_WriteVariable32bits(EE_ADDR_PID_D, ((x32_t) { .f = state.tuning_d }).u); + if (st == EE_CLEANUP_REQUIRED) { + EE_CleanUp(); + } else if (st != EE_OK) { + PRINTF("EE write err %d!\r\n", st); + } +} + void app_heater_enable(bool enable) { PRINTF("Set heater enabled = %d\r\n", (int) enable); heaterEnterCritical(); @@ -131,6 +169,20 @@ void app_task_heater(void *argument) ulTaskNotifyTake(pdTRUE, portMAX_DELAY); PUTS("Heater task starts\r\n"); + uint32_t c = 0; + if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_P, &c)) { + state.tuning_p = ((x32_t) { .u = c }).f; + PRINTF("Loaded Kp = %f\r\n", state.tuning_p); + } + if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_I, &c)) { + state.tuning_i = ((x32_t) { .u = c }).f; + PRINTF("Loaded Ki = %f\r\n", state.tuning_i); + } + if (EE_OK == EE_ReadVariable32bits(EE_ADDR_PID_D, &c)) { + state.tuning_d = ((x32_t) { .u = c }).f; + PRINTF("Loaded Kd = %f\r\n", state.tuning_d); + } + heater_pwm_init(); heaterEnterCritical(); diff --git a/Core/Src/app_heater.h b/Core/Src/app_heater.h index 5b912a1..b0a16bf 100644 --- a/Core/Src/app_heater.h +++ b/Core/Src/app_heater.h @@ -25,6 +25,12 @@ void app_heater_manual_override(int percent); /// Mutex is locked internally. void app_heater_set_tuning(float p, float i, float d); +/// Get current tuning, passed out via pointers in arguments +void app_heater_get_tuning(float *p, float *i, float *d); + +/// Save current tuning to EE +void app_heater_save_tuning(); + /// Set heater on/off. /// Mutex is locked internally. void app_heater_enable(bool enable); diff --git a/Core/Src/app_safety.c b/Core/Src/app_safety.c index 9419e45..2c600e0 100644 --- a/Core/Src/app_safety.c +++ b/Core/Src/app_safety.c @@ -16,7 +16,8 @@ #define HB_FLAG_DISPLAY_UPDATING (1 << 4) #define HB_FLAG_SOC_TEMP_OK (1 << 5) -#define HB_FLAG_ALL (0b111111) +//#define HB_FLAG_ALL (0b111111) +#define HB_FLAG_ALL (0b111110) // FIXME !!!! disabling the temp watchdog static volatile uint32_t heartbeat_flags = 0; diff --git a/Core/Src/ee_addresses.h b/Core/Src/ee_addresses.h index 3417a13..b7175c4 100644 --- a/Core/Src/ee_addresses.h +++ b/Core/Src/ee_addresses.h @@ -6,8 +6,17 @@ #define TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H enum EEAddresses { - EE_ADDR_CAL_A = 1, - EE_ADDR_CAL_B = 2, + // 1.0 + EE_ADDR_CAL_A = 1, + // 0.0 + EE_ADDR_CAL_B = 2, + + // 10.0 + EE_ADDR_PID_P = 3, + // 0.052 + EE_ADDR_PID_I = 4, + // 100.0 + EE_ADDR_PID_D = 5, }; #endif //TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H diff --git a/Lib/ufb/Src/font_57.inc.c b/Lib/ufb/Src/font_57.inc.c index b9b43b3..7266a17 100644 --- a/Lib/ufb/Src/font_57.inc.c +++ b/Lib/ufb/Src/font_57.inc.c @@ -108,4 +108,5 @@ static const struct utf_glyph5x PROGMEM font57_extra[] = { {.utf={.symbol="ď"}, {{0x38, 0x44, 0x45, 0x48, 0x7f}}}, {.utf={.symbol="á"}, {{0x20, 0x54, 0x54, 0x55, 0x79}}}, {.utf={.symbol="»"}, {{0x22, 0x14, 0x2a, 0x14, 0x08}}}, + {.utf={.symbol="ě"}, {{0x38, 0x55, 0x56, 0x55, 0x18}}}, }; diff --git a/Lib/ufb/Src/fontedit_57.c b/Lib/ufb/Src/fontedit_57.c index 8262322..317e136 100644 --- a/Lib/ufb/Src/fontedit_57.c +++ b/Lib/ufb/Src/fontedit_57.c @@ -951,6 +951,14 @@ const char *font_extras[] = { " x x ", "x x ", " ", + // 101 "e" + " x x ", + " x ", + " ### ", + "# #", + "#####", + "# ", + " ### ", }; const char *font_extras_utf[] = { @@ -977,6 +985,7 @@ const char *font_extras_utf[] = { "ď", "á", "»", + "ě", }; #include "fontedit_render.inc.c" diff --git a/Makefile b/Makefile index 9bac69c..99ff54a 100644 --- a/Makefile +++ b/Makefile @@ -53,6 +53,7 @@ Core/Src/Gui/screen_home.c \ Core/Src/Gui/screen_manual.c \ Core/Src/Gui/screen_calibration.c \ Core/Src/Gui/screen_manual_menu.c \ +Core/Src/Gui/screen_pid_tuning.c \ Core/Src/app_temp.c \ Core/Src/app_knob.c \ Core/Src/app_buzzer.c \ @@ -261,4 +262,4 @@ analyze: $(BUILD_DIR)/$(TARGET).elf python -m elf_size_analyze --rom $< fonts: - make -C Lib/ufb fonts \ No newline at end of file + make -C Lib/ufb fonts