Compare commits

..

No commits in common. 'master' and 'calib-gui' have entirely different histories.

  1. 15
      Core/Src/Gui/app_gui.c
  2. 2
      Core/Src/Gui/app_gui.h
  3. 217
      Core/Src/Gui/screen_calib_edit.c
  4. 70
      Core/Src/Gui/screen_calibration.c
  5. 12
      Core/Src/Gui/screen_home.c
  6. 194
      Core/Src/Gui/screen_pid_tuning.c
  7. 66
      Core/Src/app_heater.c
  8. 13
      Core/Src/app_heater.h
  9. 2
      Core/Src/app_knob.c
  10. 17
      Core/Src/app_pid.c
  11. 3
      Core/Src/app_pid.h
  12. 4
      Core/Src/app_safety.c
  13. 221
      Core/Src/app_temp.c
  14. 11
      Core/Src/app_temp.h
  15. 16
      Core/Src/ee_addresses.h
  16. 4
      Core/Src/freertos.c
  17. 178
      Core/Src/stm32f1xx_it.c
  18. 28
      Lib/snprintf/snprintf.c
  19. 2
      Lib/ufb/Src/font_57.inc.c
  20. 18
      Lib/ufb/Src/fontedit_57.c
  21. 4
      Makefile

@ -13,7 +13,6 @@
#include "ufb/framebuffer.h"
#include "ufb/fb_text.h"
#include "app_safety.h"
#include "app_heater.h"
struct State s_app = {};
@ -122,7 +121,6 @@ void app_task_gui(void *argument) {
/** Switch to a different screen handler.
* If "init" is true, immediately call it with the init event. */
void switch_screen(screen_t pScreen, bool init) {
PRINTF("Screen = %p, init=%d\r\n", pScreen, init);
s_app.initial_pushed = s_app.pushed;
s_app.screen = pScreen;
// clear the union field
@ -135,20 +133,11 @@ void switch_screen(screen_t pScreen, bool init) {
/** Draw GUI common to all screens */
static void draw_common_overlay() {
SPRINTF(stmp, "%5.1f°C →%3d°C", app_temp_read_oven(), (int) app_heater_get_target());
SPRINTF(stmp, "%5.1f°C →%3d°C", s_app.oven_temp, s_app.set_temp);
fb_text(3, 3, stmp, FONT_3X5, 1);
float soc = app_temp_read_soc();
if (soc > 70) {
SPRINTF(stmp, "! CHIP %d°C !", (int) soc);
fb_text(3, 14, stmp, FONT_3X5, 1);
}
if (app_heater_get_state()) {
if (s_app.heater_enabled) {
fb_frame(0, 0, FBW, 11, 1, 1);
float perc = app_heater_get_percent();
fb_hline(0, 12, (fbpos_t) ((float)FBW * (perc / 100.0f)), 1);
}
}

@ -42,8 +42,6 @@ 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);
void screen_calib_edit(GuiEvent event);
struct State {
/// Latest oven temp readout

@ -1,217 +0,0 @@
//
// Created by MightyPork on 2023/05/06
//
#include <string.h>
#include "app_gui.h"
#include "app_heater.h"
#include "ufb/fb_text.h"
#include "snprintf.h"
#include "app_temp.h"
static void apply_calib(bool temporary);
static struct calib_tuning_state {
uint8_t digits[6 * 4]; // a b l r
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;
const char * labels[4] = {"a","b","L", "R"};
const int decimal_pos[4] = {2, 0, 3, 3};
fb_text(FBW - 4, y + 2, labels[row], FONT_3X5, 1);
bool significant = row == 1;
for (int i = 0; i < 6; i++) {
if (i >= decimal_pos[row]) 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 == decimal_pos[row]) {
fb_text(x, y, ".", 0, 1);
x += 6;
}
}
}
void screen_calib_edit(GuiEvent event)
{
float A, B, L, R;
uint32_t Ai, Bi, Li, Ri;
if (event == GUI_EVENT_SCREEN_INIT) {
memset(&s_tuning, 0, sizeof(s_tuning));
app_temp_get_calib(&A, &B, &L, &R);
app_temp_backup_calib();
Ai = (uint32_t)(A * 1000.f);
Bi = (uint32_t)(B * 100000.f);
Li = (uint32_t)(L * 100.f);
Ri = (uint32_t)(R * 100.f);
char buf[25];
SNPRINTF(buf, 25, "%06lu%06lu%06lu%06lu", Ai, Bi, Li, Ri);
for(int i = 0; i < 6*4; i++) {
s_tuning.digits[i] = buf[i] - '0';
}
}
switch (event) {
case GUI_EVENT_PAINT: {
fb_text(FBW / 2, 16, "Kalibrace", TEXT_CENTER, 1);
draw_digit_row(0);
draw_digit_row(1);
draw_digit_row(2);
draw_digit_row(3);
//68
#define BTNS_TOP 72
if (s_tuning.cursor == 24) {
fb_rect(0, BTNS_TOP, FBW, 9, 1);
}
fb_text(FBW / 2, BTNS_TOP + 1, "Zrušit", TEXT_CENTER, s_tuning.cursor != 24);
if (s_tuning.cursor == 25) {
fb_rect(0, BTNS_TOP + 9, FBW, 9, 1);
}
fb_text(FBW / 2, BTNS_TOP + 1 + 9, "Uložit", TEXT_CENTER, s_tuning.cursor != 25);
fb_text(2, FBH - 8 * (1 + (s_tuning.cursor < 24)), s_tuning.digit_editing ? "←→Hodnota" : "←→Kurzor", 0, 1);
if (s_tuning.cursor < 24) {
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]++;
}
apply_calib(false);
} else {
// 24 - cancel
// 25 - save
s_tuning.cursor++;
if (s_tuning.cursor >= 24) {
s_tuning.digit_editing = false;
}
if (s_tuning.cursor > 25) {
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]--;
}
apply_calib(false);
} else {
// 24 - cancel
// 25 - save
if (s_tuning.cursor == 0) {
s_tuning.cursor = 25;
s_tuning.digit_editing = false;
} else {
s_tuning.cursor--;
}
}
break;
}
case GUI_EVENT_KNOB_RELEASE: {
if (s_tuning.cursor < 24) {
s_tuning.digit_editing = !s_tuning.digit_editing;
} else if (s_tuning.cursor == 24) {
// cancel
app_temp_restore_calib();
switch_screen(screen_home, true);
} else if (s_tuning.cursor == 25) {
// save
apply_calib(true);
switch_screen(screen_home, true);
}
break;
}
}
}
static void apply_calib(bool temporary) {
float A, B, L, R;
uint32_t Ai, Bi, Li, Ri;
Ai = Bi = Li = Ri = 0;
for(int i = 0; i < 6; i++) {
Ai *= 10;
Ai += s_tuning.digits[i];
}
for(int i = 6; i < 12; i++) {
Bi *= 10;
Bi += s_tuning.digits[i];
}
for(int i = 12; i < 18; i++) {
Li *= 10;
Li += s_tuning.digits[i];
}
for(int i = 18; i < 24; i++) {
Ri *= 10;
Ri += s_tuning.digits[i];
}
A = ((float) Ai) / 1000.f;
B = ((float) Bi) / 100000.f;
L = ((float) Li) / 100.f;
R = ((float) Ri) / 100.f;
if (temporary) {
app_temp_set_calib_temporary(A, B);
app_temp_set_calib_temporary_r(L, R);
} else {
app_temp_set_calib_persistent(A, B);
app_temp_set_calib_persistent_r(L, R);
}
}

