From a66a3ce2dc35b734f799068dfd65284574bfa0baefeb569390820053b3d52f19 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 22:01:10 +0100 Subject: [PATCH 1/8] modes --- main.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/main.c b/main.c index b9438c9..04652e2 100644 --- a/main.c +++ b/main.c @@ -20,6 +20,7 @@ #define MAIN_LOOP_SLEEP 10U // Main loop delay in ms #define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold +#define BUTTON_SHORT_PRESS_DURATION_MS 100U // Short press threshold #define BUTTON_IGNORE_DURATION_MS 2000U // Time button ignored after long press #define BUTTON_CONFIRMATION_BLINK_LOOPS 10U // Blink animation for confirmation #define BUTTON_CONFIRMATION_BLINK_DURATION_MS 50U @@ -27,11 +28,21 @@ /** Convert milliseconds to system ticks */ #define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP) +typedef enum _Mode +{ + ANIMATION, + STATIC_GLOW, + STATIC_FULL, + MAX_COUNT, +} eMode; + /** Global flags */ volatile bool bLedEnabled = true; -volatile bool bBtnPressed = false; +volatile bool bBtnLongPressed = false; +volatile eMode eModeCurrent = ANIMATION; // Forward declarations +static inline void toggleMode(void); void blinkLed(bool resetCounters); static inline void leds_off(void); static inline void leds_on(void); @@ -57,13 +68,14 @@ int main(void) battery_level_indicator(); // TODO: Implement bool bLedEnabledOld = bLedEnabled; + eModeCurrent = ANIMATION; while (true) { handleSwitch(); // Check switch state // Light LEDs while button is pressed - if (bBtnPressed) + if (bBtnLongPressed) { leds_on(); } @@ -101,9 +113,22 @@ int main(void) } else { - if (bLedEnabled && !bBtnPressed) + if (bLedEnabled && !bBtnLongPressed) { - blinkLed(false); // run normal blink + switch (eModeCurrent) + { + case ANIMATION: + blinkLed(false); // run normal blink + break; + case STATIC_GLOW: + blinkLed(false); // run normal blink + break; + case STATIC_FULL: + blinkLed(false); // run normal blink + break; + default: + break; + } } } @@ -111,6 +136,14 @@ int main(void) } } +/** + * @brief Move to next mode + */ +static inline void toggleMode(void) +{ + eModeCurrent = (eModeCurrent + 1) % MAX_COUNT; +} + /** * @brief Turn off all controlled LEDs (PA1, PA2, PA3) */ @@ -150,16 +183,21 @@ static void handleSwitch(void) if (pressed) { - bBtnPressed = true; + bBtnLongPressed = true; if (pressTicks < 0xFFFF) pressTicks++; // Prevent overflow } else { - bBtnPressed = false; + bBtnLongPressed = false; pressTicks = 0; } + if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_SHORT_PRESS_DURATION_MS)) + { + toggleMode(); + } + if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) { bLedEnabled = !bLedEnabled; // Toggle LED blinking -- 2.50.1 From a13381603b5ca56ed275314ea60b7cdddebd040897d20b03ae0d7c5e5fb1c94e Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 22:16:45 +0100 Subject: [PATCH 2/8] static mode and broken glow animation --- main.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/main.c b/main.c index 04652e2..55d8613 100644 --- a/main.c +++ b/main.c @@ -20,7 +20,7 @@ #define MAIN_LOOP_SLEEP 10U // Main loop delay in ms #define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold -#define BUTTON_SHORT_PRESS_DURATION_MS 100U // Short press threshold +#define BUTTON_SHORT_PRESS_DURATION_MS 50U // Short press threshold #define BUTTON_IGNORE_DURATION_MS 2000U // Time button ignored after long press #define BUTTON_CONFIRMATION_BLINK_LOOPS 10U // Blink animation for confirmation #define BUTTON_CONFIRMATION_BLINK_DURATION_MS 50U @@ -30,8 +30,8 @@ typedef enum _Mode { - ANIMATION, - STATIC_GLOW, + ANIMATION_BLINK, + ANIMATION_GLOW, STATIC_FULL, MAX_COUNT, } eMode; @@ -39,11 +39,13 @@ typedef enum _Mode /** Global flags */ volatile bool bLedEnabled = true; volatile bool bBtnLongPressed = false; -volatile eMode eModeCurrent = ANIMATION; +volatile eMode eModeCurrent = ANIMATION_BLINK; // Forward declarations static inline void toggleMode(void); -void blinkLed(bool resetCounters); +void ledAnimationBlink(bool resetCounters); +void ledAnimationGlow(void); +void ledStaticFull(void); static inline void leds_off(void); static inline void leds_on(void); static void battery_level_indicator(void); @@ -68,7 +70,7 @@ int main(void) battery_level_indicator(); // TODO: Implement bool bLedEnabledOld = bLedEnabled; - eModeCurrent = ANIMATION; + eModeCurrent = ANIMATION_BLINK; while (true) { @@ -117,14 +119,14 @@ int main(void) { switch (eModeCurrent) { - case ANIMATION: - blinkLed(false); // run normal blink + case ANIMATION_BLINK: + ledAnimationBlink(false); // run normal blink break; - case STATIC_GLOW: - blinkLed(false); // run normal blink + case ANIMATION_GLOW: + ledAnimationGlow(); break; case STATIC_FULL: - blinkLed(false); // run normal blink + ledStaticFull(); break; default: break; @@ -247,7 +249,7 @@ ISR(PORTA_PORT_vect) * 18: all off, wait 250 ms → restart * Special: every 3rd cycle, all LEDs ON for 250 ms */ -void blinkLed(bool resetCounters) +void ledAnimationBlink(bool resetCounters) { const uint8_t T50 = MS_TO_TICKS(50); const uint8_t T100 = MS_TO_TICKS(100); @@ -367,3 +369,51 @@ void blinkLed(bool resetCounters) break; } } + +/** + * @brief All LEDs with static full power + */ +void ledStaticFull(void) +{ + leds_on(); +} + +/** + * @brief Outer 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++; + + if (pwm_counter >= 100) + { + pwm_counter = 0; + + // Update brightness level + brightness += direction; + + if (brightness >= 100) + { + brightness = 100; + direction = -1; + } + else if (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); + } +} \ No newline at end of file -- 2.50.1 From 55426b5f2dc59221147fb10159f65ab144b105ece580aeb66bd12f6c060bb215 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 22:27:49 +0100 Subject: [PATCH 3/8] check mode change only on btn release --- main.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/main.c b/main.c index 55d8613..8726cbc 100644 --- a/main.c +++ b/main.c @@ -42,16 +42,16 @@ volatile bool bBtnLongPressed = false; volatile eMode eModeCurrent = ANIMATION_BLINK; // Forward declarations +ISR(PORTA_PORT_vect); +static void software_reset(void); +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); void ledAnimationBlink(bool resetCounters); void ledAnimationGlow(void); void ledStaticFull(void); -static inline void leds_off(void); -static inline void leds_on(void); -static void battery_level_indicator(void); -static void handleSwitch(void); -static void software_reset(void); -ISR(PORTA_PORT_vect); /** * @brief Main entry point @@ -74,7 +74,7 @@ int main(void) while (true) { - handleSwitch(); // Check switch state + bBtnLongPressed = handleSwitch(); // Check switch state // Light LEDs while button is pressed if (bBtnLongPressed) @@ -176,7 +176,7 @@ static void battery_level_indicator(void) * * A long press toggles ::bLedEnabled. */ -static void handleSwitch(void) +static bool handleSwitch(void) { static uint16_t pressTicks = 0; ///< Press duration counter static bool prevPressed = false; ///< Previous button state @@ -185,27 +185,32 @@ static void handleSwitch(void) if (pressed) { - bBtnLongPressed = true; if (pressTicks < 0xFFFF) pressTicks++; // Prevent overflow } else { - bBtnLongPressed = false; + // Button released + if (prevPressed) + { + // Check if it was a short press (not a long press) + if (pressTicks >= MS_TO_TICKS(BUTTON_SHORT_PRESS_DURATION_MS) && + pressTicks < MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) + { + toggleMode(); + } + } + pressTicks = 0; } - if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_SHORT_PRESS_DURATION_MS)) - { - toggleMode(); - } - - if (prevPressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) + if (pressed && pressTicks >= MS_TO_TICKS(BUTTON_LONG_PRESS_DURATION_MS)) { bLedEnabled = !bLedEnabled; // Toggle LED blinking } prevPressed = pressed; + return pressed; } /** -- 2.50.1 From f300ce238618e2f618915958b2ae51020dbeaa19ad45fc523875c6e264da1880 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 22:35:54 +0100 Subject: [PATCH 4/8] cleanup --- main.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/main.c b/main.c index 8726cbc..00280c9 100644 --- a/main.c +++ b/main.c @@ -38,7 +38,7 @@ typedef enum _Mode /** Global flags */ volatile bool bLedEnabled = true; -volatile bool bBtnLongPressed = false; +volatile bool bBtnPressed = false; volatile eMode eModeCurrent = ANIMATION_BLINK; // Forward declarations @@ -65,19 +65,18 @@ int main(void) VPORTA.DIR &= ~BUTTON_PIN_MASK; // Input PORTA.PIN0CTRL = PORT_PULLUPEN_bm; // Pull-up enabled - // Ensure all LEDs off at startup - leds_off(); + leds_off(); // Ensure all LEDs off at startup battery_level_indicator(); // TODO: Implement bool bLedEnabledOld = bLedEnabled; - eModeCurrent = ANIMATION_BLINK; + eModeCurrent = ANIMATION_BLINK; // Set the mode to start with while (true) { - bBtnLongPressed = handleSwitch(); // Check switch state + bBtnPressed = handleSwitch(); // Check switch state // Light LEDs while button is pressed - if (bBtnLongPressed) + if (bBtnPressed) { leds_on(); } @@ -115,7 +114,7 @@ int main(void) } else { - if (bLedEnabled && !bBtnLongPressed) + if (bLedEnabled && !bBtnPressed) { switch (eModeCurrent) { -- 2.50.1 From 0e5b6587a70ba8010155e41b2d18187534b12f801d04225065c08d7a8ea8eb0a Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 23:07:29 +0100 Subject: [PATCH 5/8] 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 -- 2.50.1 From 256a77b3fafca7ee8925c3718af093c5b6c27a2dea20b756d99110a71101b3ce Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 23:27:42 +0100 Subject: [PATCH 6/8] get hw pwm running --- main.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/main.c b/main.c index cdbcfec..285b974 100644 --- a/main.c +++ b/main.c @@ -63,7 +63,7 @@ void ledStaticFull(void); int main(void) { // Configure LED pins as outputs - VPORTA.DIR = (PA2_SET_MASK | PA3_SET_MASK | PA6_SET_MASK | PA7_SET_MASK); + VPORTA.DIR = (PA1_SET_MASK | PA2_SET_MASK | PA3_SET_MASK | PA6_SET_MASK | PA7_SET_MASK); initPWM(); // Configure PA0 as input with pull-up @@ -152,15 +152,10 @@ static inline void switchMode(void) 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 + // No PORTMUX needed - PA2 is WO2 by default // TCA0 in normal mode (single slope PWM) - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP2EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; // Set period for ~19.5kHz PWM (5MHz / 256 = ~19.5kHz) TCA0.SINGLE.PER = 0xFF; @@ -171,7 +166,7 @@ void initPWM(void) void setPWM_PA2(uint8_t duty) { - TCA0.SINGLE.CMP0 = duty; + TCA0.SINGLE.CMP2 = duty; } /** -- 2.50.1 From ca5a36449ae26e20fe2ef12c754056c307fd58b00aa34566eefe51462bb93124 Mon Sep 17 00:00:00 2001 From: localhorst Date: Sat, 8 Nov 2025 23:35:19 +0100 Subject: [PATCH 7/8] cleanup --- main.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index 285b974..41e15f0 100644 --- a/main.c +++ b/main.c @@ -150,6 +150,9 @@ static inline void switchMode(void) eModeCurrent = (eModeCurrent + 1) % MAX_COUNT; } +/** + * @brief Init PWM for PA2 + */ void initPWM(void) { // No PORTMUX needed - PA2 is WO2 by default @@ -164,6 +167,9 @@ void initPWM(void) TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; } +/** + * @brief Set PWM duty cycle for PA2 + */ void setPWM_PA2(uint8_t duty) { TCA0.SINGLE.CMP2 = duty; @@ -421,14 +427,14 @@ void ledAnimationGlow(void) brightness += direction; // Reverse direction at limits - if (brightness >= 100) + if (brightness >= 100U) { - brightness = 100; + brightness = 100U; direction = -1; } - else if (brightness == 0) + else if (brightness == 10U) { - brightness = 0; + brightness = 10U; direction = 1; } -- 2.50.1 From e2cdb7470a3e605e5359064b5e09a44e54a74944a1a32105bff78e6a16324ffc Mon Sep 17 00:00:00 2001 From: localhorst Date: Sun, 9 Nov 2025 13:54:26 +0100 Subject: [PATCH 8/8] format --- main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.c b/main.c index 41e15f0..e77d1f8 100644 --- a/main.c +++ b/main.c @@ -44,10 +44,8 @@ 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); -- 2.50.1