Compare commits

..

5 Commits

Author SHA256 Message Date
042d38b0f5 Merge pull request 'Disable CPU while Rear Light is not used' (#3) from feature/power-off into main
Reviewed-on: #3
2025-10-25 14:49:38 +02:00
7e8165e7a2 cleanup 2025-10-25 14:47:08 +02:00
e0781257a6 do power down 2025-10-25 14:30:43 +02:00
35c66787de cleanup 2025-10-25 14:18:03 +02:00
c9d30ef44e first interrupt wakeup 2025-10-25 14:15:08 +02:00
2 changed files with 55 additions and 10 deletions

View File

@ -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

63
main.c
View File

@ -8,8 +8,10 @@
#include <stdbool.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define BUTTON_PIN_MASK 0x01 // PA0 TODO: using RESET/UPDI pin
#define BUTTON_PIN_MASK 0x01 // PA0 used as RESET/UPDI pin
#define PA1_SET_MASK 0x02 ///< LED 12
#define PA2_SET_MASK 0x04 ///< LED 36
#define PA3_SET_MASK 0x08 ///< LED 78
@ -18,7 +20,9 @@
#define MAIN_LOOP_SLEEP 10U // Main loop delay in ms
#define BUTTON_LONG_PRESS_DURATION_MS 1000U // Long press threshold
#define BUTTON_IGNORE_DURATION_MS 1000U // Time button ignored 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
/** Convert milliseconds to system ticks */
#define MS_TO_TICKS(ms) ((ms) / MAIN_LOOP_SLEEP)
@ -33,6 +37,8 @@ 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
@ -66,19 +72,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
{
@ -149,6 +168,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)
*