@ -30,17 +30,6 @@ enum Phase {
PH_DONE,
};
static void stop_heater() {
app_heater_set_target(0);
app_heater_enable(false);
}
static void calib_abort() {
app_temp_restore_calib();
stop_heater();
switch_screen(screen_home, true);
}
static void next_phase() {
PUTS("Phase++\r\n");
s_calib.phase++;
@ -58,12 +47,11 @@ static void hello_menu_cb(int opt) {
// Continue
next_phase();
request_paint();
app_heater_set_target(100);
app_heater_enable(true);
app_heater_manual_override(100);
break;
case 1:
calib_abort();
switch_screen(screen_home, true);
break;
}
}
@ -81,13 +69,13 @@ static void sample1_menu_cb(int opt) {
// Continue
next_phase();
request_paint();
s_calib.temp1 = 100;
s_calib.sample1 = app_temp_read_oven_raw();
app_heater_enable(false);
app_heater_manual_override(0);
break;
case 1:
calib_abort();
app_heater_manual_override(-1);
switch_screen(screen_home, true);
break;
}
}
@ -105,13 +93,13 @@ static void sample2_menu_cb(int opt) {
// Continue
next_phase();
request_paint();
s_calib.temp2 = 200;
s_calib.sample2 = app_temp_read_oven_raw();
app_heater_enable(false);
app_heater_manual_override(0);
break;
case 1:
calib_abort();
app_heater_manual_override(-1);
switch_screen(screen_home, true);
break;
}
}
@ -119,8 +107,6 @@ static void sample2_menu_cb(int opt) {
void screen_calibration(GuiEvent event)
{
if (event == GUI_EVENT_SCREEN_INIT) {
app_temp_backup_calib();
app_temp_set_calib_temporary(1, 0);
memset(&s_calib, 0, sizeof(s_calib));
// continue to the rest - so the menu can be inited
}
@ -135,20 +121,17 @@ void screen_calibration(GuiEvent event)
screen_menu_offset(event, hello_menu_opts, hello_menu_cb, 30);
break;
case PH_SAMPLE1:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 16, "Vyčkej", TEXT_CENTER, 1);
fb_text(FBW/2, 26, "ustálení", TEXT_CENTER, 1);
}
screen_menu_offset(event, sample1_menu_opts, sample1_menu_cb, 30);
break;
case PH_SAMPLE1: // Heater is active, waiting for mark
case PH_SAMPLE2:
if (event == GUI_EVENT_PAINT) {
fb_text(FBW/2, 16, "Vyčkej", TEXT_CENTER, 1);
fb_text(FBW/2, 26, "ustálení", TEXT_CENTER, 1);
fb_text(FBW/2, 16, "Zapiš", TEXT_CENTER, 1);
fb_text(FBW/2, 26, "teplotu", TEXT_CENTER, 1);
}
if (s_calib.phase == PH_SAMPLE1) {
screen_menu_offset(event, sample1_menu_opts, sample1_menu_cb, 30);
} else {
screen_menu_offset(event, sample2_menu_opts, sample2_menu_cb, 30);
}
screen_menu_offset(event, sample2_menu_opts, sample2_menu_cb, 30);
break;
case PH_TEMP1:
@ -161,7 +144,8 @@ void screen_calibration(GuiEvent event)
if (push_time() > pdMS_TO_TICKS(500)) {
input_sound_effect();
calib_abort();
app_heater_manual_override_clear();
switch_screen(screen_home, true);
return;
}
@ -199,12 +183,8 @@ void screen_calibration(GuiEvent event)
next_phase();
request_paint();
PRINTF("KNOB_REL PH %d\r\n", s_calib.phase);
if (s_calib.phase == PH_DONE) {
app_heater_set_target(0);
app_heater_enable(false);
app_heater_manual_override(-1);
// TODO do the math
PRINTF("Sample 1 %f, T1 %d\r\n", s_calib.sample1, s_calib.temp1);
PRINTF("Sample 2 %f, T2 %d\r\n", s_calib.sample2, s_calib.temp2);
@ -215,13 +195,10 @@ void screen_calibration(GuiEvent event)
float a = (corrected1 - corrected2) / (s_calib.sample1 - s_calib.sample2);
float b = corrected1 - a * s_calib.sample1;
app_temp_set_calib_persistent(a, b);
} else if (s_calib.phase == PH_SAMPLE1) {
app_heater_set_target(100);
app_heater_enable(true);
} else if (s_calib.phase == PH_SAMPLE2) {
app_heater_set_target(200);
app_heater_enable(true);
app_temp_set_calib(a, b);
} else {
// for the next phase
app_heater_manual_override(100);
}
break;
}
@ -234,7 +211,6 @@ void screen_calibration(GuiEvent event)
fb_text(FBW/2, 36, "→Hlavní menu", TEXT_CENTER, 1);
}
if (event == GUI_EVENT_KNOB_RELEASE) {
stop_heater();
switch_screen(screen_home, 1);
}
break;

