simplified main loop with coroutines

This commit is contained in:
Alessandro Mauri 2026-06-01 19:24:25 +02:00
parent 9566b8da48
commit adabc92f1c

150
fw/main.c
View File

@ -33,6 +33,26 @@ static inline bool timer_expired(struct timer *t)
} }
// Button
struct button {
bool now, prev;
};
static inline void button_init(struct button *btn, bool pullup)
{
btn->now = btn->prev = pullup;
}
static inline void button_update(struct button *btn, bool state)
{
btn->prev = btn->now;
btn->now = state;
}
#define button_rising(btn) ((btn).now == true && (btn).prev == false)
#define button_falling(btn) ((btn).now == false && (btn).prev == true)
/* ------------------------------ Global State ------------------------------ */ /* ------------------------------ Global State ------------------------------ */
u8g2_t *u8g2; // Display state u8g2_t *u8g2; // Display state
int16_t encoder; // Rotary encoder counter int16_t encoder; // Rotary encoder counter
@ -45,7 +65,6 @@ uint16_t vbus_mv; // USB bus voltage in mV
uint16_t current_ma; // USB bus current to the heater in mA uint16_t current_ma; // USB bus current to the heater in mA
uint16_t power; // Current power provided to the heater uint16_t power; // Current power provided to the heater
uint16_t duty; // Current mosfet driver duty cycle (0-100%) uint16_t duty; // Current mosfet driver duty cycle (0-100%)
bool pwm = false; // PWM status (on-off)
bool enabled = false; // Power electronics enabled bool enabled = false; // Power electronics enabled
@ -493,10 +512,69 @@ static inline void update_tip_and_vcc(void)
} }
// coroutine to draw the "main" ui which draws the current tip temperature, power
// pwm state, etc.
coro_state_t cs_ui;
coroutine c_draw_main_ui(coro_state_t *state)
{
static struct timer t;
coro_begin(state);
for(;;) {
// Wait for the next frame, roughly 30 fps
timer_set(&t, 33);
coro_wait_until(state, timer_expired(&t));
// Draw UI
u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
draw_temp(u8g2, x_off+0, y_off+0, tip_temp_c, true);
u8g2_DrawStr(u8g2, x_off+32, y_off+6, "A:");
u8g2_DrawStr(u8g2, x_off+42, y_off+6, u16toa((current_ma+500)/1000));
u8g2_DrawStr(u8g2, x_off+60, y_off+6, "V:");
u8g2_DrawStr(u8g2, x_off+70, y_off+6, u16toa((vbus_mv+500)/1000));
uint8_t p = (power*100)/pd_profile.set_power;
uint8_t w = (uint16_t)(p*54)/100;
u8g2_DrawBox(u8g2, x_off+42, y_off+14, w, 5);
}
coro_end();
}
// coroutine to update the tip temperature, vcc and compute the new pid value
// this has to be called periodically but only with pwm disabled
coro_state_t cs_duty;
coroutine c_update_duty(coro_state_t *state)
{
static struct timer t;
coro_begin(state);
for(;;) {
timer_set(&t, 50);
coro_wait_until(state, timer_expired(&t));
pwm_set(0);
Delay_Ms(TURN_OFF_DELAY);
update_tip_and_vcc();
if (enabled) {
duty = pid((int16_t)pd_profile.set_temp - tip_temp_c, pd_profile.max_duty);
} else {
duty = 0;
}
}
coro_end();
}
__attribute__((noreturn)) int main(void) __attribute__((noreturn)) int main(void)
{ {
setup(); setup();
coro_init(&cs_ui);
coro_init(&cs_duty);
u8g2_ClearBuffer(u8g2); u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr); u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "Negotiating..."); u8g2_DrawStr(u8g2, x_off+0, y_off+7, "Negotiating...");
@ -539,33 +617,21 @@ __attribute__((noreturn)) int main(void)
STATE_MENU, STATE_MENU,
STATE_HEATING, STATE_HEATING,
} state = STATE_MENU; } state = STATE_MENU;
/* ============================== Main Loop =============================== */
struct button btn;
button_init(&btn, true);
for (;;) { for (;;) {
u32 start = funSysTick32(); button_update(&btn, funDigitalRead(PIN_BTN));
u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
static uint8_t count = 0; // Loop cycles with PWM on
static s32 elapsed = 0;
static bool prev_btn = true;
bool btn = funDigitalRead(PIN_BTN);
if (has_pd) {
update_power_and_temperature(); update_power_and_temperature();
// Update the tip temperature only when the PWM is not running c_update_duty(&cs_duty);
if (!pwm || !enabled) {
Delay_Ms(TURN_OFF_DELAY);
update_tip_and_vcc();
if (enabled) {
duty = pid((int16_t)pd_profile.set_temp - tip_temp_c, pd_profile.max_duty);
} else {
duty = 0;
}
}
switch (state) { switch (state) {
case STATE_MENU: case STATE_MENU:
u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TEMP:"); u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TEMP:");
u8g2_DrawStr(u8g2, x_off+25, y_off+7, u8g2_u16toa(pd_profile.set_temp, 4)); u8g2_DrawStr(u8g2, x_off+25, y_off+7, u8g2_u16toa(pd_profile.set_temp, 4));
@ -576,53 +642,31 @@ __attribute__((noreturn)) int main(void)
if (pd_profile.set_temp > MAX_TIP_SET_TEMP) pd_profile.set_temp = MAX_TIP_SET_TEMP; if (pd_profile.set_temp > MAX_TIP_SET_TEMP) pd_profile.set_temp = MAX_TIP_SET_TEMP;
} }
if (btn == 0 && prev_btn == 1) { if (button_falling(btn)) {
state = STATE_HEATING; state = STATE_HEATING;
enabled = false; enabled = false;
} }
break; break;
case STATE_HEATING: case STATE_HEATING:
// Draw UI c_draw_main_ui(&cs_ui);
draw_temp(u8g2, x_off+0, y_off+0, tip_temp_c, true);
u8g2_DrawStr(u8g2, x_off+32, y_off+6, "A:");
u8g2_DrawStr(u8g2, x_off+42, y_off+6, u16toa((current_ma+500)/1000));
u8g2_DrawStr(u8g2, x_off+60, y_off+6, "V:");
u8g2_DrawStr(u8g2, x_off+70, y_off+6, u16toa((vbus_mv+500)/1000));
uint8_t p = (power*100)/pd_profile.set_power;
uint8_t w = (uint16_t)(p*54)/100;
u8g2_DrawBox(u8g2, x_off+42, y_off+14, w, 5);
if (enabled) { if (enabled) {
funDigitalWrite(PIN_12V, 1); funDigitalWrite(PIN_12V, 1);
if (count > CYCLES_PER_MEASURE) {
pwm = false;
count = 0;
} else {
pwm = true;
count++;
}
// Safety logic // Safety logic
if (current_ma > pd_profile.max_current + pd_profile.max_current/10) { if (current_ma > pd_profile.max_current + pd_profile.max_current/10) {
pwm = false; enabled = false;
} }
if (temp_c > MAX_BOARD_TEMP) { if (temp_c > MAX_BOARD_TEMP) {
enabled = false; enabled = false;
pwm = false;
} }
if (tip_temp_c > MAX_TIP_TEMP) { if (tip_temp_c > MAX_TIP_TEMP) {
enabled = false; enabled = false;
pwm = false;
} }
if (pwm) {
const uint16_t tim_max = FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1; const uint16_t tim_max = FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1;
pwm_set(((u32)duty*tim_max)/100); pwm_set(((u32)duty*tim_max)/100);
u8g2_DrawBox(u8g2, x_off+92, y_off+0, 4, 4); u8g2_DrawBox(u8g2, x_off+92, y_off+0, 4, 4);
} else {
pwm_set(0);
}
} else { } else {
funDigitalWrite(PIN_12V, 0); funDigitalWrite(PIN_12V, 0);
} }
@ -635,7 +679,7 @@ __attribute__((noreturn)) int main(void)
} }
// Check button to toggle enable // Check button to toggle enable
if (btn == 0 && prev_btn == 1) { if (button_falling(btn)) {
enabled = !enabled; enabled = !enabled;
if (enabled) { if (enabled) {
pwm_on(); pwm_on();
@ -645,18 +689,6 @@ __attribute__((noreturn)) int main(void)
} }
break; break;
} }
} else {
// No PD capability, just display a message
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "NO PD");
}
u8g2_SendBuffer(u8g2); u8g2_SendBuffer(u8g2);
prev_btn = btn;
elapsed = funSysTick32() - start;
if (elapsed > 0 && elapsed < Ticks_from_Ms(FRAME_TIME_MS)) {
DelaySysTick(Ticks_from_Ms(FRAME_TIME_MS) - elapsed);
}
} }
} }