aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2026-02-06 16:46:28 +0530
committerAkshay Nair <phenax5@gmail.com>2026-02-07 17:53:19 +0530
commiteef689b2e209dcf84c149ee4866c2a007676dc71 (patch)
treec814443ad4b19bebe8396d645520ce3db50bc04b
parentd544925cf75a05b681cadfc11b7d8a2d98de6679 (diff)
downloaddaft-watch-eef689b2e209dcf84c149ee4866c2a007676dc71.tar.gz
daft-watch-eef689b2e209dcf84c149ee4866c2a007676dc71.zip
Fix timer interrupt priority + refactor
-rw-r--r--README.md2
-rw-r--r--flake.lock6
-rw-r--r--justfile2
-rw-r--r--src/display.c44
-rw-r--r--src/display.h8
-rw-r--r--src/main.c87
-rw-r--r--src/rtc.c36
-rw-r--r--src/rtc.h13
-rw-r--r--test/stubbed/avr/interrupt.h12
-rw-r--r--test/stubbed/avr/io.h12
10 files changed, 109 insertions, 113 deletions
diff --git a/README.md b/README.md
index 7b4423b..32c9a5e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
# Watch with attiny84a WIP
-RTC with attiny84a trying to re-create https://github.com/ingepnet/breadboardwatch
+Inspired by https://github.com/ingepnet/breadboardwatch
diff --git a/flake.lock b/flake.lock
index 90a6f4d..60da8a8 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1769461804,
- "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
+ "lastModified": 1770197578,
+ "narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
+ "rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2",
"type": "github"
},
"original": {
diff --git a/justfile b/justfile
index eec984d..224a293 100644
--- a/justfile
+++ b/justfile
@@ -8,7 +8,7 @@ AVR_LIBC := env("AVR_LIBC", "/usr/lib/avr")
F_CPU := "32768"
MCU := "attiny84a"
MCU_PART := "attiny84"
-SRCS := "./src/main.c ./src/display.c"
+SRCS := "src/main.c src/display.c src/rtc.c"
OUTDIR := "./out"
PROGRAMMER := "arduino"
UPLOAD_SPEED := "19200"
diff --git a/src/display.c b/src/display.c
index 5fccd50..8de5043 100644
--- a/src/display.c
+++ b/src/display.c
@@ -4,6 +4,7 @@
#include <util/delay.h>
#include "display.h"
+#include "rtc.h"
// "_gfedcba"
// Reversed because a-g is mapped to pa0-6. (pa7 is decimal)
@@ -13,20 +14,18 @@ const uint32_t digit_masks[] = {
0b00010010, 0b00000010, 0b01111000, 0b00000000, 0b00010000,
};
-void setup_display() {
- TIMSK1 = 0;
-
- // Set prescaler (Timer clock = F_CPU / 64)
+void display_setup() {
+ // Set prescaler CS01 + CS00 (F_CPU / 64) + CTC
// For 32768Hz -> 32768/64 = 512Hz
- TCCR1B = (1 << CS11) | (1 << CS10) | (1 << WGM12) | (1 << WGM13);
- TCCR1A = (1 << WGM11) | (1 << WGM10);
+ TCCR0B = (1 << CS01) | (1 << CS00) | (1 << WGM02);
+ TCCR0A = (1 << WGM01) | (1 << WGM00);
- TCNT1 = 0; // Start counting from 0
- OCR1A = 1; // 0-1 = 2 counts before timer interrupt (512/2 = 256Hz)
- OCR1B = 0;
+ TCNT0 = 0; // Start counting from 0
+ OCR0A = 1; // 0-1 = 2 counts before timer interrupt (512/2 = 256Hz)
+ OCR0B = 0;
- TIFR1 = (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1); // Clear interrupt flags
- TIMSK1 = (1 << OCIE1A); // Enable timer overflow interrupt
+ TIFR0 = (1 << OCF0A) | (1 << OCF0B) | (1 << TOV0); // Clear interrupt flags
+ TIMSK0 = (1 << OCIE0A); // Enable timer overflow interrupt
// Draw startup state
DDRA |= 0b11111111;
@@ -35,6 +34,19 @@ void setup_display() {
PORTB = (1 << PB2);
}
+volatile uint8_t current_digit = 0;
+
+// Render current digit
+void display_render(void) {
+ DDRA |= 0b11111111;
+ DDRB |= 0b11111111;
+
+ write_time(minutes, seconds, current_digit);
+
+ // Next digit
+ current_digit = (current_digit + 1) % 4;
+}
+
void write_digit(uint8_t digit) {
if (digit > 9 || digit < 0)
return;
@@ -47,25 +59,23 @@ void write_time(uint16_t hour, uint16_t minute, uint8_t mask) {
// unsigned short hour_digit1 = hour % 10;
// unsigned short hour_digit2 = (hour / 10) % 10;
- // _delay_ms(4);
// Reset digit control pins
PORTA &= ~(1 << PA7); // minute digit 1
PORTB &= ~(1 << PB2); // minute digit 2
- // _delay_ms(4);
// cli();
- if (mask & 0b0001 || mask & 0b0100) {
+ if (mask == 0 || mask == 2) {
#ifdef STUBBED
- printf(":: %d\n", minute_digit1);
+ printf(" %d\n", minute_digit1);
fflush(stdout);
#endif
write_digit(minute_digit1);
PORTA |= (1 << PA7);
}
- if (mask & 0b0010 || mask & 0b1000) {
+ if (mask == 1 || mask == 3) {
#ifdef STUBBED
- printf(":: %d\n", minute_digit2);
+ printf(":: %d", minute_digit2);
fflush(stdout);
#endif
write_digit(minute_digit2);
diff --git a/src/display.h b/src/display.h
index 167374a..34a065d 100644
--- a/src/display.h
+++ b/src/display.h
@@ -2,10 +2,14 @@
#define _LOADED_DISPLAY
#include <stdint.h>
-void setup_display();
+volatile extern uint8_t current_digit;
+
+void display_setup(void);
void write_digit(uint8_t digit);
void write_time(uint16_t hour, uint16_t minute, uint8_t digit_mask);
-#endif
+void display_render(void);
+
+#endif \ No newline at end of file
diff --git a/src/main.c b/src/main.c
index b3fa431..cf6f7a8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,10 +1,10 @@
#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h>
-#include <stdint.h>
#include <util/delay.h>
#include "display.h"
+#include "rtc.h"
// Config for attiny84a + external 32KHz crystal osc taken from
// https://github.com/ingepnet/breadboardwatch/blob/master/Makefile#L26
@@ -15,68 +15,13 @@ FUSES = {
.extended = 0xff,
};
-void set_all_pins_output(void) {
- DDRA |= 0b11111111;
- DDRB |= 0b11111111;
-}
-
-void setup_rtc() {
- // Set prescaler (Timer clock = F_CPU / 1024)
- // For 32768Hz -> 32768/1024 = 32Hz
- TCCR0B = (1 << CS02) | (1 << CS00) | (1 << WGM02);
- TCCR0A = (1 << WGM01) | (1 << WGM00);
-
- TCNT0 = 0; // Start counting from 0
- OCR0A = 31; // 0-31 = 32 counts before timer interrupt (1Hz)
- OCR0B = 0;
-
- // TIFR0 = (1 << TOV0); // Clear interrupt flags
- TIFR0 = (1 << OCF0A) | (1 << OCF0B) | (1 << TOV0); // Clear interrupt flags
- // TIMSK0 = (1 << TOIE0); // Enable timer overflow interrupt
- TIMSK0 = (1 << OCIE0A); // Enable timer overflow interrupt
-}
-
-volatile uint8_t seconds = 10;
-volatile uint8_t minutes = 0;
-volatile uint8_t hours = 0;
-// Clock
-ISR(TIM0_COMPA_vect, ISR_FLATTEN) {
- // if (true) {
- // OCR0A = 32;
- // } else if (true) {
- // OCR0A = 31;
- // } else {
- // OCR0A = 30;
- // }
-
- uint8_t s = seconds + 1;
- seconds = s % 60;
- if (s >= 60) {
- uint8_t m = minutes + 1;
- minutes = m % 60;
- if (m >= 60) {
- hours = (hours + 1) % 24;
- }
- }
-}
-
-volatile static uint8_t digit_mask = 0b0001;
// Display
-ISR(TIM1_COMPA_vect, ISR_FLATTEN) {
- set_all_pins_output();
- write_time(minutes, seconds, digit_mask);
- if (seconds % 2) {
- PORTA &= ~(1 << PA5);
- PORTB &= ~(1 << PB3);
- } else {
- PORTA |= (1 << PA5);
- PORTB |= (1 << PB3);
- }
+// timer 0 has lower priority than timer 1, so some ticks could get skipped due
+// to interrupt starvation
+ISR(TIM0_COMPA_vect, ISR_FLATTEN) { display_render(); }
- digit_mask = digit_mask << 1;
- if (digit_mask > 0b1000)
- digit_mask = 0b0001;
-}
+// RTC interrupt
+ISR(TIM1_COMPA_vect, ISR_FLATTEN) { rtc_increment(); }
#define IS_BUTTON_ON() ((PINA & (1 << PA0)) == 0)
#define ENABLE_BUTTON() (DDRA &= ~(1 << PA0))
@@ -84,28 +29,12 @@ ISR(TIM1_COMPA_vect, ISR_FLATTEN) {
int main(void) {
PRR = 0b0011; // Power reduction register. Shut down USI and ADC
- setup_rtc();
- setup_display();
+ display_setup();
+ rtc_setup();
sei();
- set_all_pins_output();
-
while (1) {
- // cli();
- // set_all_pins_output();
- // write_time(minutes, seconds, digit_mask);
- // if (seconds % 2) {
- // PORTA &= ~(1 << PA5);
- // PORTB &= ~(1 << PB3);
- // } else {
- // PORTA |= (1 << PA5);
- // PORTB |= (1 << PB3);
- // }
- // digit_mask = digit_mask << 1;
- // if (digit_mask > 0b1000)
- // digit_mask = 0b0001;
-
// ENABLE_BUTTON();
// if (IS_BUTTON_ON()) {
// cli();
diff --git a/src/rtc.c b/src/rtc.c
new file mode 100644
index 0000000..1ac50c3
--- /dev/null
+++ b/src/rtc.c
@@ -0,0 +1,36 @@
+#include <avr/interrupt.h>
+#include <avr/io.h>
+#include <stdint.h>
+#include <util/delay.h>
+
+#include "rtc.h"
+
+void rtc_setup(void) {
+ // Set prescaler CS12 + CS10 (F_CPU / 1024) + CTC
+ // For 32768Hz -> 32768/1024 = 32Hz
+ TCCR1B = (1 << CS12) | (1 << CS10) | (1 << WGM12) | (1 << WGM13);
+ TCCR1A = (1 << WGM11) | (1 << WGM10);
+
+ TCNT1 = 0; // Start counting from 0
+ OCR1A = 31; // 0-31 = 32 counts before timer interrupt (1Hz)
+ OCR1B = 0;
+
+ TIFR1 = (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1); // Clear interrupt flags
+ TIMSK1 = (1 << OCIE1A); // Enable timer overflow interrupt
+}
+
+volatile uint8_t seconds = 10;
+volatile uint8_t minutes = 0;
+volatile uint8_t hours = 0;
+
+void rtc_increment(void) {
+ uint8_t s = seconds + 1;
+ seconds = s % 60;
+ if (s >= 60) {
+ uint8_t m = minutes + 1;
+ minutes = m % 60;
+ if (m >= 60) {
+ hours = (hours + 1) % 24;
+ }
+ }
+}
diff --git a/src/rtc.h b/src/rtc.h
new file mode 100644
index 0000000..f3f8f9c
--- /dev/null
+++ b/src/rtc.h
@@ -0,0 +1,13 @@
+#ifndef _LOADED_RTC
+#define _LOADED_RTC
+#include <stdint.h>
+
+volatile extern uint8_t seconds;
+volatile extern uint8_t minutes;
+volatile extern uint8_t hours;
+
+void rtc_setup(void);
+
+void rtc_increment(void);
+
+#endif
diff --git a/test/stubbed/avr/interrupt.h b/test/stubbed/avr/interrupt.h
index bcab79c..19dfa36 100644
--- a/test/stubbed/avr/interrupt.h
+++ b/test/stubbed/avr/interrupt.h
@@ -1,4 +1,4 @@
-#define ISR(INTER) void generated_interrupt_##INTER()
+#define ISR(INTER, ...) void generated_interrupt_##INTER()
static void cli() {}
static void sei() {}
@@ -6,15 +6,15 @@ static void sei() {}
#define stub_run_timers() \
{ \
if (TCNT0 == OCR0A) { \
- generated_interrupt_TIM0_OVF_vect(); \
+ generated_interrupt_TIM0_COMPA_vect(); \
TCNT0 = 0; \
} else { \
TCNT0++; \
} \
- if (TCNT1L == OCR1AH) { \
- generated_interrupt_TIM1_OVF_vect(); \
- TCNT1L = 0; \
+ if (TCNT1 == OCR1A) { \
+ generated_interrupt_TIM1_COMPA_vect(); \
+ TCNT1 = 0; \
} else { \
- TCNT1L++; \
+ TCNT1++; \
} \
}
diff --git a/test/stubbed/avr/io.h b/test/stubbed/avr/io.h
index 8c1ee92..40cc460 100644
--- a/test/stubbed/avr/io.h
+++ b/test/stubbed/avr/io.h
@@ -36,10 +36,8 @@ static int TCCR1B = 0;
static int TCCR1A = 0;
static int TIMSK1 = 0;
static int TIFR1 = 0;
-static int OCR1AH = 0;
-static int OCR1BH = 0;
-static int OCR1AL = 0;
-static int OCR1BL = 0;
+static int OCR1A = 0;
+static int OCR1B = 0;
static int TCNT1 = 0;
static int TCNT1H = 0;
static int TCNT1L = 0;
@@ -63,4 +61,10 @@ static int TCNT1L = 0;
#define TOV1 0
#define OCF1A 0
#define OCF1B 0
+#define OCF0A 0
+#define OCF0B 0
+#define OCIE0A 0
+#define OCIE0B 0
+#define OCIE1A 0
+#define OCIE1B 0
#endif