@ -11,9 +11,9 @@
static const char* main_menu_opts[] = {
"Ruční režim",
"Ladění PID",
"Auto kalibrace",
"Ruční kalibrace",
"Kalibrace",
// "Programy",
// "Diagnostika",
NULL
};
@ -23,14 +23,8 @@ 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;
case 3:
switch_screen(screen_calib_edit, true);
break;
}
}

@ -1,194 +0,0 @@
//
// Created by MightyPork on 2023/04/09.
//
#include <string.h>
#include "app_gui.h"
#include "app_heater.h"
#include "ufb/fb_text.h"
#include "snprintf.h"
static struct calib_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;
const char * labels[3] = {"P","I","D"};
fb_text(FBW - 4, y + 2, labels[row], FONT_3X5, 1);
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;
}
}
}

@ -10,9 +10,6 @@
#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;
@ -83,45 +80,10 @@ 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();
@ -136,18 +98,6 @@ void app_heater_set_target(float target) {
heaterExitCritical();
}
bool app_heater_get_state() {
return state.pid.ctlMode == PID_AUTOMATIC;
}
float app_heater_get_percent() {
return state.pid.Output;
}
float app_heater_get_target() {
return state.pid.Setpoint;
}
// emergency shutdown, this must not block use RTOS since it can be called from fault handlers or interrupt
void app_heater_emergency_shutdown() {
// Stop pwm
@ -173,27 +123,11 @@ 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();
// TODO load from flash
PID_SetTunings(&state.pid, state.tuning_p, state.tuning_i, state.tuning_d);
PID_SetOutputLimits(&state.pid, 0, 100);
PID_SetITermLimits(&state.pid, 0, 100);
PID_Initialize(&state.pid);
heaterExitCritical();

@ -25,12 +25,6 @@ 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);
@ -42,11 +36,4 @@ void app_heater_set_target(float target);
/// Shutdown the heater; This function does not use mutex and just disables the PWM via register access.
void app_heater_emergency_shutdown();
bool app_heater_get_state();
float app_heater_get_target();
float app_heater_get_percent();
#endif //BLUEPILLTROUBA_APP_HEATER_H

