From 4ffb554d439e553c1b2bb9e2c1b812979bdf6937 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Sun, 26 Apr 2026 22:11:19 +0200 Subject: [PATCH] pwm generation and tip driving --- fw/main.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 107 insertions(+), 13 deletions(-) diff --git a/fw/main.c b/fw/main.c index dfcaddd..f70b903 100644 --- a/fw/main.c +++ b/fw/main.c @@ -31,6 +31,8 @@ #define FRAME_TIME_MS 41 // roughly 24 fps +#define PWM_FREQ_HZ 150000 + // constants // LUT for converting NTC readings to degrees kelvin // Nominal: 1kOhm, Beta: 3380, Step: 64 @@ -279,6 +281,68 @@ static inline bool adc_injection_conversion() { return true; } +// mask for the CCxP bits +// when set PWM outputs are held HIGH by default and pulled LOW +// when zero PWM outputs are held LOW by default and pulled HIGH +// #define TIM3_DEFAULT 0xff +#define TIM3_DEFAULT 0x00 +static inline void setup_pwm(void) +{ + // Enable TIM3 clock + RCC->APB1PCENR |= RCC_APB1Periph_TIM3; + + // Since TIM3 is enabled with TIM3->SMCFGR.SMS = 0b000 (default value) the + // clock source is the internal clock + // The internal clock goes through the HBB prescaler RCC->CFGR0.HPRE which + // by default is disabled + + // Reset TIM3 to init all regs + RCC->APB1PRSTR |= RCC_APB1Periph_TIM3; + RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM3; + + // set TIM3 clock prescaler divider + TIM3->PSC = 0x0000; // no prescaler + // set PWM total cycle width + static_assert((FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1) < 0xffff, "PWM_FREQ_HZ too low for TIM3"); + TIM3->ATRLR = FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1; + + // for channel 1 let CCxS stay 00 (output), set OC1M to 110 (PWM 1) + // enabling preload (OC1PE) causes the new pulse width in compare capture + // register only to come into effect when UG bit in SWEVGR is set + // (= initiate update) (auto-clears) + TIM3->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1 | TIM_OC1PE; + + // Enable channel 1 output (PA6) + TIM3->CCER |= TIM_CC1E | ( TIM_CC1P & TIM3_DEFAULT ); + + // CTLR1: default is up, events generated, edge align + // enable auto-reload of preload + TIM3->CTLR1 |= TIM_ARPE; +} + + +static inline void pwm_on(void) +{ + // initialize counter + TIM3->SWEVGR |= TIM_UG; + // Enable TIM3 + TIM3->CTLR1 |= TIM_CEN; +} + + +static inline void pwm_off(void) +{ + // Disable TIM3 + TIM3->CTLR1 &= ~TIM_CEN; + TIM3->CH1CVR = 0; +} + + +static inline void pwm_set(uint16_t pulse_width) +{ + TIM3->CH1CVR = pulse_width; +} + __attribute__((noreturn)) int main(void) { @@ -303,7 +367,7 @@ __attribute__((noreturn)) int main(void) funPinMode(PIN_12V, GPIO_CFGLR_OUT_10Mhz_PP); funDigitalWrite(PIN_12V, 0); - funPinMode(PIN_HEATER, GPIO_CFGLR_OUT_10Mhz_PP); + funPinMode(PIN_HEATER, GPIO_CFGLR_OUT_10Mhz_AF_PP); funDigitalWrite(PIN_HEATER, 0); funPinMode(PIN_DISP_RST, GPIO_CFGLR_OUT_10Mhz_PP); funDigitalWrite(PIN_DISP_RST, 1); // start with display disabled @@ -314,6 +378,9 @@ __attribute__((noreturn)) int main(void) funDigitalWrite(PIN_ENC_B, 1); // specify pull-up funPinMode(PIN_BTN, GPIO_CFGLR_IN_FLOAT); + setup_pwm(); + pwm_off(); + setup_i2c(); // Configure the IO as an interrupt. @@ -392,6 +459,11 @@ __attribute__((noreturn)) int main(void) } } + if (idx_9v >= 0) { + USBPD_SelectPDO(idx_9v, 0); + Delay_Ms(200); + } + for (;;) { static uint16_t tip_mv, vbus_mv, current_ma; static int16_t temp_k; @@ -408,6 +480,20 @@ __attribute__((noreturn)) int main(void) tip_mv = U16_FP_EMA_K4(tip_mv, (u32)(injection_results[0]*VCC_MV)/4096); } + static bool pwm = false; + if (funDigitalRead(PIN_BTN) == 0) { + if (!pwm) { + funDigitalWrite(PIN_12V, 1); + pwm_on(); + pwm = true; + pwm_set(100); + } + } else { + funDigitalWrite(PIN_12V, 0); + pwm_off(); + pwm = false; + } + u8g2_ClearBuffer(u8g2); u8g2_SetBitmapMode(u8g2, 1); u8g2_SetFontMode(u8g2, 1); @@ -415,32 +501,40 @@ __attribute__((noreturn)) int main(void) #define x_off 0 #define y_off 8 static bool mode = true; - if (mode) { +// if (mode) { u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TIP:"); u8g2_DrawStr(u8g2, x_off+20, y_off+7, u8x8_u16toa(tip_mv, 4)); u8g2_DrawStr(u8g2, x_off+0, y_off+15, "VBUS:"); u8g2_DrawStr(u8g2, x_off+25, y_off+15, u8x8_u16toa(vbus_mv, 4)); u8g2_DrawStr(u8g2, x_off+51, y_off+7, "TEMP:"); u8g2_DrawStr(u8g2, x_off+75, y_off+7, u8x8_u16toa(temp_k, 2)); - u8g2_DrawStr(u8g2, x_off+51, y_off+15, "V:"); - u8g2_DrawStr(u8g2, x_off+60, y_off+15, u8x8_u16toa(max_v, 2)); - } else { - static int16_t ax, ay, az; - sc7a20_get_readings(&ax, &ay, &az); - u8g2_DrawStr(u8g2, x_off+0, y_off+7, ax > 0 ? "AX:+" : "AX:-"); - u8g2_DrawStr(u8g2, x_off+20, y_off+7, u8x8_u16toa(ax > 0 ? ax : -ax, 5)); - u8g2_DrawStr(u8g2, x_off+0, y_off+15, ay > 0 ? "AY:+" : "AY:-"); - u8g2_DrawStr(u8g2, x_off+20, y_off+15, u8x8_u16toa(ay > 0 ? ay : -ay, 5)); - u8g2_DrawStr(u8g2, x_off+50, y_off+7, az > 0 ? "AZ:+" : "AZ:-"); - u8g2_DrawStr(u8g2, x_off+70, y_off+7, u8x8_u16toa(az > 0 ? az : -az, 5)); + //u8g2_DrawStr(u8g2, x_off+51, y_off+15, "V:"); + //u8g2_DrawStr(u8g2, x_off+60, y_off+15, u8x8_u16toa(max_v, 2)); + u8g2_DrawStr(u8g2, x_off+50, y_off+15, "CURR:"); + u8g2_DrawStr(u8g2, x_off+75, y_off+15, u8x8_u16toa(current_ma, 4)); +// } else { +// static int16_t ax, ay, az; +// sc7a20_get_readings(&ax, &ay, &az); +// u8g2_DrawStr(u8g2, x_off+0, y_off+7, ax > 0 ? "AX:+" : "AX:-"); +// u8g2_DrawStr(u8g2, x_off+20, y_off+7, u8x8_u16toa(ax > 0 ? ax : -ax, 5)); +// u8g2_DrawStr(u8g2, x_off+0, y_off+15, ay > 0 ? "AY:+" : "AY:-"); +// u8g2_DrawStr(u8g2, x_off+20, y_off+15, u8x8_u16toa(ay > 0 ? ay : -ay, 5)); +// u8g2_DrawStr(u8g2, x_off+50, y_off+7, az > 0 ? "AZ:+" : "AZ:-"); +// u8g2_DrawStr(u8g2, x_off+70, y_off+7, u8x8_u16toa(az > 0 ? az : -az, 5)); +// } + + if (pwm) { + u8g2_DrawBox(u8g2, x_off+92, y_off+0, 4, 4); } u8g2_SendBuffer(u8g2); +/* if (idx_9v != -1 && funDigitalRead(PIN_BTN) == 0) { USBPD_SelectPDO(idx_9v, 0); Delay_Ms(200); } +*/ if (encoder != 0) { mode = !mode; encoder = 0;