diff --git a/README.md b/README.md index 7dc0b68..03e253f 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Hardware: FT232 USB-UART adapter connected to UPDI with a 4.7 kΩ resistor. ``` 4. Flash using pymcuprog: ```bash - pymcuprog -t uart -u /dev/ttyUSB0 -d attiny202 write -f build/main.hex + pymcuprog -t uart -u /dev/ttyUSB0 -d attiny202 erase && pymcuprog -t uart -u /dev/ttyUSB0 -d attiny202 write -f build/main.hex ``` ## Hardware Setup (FT232 → ATtiny202 UPDI) ```bash diff --git a/main.c b/main.c index efc9510..acf6c63 100644 --- a/main.c +++ b/main.c @@ -10,27 +10,33 @@ #include #include -#define BUTTON_PIN_MASK 0x01 // PA0 -#define PA1_SET_MASK 0x02 // LED 1–2 -#define PA2_SET_MASK 0x04 // LED 3–6 -#define PA3_SET_MASK 0x08 // LED 7–8 -#define PA6_SET_MASK 0x40 // Green LED -#define PA7_SET_MASK 0x80 // Red LED +#define BUTTON_PIN_MASK 0x01 // PA0 used as RESET/UPDI pin +#define PA1_SET_MASK 0x02 ///< LED 1–2 +#define PA2_SET_MASK 0x04 ///< LED 3–6 +#define PA3_SET_MASK 0x08 ///< LED 7–8 +#define PA6_SET_MASK 0x40 ///< Green LED pin +#define PA7_SET_MASK 0x80 ///< Red LED #define MAIN_LOOP_SLEEP 50U // Loop period in ms #define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold -#define BUTTON_IGNORE_DURATION_MS 1000U // Ignore after long press +#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 #define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP) -volatile bool bLedEnabled = false; +/** Global flags */ +volatile bool bLedEnabled = true; volatile bool bBtnPressed = false; +// Forward declarations +void blinkLed(bool resetCounters); static inline void leds_off(void); static inline void leds_on(void); static void battery_level_indicator(void); static void handleSwitch(void); -void blinkLed(bool resetCounters); +static void software_reset(void); +ISR(PORTA_PORT_vect); /* --- Timer init: Use RTC PIT for periodic wake-up --- */ void init_timer(void) @@ -86,19 +92,32 @@ int main(void) leds_off(); } - // Long press detected → show confirmation blink + // Long press detected --> show confirmation blink if (bLedEnabledOld != bLedEnabled) { bLedEnabledOld = bLedEnabled; - leds_off(); - _delay_ms(BUTTON_IGNORE_DURATION_MS / 10); - leds_on(); - _delay_ms(BUTTON_IGNORE_DURATION_MS / 10); - leds_off(); + for (uint8_t i = 0U; i < BUTTON_CONFIRMATION_BLINK_LOOPS; i++) + { + leds_off(); + _delay_ms(BUTTON_CONFIRMATION_BLINK_DURATION_MS); + leds_on(); + _delay_ms(BUTTON_CONFIRMATION_BLINK_DURATION_MS); + leds_off(); + } + + // Give time until button is released _delay_ms(BUTTON_IGNORE_DURATION_MS); - blinkLed(true); // reset blink state machine + // Activate the interrupt for PA0 + PORTA.PIN0CTRL = PORT_PULLUPEN_bm | PORT_ISC_FALLING_gc; + + set_sleep_mode(SLEEP_MODE_STANDBY); // Deepest sleep mode (standby) + sleep_enable(); // Enable sleep + + cli(); // Disable global interrupts + sei(); // Re-enable interrupts + sleep_cpu(); // MCU sleeps here } else { @@ -171,6 +190,32 @@ static void handleSwitch(void) prevPressed = pressed; } +/** + * @brief Perform software reset + */ +static void software_reset(void) +{ + CCP = CCP_IOREG_gc; // unlock protected registers + RSTCTRL.SWRR = 1; // trigger software reset + while (1) + ; // wait for reset +} + +/** + * @brief Interrupt service routine + */ +ISR(PORTA_PORT_vect) +{ + // Clear interrupt flags for PA0 + PORTA.INTFLAGS = BUTTON_PIN_MASK; + + if (!(VPORTA.IN & BUTTON_PIN_MASK)) // check PA0 low + { + // Turn off all LEDs + software_reset(); + } +} + /** * @brief LED blink state machine (bike rear light style) *