@ -71,7 +71,7 @@ bool app_knob_pushed() {
void app_knob_push_isr(bool push)
{
//PUTCHAR(push ? '#' : '.');
PUTCHAR(push ? '#' : '.');
BaseType_t yield = pdFALSE;
if (push) {

@ -13,8 +13,8 @@ static void clampOutput(struct PID *self)
static void clampIterm(struct PID *self)
{
if (self->ITerm > self->iTermMax) { self->ITerm = self->iTermMax; }
else if (self->ITerm < self->iTermMin) { self->ITerm = self->iTermMin; }
if (self->ITerm > self->outMax) { self->ITerm = self->outMax; }
else if (self->ITerm < self->outMin) { self->ITerm = self->outMin; }
}
void PID_Compute(struct PID *self, float input)
@ -32,11 +32,6 @@ void PID_Compute(struct PID *self, float input)
clampIterm(self);
// Shortcut to reduce overshoot
if (error < 0 && self->ITerm > 0) {
self->ITerm = 0;
}
float dInput = (input - self->lastInput);
@ -96,14 +91,6 @@ void PID_SetOutputLimits(struct PID *self, float min, float max)
self->outMax = max;
clampOutput(self);
}
void PID_SetITermLimits(struct PID *self, float min, float max)
{
if (min > max) { return; }
self->iTermMin = min;
self->iTermMax = max;
clampIterm(self);
}

@ -27,7 +27,6 @@ struct PID {
float kp, ki, kd;
uint32_t SampleTimeTicks;
float outMin, outMax;
float iTermMin, iTermMax;
enum PIDCtlMode ctlMode; // false
enum PIDDirection controllerDirection;
};
@ -42,8 +41,6 @@ void PID_SetSampleTime(struct PID *self, uint32_t new_sample_time);
void PID_SetOutputLimits(struct PID *self, float min, float max);
void PID_SetITermLimits(struct PID *self, float min, float max);
void PID_SetCtlMode(struct PID *self, enum PIDCtlMode mode);
void PID_Initialize(struct PID *self);

@ -16,8 +16,7 @@
#define HB_FLAG_DISPLAY_UPDATING (1 << 4)
#define HB_FLAG_SOC_TEMP_OK (1 << 5)
//#define HB_FLAG_ALL (0b111111)
#define HB_FLAG_ALL (0b111110) // FIXME !!!! disabling the temp watchdog
#define HB_FLAG_ALL (0b111111)
static volatile uint32_t heartbeat_flags = 0;
@ -46,7 +45,6 @@ void app_safety_pass_soc_temp_ok() {
}
void app_safety_poll() {
//PRINTF("\r\n*** HB FLAGS %x ***\r\n", heartbeat_flags);
if ((heartbeat_flags & HB_FLAG_ALL) == HB_FLAG_ALL) {
LL_IWDG_ReloadCounter(IWDG);
LL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

@ -3,8 +3,12 @@
*/
#include "main.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "app_temp.h"
#include "adc.h"
#include "snprintf.h"
#include "app_safety.h"
#include "eeprom_emul_types.h"
@ -17,32 +21,20 @@ static volatile uint16_t adc_values[4];
const float V_REFINT = 1.23f;
#define AVERAGEBUF_DEPTH 4
#define OVENTEMP_HISTORY_DEPTH 4
#define AVERAGEBUF_DEPTH 16
#define OVENTEMP_HISTORY_DEPTH 20
static struct App {
float oven_temp;
float oven_temp_raw;
float soc_temp;
float cal_a;
float cal_b;
float reference_resistor;
float lead_resistance;
// original values are copied here during calibration, so they can be reverted
float saved_cal_a;
float saved_cal_b;
float saved_lead_resistance;
float saved_reference_resistor;
float oventemp_history[OVENTEMP_HISTORY_DEPTH]; // raw temp
uint16_t adc_averagebuf[AVERAGEBUF_DEPTH * 4];
uint8_t averagebuf_ptr;
uint8_t oventemp_history_ptr;
} s_analog = {
.reference_resistor = 1000.0f,
.lead_resistance = 0.0f,
// Ax + B = y ... X = raw sample (ratio 0-1 of 3.3), Y = corrected sample
.cal_a = 1.0f, // safe default calibration constants
.cal_b = 0.0f,
@ -52,8 +44,6 @@ static struct App {
#define TSENSE_T_STEP 5.0f
#define TSENSE_T_MIN 0.0f
#define TSENSE_T_MAX 500.0f
#if 0 // Ratios
static const float TSENSE_LOOKUP[TSENSE_LOOKUP_LEN] = {
0.0909090909090909f,
0.0925200328471449f,
@ -157,136 +147,18 @@ static const float TSENSE_LOOKUP[TSENSE_LOOKUP_LEN] = {
0.218329057984116f,
0.219346163379138f,
};
#else
static const float PT100_LOOKUP[TSENSE_LOOKUP_LEN] = {
100.f, // 0 C
101.9527f,
103.9025f,
105.8495f,
107.7935f,
109.7347f,
111.6729f,
113.6083f,
115.5408f,
117.4704f,
119.3971f,
121.321f,
123.2419f,
125.16f,
127.0751f,
128.9874f,
130.8968f,
132.8033f,
134.7069f,
136.6077f,
138.5055f,
140.4005f,
142.2925f,
144.1817f,
146.068f,
147.9514f,
149.8319f,
151.7096f,
153.5843f,
155.4562f,
157.3251f,
159.1912f,
161.0544f,
162.9147f,
164.7721f,
166.6267f,
168.4783f,
170.3271f,
172.1729f,
174.0159f,
175.856f,
177.6932f,
179.5275f,
181.359f,
183.1875f,
185.0132f,
186.8359f,
188.6558f,
190.4728f,
192.2869f,
194.0981f,
195.9065f,
197.7119f,
199.5145f,
201.3141f,
203.1109f,
204.9048f,
206.6958f,
208.4839f,
210.2692f,
212.0515f,
213.831f,
215.6075f,
217.3812f,
219.152f,
220.9199f,
222.6849f,
224.4471f,
226.2063f,
227.9627f,
229.7161f,
231.4667f,
233.2144f,
234.9592f,
236.7011f,
238.4402f,
240.1763f,
241.9096f,
243.6399f,
245.3674f,
247.092f,
248.8137f,
250.5325f,
252.2485f,
253.9615f,
255.6717f,
257.3789f,
259.0833f,
260.7848f,
262.4834f,
264.1791f,
265.872f,
267.5619f,
269.249f,
270.9331f,
272.6144f,
274.2928f,
275.9683f,
277.6409f,
279.3107f,
280.9775f, // 500 C
};
#endif
void app_temp_get_calib(float *a, float *b, float *l, float *r) {
*a = s_analog.cal_a;
*b = s_analog.cal_b;
*l = s_analog.lead_resistance;
*r = s_analog.reference_resistor;
}
/// if the calibration constants are zero, reset to defaults
static void correct_invalid_calib() {
if (s_analog.cal_a == 0.0f) { // || s_analog.cal_b == 0.0f
if (s_analog.cal_a == 0.0f || s_analog.cal_b == 0.0f) {
PRINTF("ADC invalid calib, reset\r\n");
s_analog.cal_a = 1.0f;
s_analog.cal_b = 0.0f;
}
if (s_analog.reference_resistor == 0.0f) {
s_analog.reference_resistor = 1000.0f;
}
// 0 lead_r is a lie, but ok
// if (s_analog.lead_resistance == 0.0f) {
// s_analog.lead_resistance = 0.0f;
// }
}
/// Set and persist calibration constants
void app_temp_set_calib_persistent(float a, float b) {
void app_temp_set_calib(float a, float b) {
s_analog.cal_a = a;
s_analog.cal_b = b;
correct_invalid_calib();
@ -305,49 +177,6 @@ void app_temp_set_calib_persistent(float a, float b) {
}
}
void app_temp_set_calib_persistent_r(float lead, float reference) {
s_analog.lead_resistance = lead;
s_analog.reference_resistor = reference;
correct_invalid_calib();
EE_Status st = EE_WriteVariable32bits(EE_ADDR_LEAD_R, ((x32_t) { .f = lead }).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_REF_R, ((x32_t) { .f = reference }).u);
if (st == EE_CLEANUP_REQUIRED) {
EE_CleanUp();
} else if (st != EE_OK) {
PRINTF("EE write err %d!\r\n", st);
}
}
void app_temp_backup_calib() {
s_analog.saved_cal_a = s_analog.cal_a;
s_analog.saved_cal_b = s_analog.cal_b;
s_analog.saved_lead_resistance = s_analog.lead_resistance;
s_analog.saved_reference_resistor = s_analog.reference_resistor;
}
void app_temp_set_calib_temporary(float a, float b) {
s_analog.cal_a = a;
s_analog.cal_b = b;
}
void app_temp_set_calib_temporary_r(float l, float r) {
s_analog.lead_resistance = l;
s_analog.reference_resistor = r;
}
void app_temp_restore_calib() {
s_analog.cal_a = s_analog.saved_cal_a;
s_analog.cal_b = s_analog.saved_cal_b;
s_analog.lead_resistance = s_analog.saved_lead_resistance;
s_analog.reference_resistor = s_analog.saved_reference_resistor;
}
void app_analog_init()
{
// read calibration constants
@ -360,14 +189,6 @@ void app_analog_init()
s_analog.cal_b = ((x32_t) { .u = c }).f;
PRINTF("ADC calib b read from EE: %f\r\n", s_analog.cal_b);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_LEAD_R, &c)) {
s_analog.lead_resistance = ((x32_t) { .u = c }).f;
PRINTF("ADC calib R_LEAD read from EE: %f\r\n", s_analog.lead_resistance);
}
if (EE_OK == EE_ReadVariable32bits(EE_ADDR_REF_R, &c)) {
s_analog.reference_resistor = ((x32_t) { .u = c }).f;
PRINTF("ADC calib R_REF read from EE: %f\r\n", s_analog.reference_resistor);
}
correct_invalid_calib();
@ -396,19 +217,15 @@ void app_analog_init()
LL_TIM_EnableCounter(TIM1);
}
float val_to_c(float x)
float val_to_c(float val)
{
// val is the ratio
float pt100r = (x * s_analog.lead_resistance + x * s_analog.reference_resistor - s_analog.lead_resistance) / (1 - x);
// TODO use binary search.. lol
for (int i = 1; i < TSENSE_LOOKUP_LEN; i++) {
float cur = PT100_LOOKUP[i];
if (cur >= pt100r) {
float prev = PT100_LOOKUP[i - 1];
float cur = TSENSE_LOOKUP[i];
if (cur >= val) {
float prev = TSENSE_LOOKUP[i - 1];
float ratio = (pt100r - prev) / (cur - prev);
float ratio = (val - prev) / (cur - prev);
return TSENSE_T_MIN + ((float) i + ratio) * TSENSE_T_STEP;
}
}
@ -428,7 +245,7 @@ float c_to_val(float cf)
int upper = lower + 1;
float ratio = (cf - ((float)lower * TSENSE_T_STEP)) / 5.0f;
return PT100_LOOKUP[lower] + (PT100_LOOKUP[upper] - PT100_LOOKUP[lower]) * ratio;
return TSENSE_LOOKUP[lower] + (TSENSE_LOOKUP[upper] - TSENSE_LOOKUP[lower]) * ratio;
}
void app_temp_sample()
@ -495,10 +312,8 @@ void app_temp_sample()
}
float y = s_analog.cal_a * sum + s_analog.cal_b;
//float y = sum;
float actual_temp = val_to_c(y);
PRINTF("T Raw[%f] * A[%f] + B[%f]-> %f, temp %f°C\r\n", sum, s_analog.cal_a, s_analog.cal_b, y, actual_temp);
PRINTF("T raw %f %f -> comp %f, temp %f°C\r\n", sum, y, actual_temp);
s_analog.oven_temp = actual_temp;
s_analog.oven_temp_raw = sum;
@ -509,10 +324,8 @@ void app_temp_sample()
app_safety_pass_temp_normal();
}
if (s_analog.soc_temp >= 2.0 && s_analog.soc_temp <= 90.0) {
if (s_analog.soc_temp >= 2.0 && s_analog.soc_temp <= 80.0) {
app_safety_pass_soc_temp_ok();
} else {
PRINTF("SOC OVERHEAT!! %f\r\n", s_analog.soc_temp);
}
}

@ -10,16 +10,7 @@ void app_analog_init();
float val_to_c(float val);
float c_to_val(float c);
void app_temp_set_calib_persistent(float a, float b);
void app_temp_set_calib_persistent_r(float lead, float reference);
void app_temp_backup_calib();
void app_temp_set_calib_temporary(float a, float b);
void app_temp_set_calib_temporary_r(float lead, float reference);
void app_temp_get_calib(float *a, float *b, float *l, float *r);
void app_temp_restore_calib();
void app_temp_set_calib(float a, float b);
/**
* Update temperature measurement.

@ -6,20 +6,8 @@
#define TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H
enum EEAddresses {
// 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,
EE_ADDR_LEAD_R = 6,
EE_ADDR_REF_R = 7,
EE_ADDR_CAL_A = 1,
EE_ADDR_CAL_B = 2,
};
#endif //TOASTER_OVEN_BLUEPILL_EE_ADDRESSES_H

@ -66,7 +66,7 @@ const osThreadAttr_t mainTsk_attributes = {
};
/* Definitions for heaterTsk */
osThreadId_t heaterTskHandle;
uint32_t heaterTskBuffer[ 300 ];
uint32_t heaterTskBuffer[ 128 ];
osStaticThreadDef_t heaterTskControlBlock;
const osThreadAttr_t heaterTsk_attributes = {
.name = "heaterTsk",
@ -78,7 +78,7 @@ const osThreadAttr_t heaterTsk_attributes = {
};
/* Definitions for guiTsk */
osThreadId_t guiTskHandle;
uint32_t guiTskBuffer[ 300 ];
uint32_t guiTskBuffer[ 256 ];
osStaticThreadDef_t guiTskControlBlock;
const osThreadAttr_t guiTsk_attributes = {
.name = "guiTsk",

@ -26,8 +26,6 @@
/* USER CODE BEGIN Includes */
#include "app_temp.h"
#include "app_knob.h"
#include "app_heater.h"
#include <inttypes.h>
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@ -91,174 +89,20 @@ void NMI_Handler(void)
/* USER CODE END NonMaskableInt_IRQn 1 */
}
#define VERBOSE_HARDFAULT 1
#if VERBOSE_HARDFAULT
void __attribute__((used)) HardFault_DumpRegisters(const uint32_t *origStack, uint32_t lr_value)
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used. If the debugger won't show the
values of the variables, make them global my moving their declaration outside
of this function. */
volatile uint32_t stacked_r0;
volatile uint32_t stacked_r1;
volatile uint32_t stacked_r2;
volatile uint32_t stacked_r3;
volatile uint32_t stacked_r12;
volatile uint32_t stacked_lr; /* Link register. */
volatile uint32_t stacked_pc; /* Program counter. */
volatile uint32_t stacked_psr;/* Program status register. */
#if (__CORTEX_M >= 3)
uint32_t cfsr, hfsr, dfsr;
uint32_t bus_fault_address;
uint32_t memmanage_fault_address;
bus_fault_address = SCB->BFAR;
memmanage_fault_address = SCB->MMFAR;
cfsr = SCB->CFSR;
hfsr = SCB->HFSR;
dfsr = SCB->DFSR;
#endif
stacked_r0 = origStack[0];
stacked_r1 = origStack[1];
stacked_r2 = origStack[2];
stacked_r3 = origStack[3];
stacked_r12 = origStack[4];
stacked_lr = origStack[5];
stacked_pc = origStack[6];
stacked_psr = origStack[7];
app_heater_emergency_shutdown();
#define BS(reg, pos, str) (((reg)&(1<<(pos)))?(str" "):"")
#define REDPTR(val) (((val)&0xFF000000) != 0x08000000?"\033[31m":"\033[32m")
PRINTF("\r\n*** HARD FAULT ***\r\n\r\n");
PRINTF("- Stack frame:\r\n");
PRINTF(" R0 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r0);
PRINTF(" R1 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r1);
PRINTF(" R2 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r2);
PRINTF(" R3 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r3);
PRINTF(" R12 = \033[35m0x%"PRIX32"\033[m\r\n", stacked_r12);
PRINTF(" LR = %s0x%08"PRIX32"\033[m\r\n", REDPTR(stacked_lr), stacked_lr);
PRINTF(" PC = %s0x%08"PRIX32"\033[m\r\n", REDPTR(stacked_pc), stacked_pc);
PRINTF(" PSR = \033[36m0x%08"PRIX32"\033[m", stacked_psr);
uint32_t exc = stacked_psr & 0x3F;
PRINTF(" [ %s%s%s%s%s ]\r\n",
BS(stacked_psr, 31, "N"),
BS(stacked_psr, 30, "Z"),
BS(stacked_psr, 29, "C"),
BS(stacked_psr, 28, "V"),
//BS(stacked_psr, 24, "T"), - thumb, always ON
(exc==0)?"Thread":
(exc==2)?"NMI":
(exc==3)?"HardFault":
(exc==11)?"SVCall":
(exc==14)?"PendSV":
(exc==15)?"SysTick":
(exc>=16)?"IRQ":"Unknown"
);
#if (__CORTEX_M >= 3)
PRINTF("\r\n- FSR/FAR:\r\n");
PRINTF(" CFSR = \033[36m0x%08"PRIX32"\033[m\r\n", cfsr);
PRINTF(" UsageFault: \033[31;1m%s%s%s%s%s%s%s\033[m\r\n"
" BusFault: \033[31;1m%s%s%s%s%s%s%s%s\033[m\r\n"
" MemFault: \033[31;1m%s%s%s%s%s%s%s\033[m\r\n",
BS(cfsr, 0, "IAccViol"),
BS(cfsr, 1, "DAccViol"),
BS(cfsr, 3, "MUnstkErr"),
BS(cfsr, 4, "MStkErr"),
BS(cfsr, 5, "MLSPErr(FPU)"),
BS(cfsr, 7, "MMArValid"),
((cfsr&0xFF)?"":"\033[m- "),
BS(cfsr, 8, "IBusErr"),
BS(cfsr, 9, "PreciseErr"),
BS(cfsr, 10, "ImpreciseErr"),
BS(cfsr, 11, "UnstkErr"),
BS(cfsr, 12, "StkErr"),
BS(cfsr, 13, "LSPErr"),
BS(cfsr, 15, "BFArValid"),
((cfsr&0xFF00)?"":"\033[m- "),
BS(cfsr, 16, "UndefInstr"),
BS(cfsr, 17, "InvState"),
BS(cfsr, 18, "InvPC"),
BS(cfsr, 19, "NoCP"),
BS(cfsr, 24, "Unaligned"),
BS(cfsr, 25, "Div0"),
((cfsr&0xFFFF0000)?"":"\033[m- ")
);
PRINTF(" HFSR = \033[36m0x%08"PRIX32"\033[m", hfsr);
PRINTF(" [ %s%s%s]\r\n",
BS(hfsr, 31, "DebugEvt"),
BS(hfsr, 30, "Forced"),
BS(hfsr, 1, "VectTbl")
);
PRINTF(" DFSR = \033[36m0x%08"PRIX32"\033[m", dfsr);
PRINTF(" [ %s%s%s%s%s]\r\n",
BS(dfsr, 0, "Halted"),
BS(dfsr, 1, "Bkpt"),
BS(dfsr, 2, "DWtTrap"),
BS(dfsr, 3, "VCatch"),
BS(dfsr, 4, "External")
);
if (cfsr & 0x0080) PRINTF(" MMFAR = \033[33m0x%08"PRIX32"\033[m\r\n", memmanage_fault_address);
if (cfsr & 0x8000) PRINTF(" BFAR = \033[33m0x%08"PRIX32"\033[m\r\n", bus_fault_address);
PRINTF("\r\n- Misc\r\n");
PRINTF(" LR/EXC_RETURN= %s0x%08"PRIX32"\033[m\n", REDPTR(lr_value), lr_value);
#endif
while (1);
}
#endif
/**
* @brief This function handles Hard fault interrupt.
*/
void __attribute__((naked)) HardFault_Handler(void)
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
#if VERBOSE_HARDFAULT
// __asm volatile
// (
// " tst lr, #4 \n"
// " ite eq \n"
// " mrseq r0, msp \n"
// " mrsne r0, psp \n"
// " ldr r1, [r0, #24] \n"
// " mov r2, lr \n"
// " ldr r3, handler2_address_const \n"
// " bx r3 \n"
// " handler2_address_const: .word HardFault_DumpRegisters \n"
// );
//
__asm volatile( ".syntax unified\n"
"MOVS R0, #4 \n"
"MOV R1, LR \n"
"TST R0, R1 \n"
"BEQ _MSP \n"
"MRS R0, PSP \n"
"B HardFault_DumpRegisters \n"
"_MSP: \n"
"MRS R0, MSP \n"
"B HardFault_DumpRegisters \n"
".syntax divided\n") ;
#else
/* USER CODE BEGIN HardFault_IRQn 0 */
PUTS("HardFault_Handler\r\n");
app_emergency_stop();
PRINTF("*** HARD FAULT ***\r\n\r\n");
while (1);
#endif
/* USER CODE END HardFault_IRQn 0 */
while (1) {
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
/**

@ -29,10 +29,6 @@
#define my_malloc(len) pvPortMalloc((len))
#define my_free(p) vPortFree((p))
// Use a static buffer to avoid allocating for every printf!
#define S_PRINTF_BUF_LEN 200
static char s_printf_buf[S_PRINTF_BUF_LEN];
// Toggle features
#define size_t size_t /* normally: int, unsigned */
#undef HAVE_LONG_DOUBLE
@ -737,11 +733,9 @@ static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
// leading zeros in the fractional part
fzeropad = 0;
fzerocnt = max - 1;
if (fzerocnt > 0) {
while (fracpart < POW10(fzerocnt)) {
fzeropad++;
fzerocnt--;
}
while (fracpart < POW10(fzerocnt)) {
fzeropad++;
fzerocnt--;
}
do {
temp = fracpart;
@ -806,9 +800,8 @@ static void fmtfp(char *buffer, size_t *currlen, size_t maxlen,
zpadlen = 0;
}
while (fzeropad > 0) {
while (fzeropad-- > 0) {
dopr_outch(buffer, currlen, maxlen, '0');
fzeropad--;
}
while (fplace > 0) {
@ -899,18 +892,6 @@ int printf(const char *format, ...)
va_list ap;
int ret;
va_start(ap, format);
ret = vsnprintf(s_printf_buf, S_PRINTF_BUF_LEN, format, ap);
va_end(ap);
PUTS(s_printf_buf);
return ret;
#if 0
va_list ap;
int ret;
char *ptr = NULL;
va_start(ap, format);
@ -925,7 +906,6 @@ int printf(const char *format, ...)
my_free(ptr);
return ret;
#endif
}
int vprintf(const char *format, va_list ap)

@ -106,7 +106,5 @@ static const struct utf_glyph5x PROGMEM font57_extra[] = {
{.utf={.symbol="í"}, {{0x00, 0x44, 0x7d, 0x41, 0x00}}},
{.utf={.symbol="ž"}, {{0x44, 0x65, 0x56, 0x4d, 0x44}}},
{.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}}},
};

@ -935,14 +935,6 @@ const char *font_extras[] = {
"# #",
"# #",
" ####",
// 97 "a"
" xx",
" ",
" ### ",
" #",
" ####",
"# #",
" ####",
// »
" ",
"x x ",
@ -951,14 +943,6 @@ const char *font_extras[] = {
" x x ",
"x x ",
" ",
// 101 "e"
" x x ",
" x ",
" ### ",
"# #",
"#####",
"# ",
" ### ",
};
const char *font_extras_utf[] = {
@ -983,9 +967,7 @@ const char *font_extras_utf[] = {
"í",
"ž",
"ď",
"á",
"»",
"ě",
};
#include "fontedit_render.inc.c"

@ -53,8 +53,6 @@ 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/Gui/screen_calib_edit.c \
Core/Src/app_temp.c \
Core/Src/app_knob.c \
Core/Src/app_buzzer.c \
@ -263,4 +261,4 @@ analyze: $(BUILD_DIR)/$(TARGET).elf
python -m elf_size_analyze --rom $<
fonts:
make -C Lib/ufb fonts
make -C Lib/ufb fonts
Loading…
Cancel
Save