From 0e5b6587a70ba8010155e41b2d18187534b12f801d04225065c08d7a8ea8eb0a Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 23:07:29 +0100 Subject: [PATCH] hw pwm is shit --- main.c | 93 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 37 deletions(-) diff --git a/main.c b/main.c index 00280c9..cdbcfec 100644 --- a/main.c +++ b/main.c @@ -44,11 +44,15 @@ volatile eMode eModeCurrent = ANIMATION_BLINK; // Forward declarations ISR(PORTA_PORT_vect); static void software_reset(void); + +void initPWM(void); +void setPWM_PA2(uint8_t duty); + static inline void leds_off(void); static inline void leds_on(void); static void battery_level_indicator(void); static bool handleSwitch(void); -static inline void toggleMode(void); +static inline void switchMode(void); void ledAnimationBlink(bool resetCounters); void ledAnimationGlow(void); void ledStaticFull(void); @@ -59,7 +63,8 @@ void ledStaticFull(void); int main(void) { // Configure LED pins as outputs - VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK | PA6_SET_MASK | PA7_SET_MASK); + VPORTA.DIR = (PA2_SET_MASK | PA3_SET_MASK | PA6_SET_MASK | PA7_SET_MASK); + initPWM(); // Configure PA0 as input with pull-up VPORTA.DIR &= ~BUTTON_PIN_MASK; // Input @@ -140,17 +145,42 @@ int main(void) /** * @brief Move to next mode */ -static inline void toggleMode(void) +static inline void switchMode(void) { eModeCurrent = (eModeCurrent + 1) % MAX_COUNT; } +void initPWM(void) +{ + // Configure PA2 as output + PORTA.DIRSET = PIN2_bm; + + // Remap TCA0 WO0 to alternative pin (PA2) + // Check datasheet for correct PORTMUX bit - this is typically: + PORTMUX.CTRLC = PORTMUX_TCA00_bm; // or similar bit to route WO0 to PA2 + + // TCA0 in normal mode (single slope PWM) + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + + // Set period for ~19.5kHz PWM (5MHz / 256 = ~19.5kHz) + TCA0.SINGLE.PER = 0xFF; + + // Start timer with DIV1 (no prescaler) + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + +void setPWM_PA2(uint8_t duty) +{ + TCA0.SINGLE.CMP0 = duty; +} + /** * @brief Turn off all controlled LEDs (PA1, PA2, PA3) */ static inline void leds_off(void) { - VPORTA.OUT &= (uint8_t) ~(PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK); + VPORTA.OUT &= (uint8_t) ~(PA1_SET_MASK | PA3_SET_MASK); + setPWM_PA2(0U); } /** @@ -158,7 +188,8 @@ static inline void leds_off(void) */ static inline void leds_on(void) { - VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK); + VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK); + setPWM_PA2(255U); } /** @@ -173,7 +204,8 @@ static void battery_level_indicator(void) /** * @brief Handle momentary switch input on PA0 * - * A long press toggles ::bLedEnabled. + * A long press toggles bLedEnabled. + * A short press swiches the mode. */ static bool handleSwitch(void) { @@ -196,7 +228,7 @@ static bool handleSwitch(void) if (pressTicks >= MS_TO_TICKS(BUTTON_SHORT_PRESS_DURATION_MS) && pressTicks < MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) { - toggleMode(); + switchMode(); } } @@ -320,7 +352,7 @@ void ledAnimationBlink(bool resetCounters) break; case 12: // LED 3–6 on, wait 50 ms - VPORTA.OUT |= PA2_SET_MASK; + setPWM_PA2(255U); if (counter >= T50) { counter = 0; @@ -338,7 +370,7 @@ void ledAnimationBlink(bool resetCounters) break; case 16: // LED 3–6 on, wait 50 ms - VPORTA.OUT |= PA2_SET_MASK; + setPWM_PA2(255U); if (counter >= T50) { counter = 0; @@ -364,7 +396,7 @@ void ledAnimationBlink(bool resetCounters) break; case 20: // special: all LEDs on for 250 ms - VPORTA.OUT |= (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK); + leds_on(); if (counter >= T250) { counter = 0; @@ -383,41 +415,28 @@ void ledStaticFull(void) } /** - * @brief Outer LEDs with glow animation + * @brief Inner LEDs with glow animation */ void ledAnimationGlow(void) { static uint8_t brightness = 0; static int8_t direction = 1; - static uint8_t pwm_counter = 0; - pwm_counter++; + // Update brightness level every call (10ms) + brightness += direction; - if (pwm_counter >= 100) + // Reverse direction at limits + if (brightness >= 100) { - pwm_counter = 0; - - // Update brightness level - brightness += direction; - - if (brightness >= 100) - { - brightness = 100; - direction = -1; - } - else if (brightness == 0) - { - direction = 1; - } + brightness = 100; + direction = -1; + } + else if (brightness == 0) + { + brightness = 0; + direction = 1; } - // Software PWM: compare pwm_counter with brightness - if (pwm_counter < brightness) - { - VPORTA.OUT |= (PA1_SET_MASK | PA3_SET_MASK); - } - else - { - VPORTA.OUT &= ~(PA1_SET_MASK | PA3_SET_MASK); - } + // Apply PWM brightness to LED 3-6 + setPWM_PA2(brightness * 255 / 100); // Scale 0-100 to 0-255 } \ No newline at end of file