--- a/hello.c Thu Apr 03 18:49:02 2014 +0300
+++ b/hello.c Thu Apr 03 18:49:18 2014 +0300
@@ -1,22 +1,116 @@
#include <avr/io.h>
-#include <util/delay.h>
+#include "stdlib.h"
-#define false 0
-#define true 1
+#include <avr/interrupt.h>
-#define SBI(port, bit) do { port |= (1 << (bit)); } while (0)
-#define CBI(port, bit) do { port &= ~(1 << (bit)); } while (0)
+#define TIMER_FLAGS GPIOR0
+#define TIMER1_BUSY 1
+
+/*
+ * Setup timers.
+ */
+void timer_init (void)
+{
+ TCCR1A = (
+ // OC1A output pin disconnected
+ 0b00 << COM1A0
+ // OC1B output pin disconnected
+ | 0b00 << COM1B0
+ // no PWM
+ | 0b00 << WGM10
+ );
+ TCCR1B = (
+ // CTC mode
+ 0b01 << WGM12
+ );
+ TCCR1C = 0;
+}
+
+void timer1_start (short cycles)
+{
+ // count up from zero...
+ TCNT1 = 0;
+
+ // ...to the given number of timer cycles
+ OCR1A = cycles;
+
+ // start!
+ sbi(&TIMER_FLAGS, TIMER1_BUSY);
+ TIMSK1 = (
+ // OCA interrupt
+ 0b1 << OCIE1A // enable
+ );
+ TCCR1B = (
+ // WGM
+ 0b01 << WGM12 // CTC
+
+ // clocksource
+ | 0b101 << CS10 // 1024'th
+ );
+}
+
+static void timer1_stop ()
+{
+ // WGM: normal
+ // clocksource: stop
+ TCCR1B = 0;
+
+ cbi(&TIMER_FLAGS, TIMER1_BUSY);
+}
+
+ISR(TIMER1_COMPA_vect)
+{
+ timer1_stop();
+
+ // XXX: cpu will automatically wake up from sleep()
+}
+
+/*
+ * Sleep on timer1 interrupt.
+ */
+void timer_sleep (int cycles)
+{
+ // set timer
+ timer1_start(cycles);
+
+ // sleep
+ // TODO: PRR
+ SMCR = (
+ // idle sleep
+ (0b00 << SM0)
+
+ // enable sleep
+ | (0b1 << SE)
+ );
+
+ // sleep
+ while (tbi(&TIMER_FLAGS, TIMER1_BUSY)) {
+ __asm__ ( "sleep" :: );
+ }
+
+ // cleanup
+ SMCR = 0;
+}
int main (void)
{
+ timer_init();
+
// LED
- SBI(DDRB, DDB5);
+ sbi(&DDRB, DDB5);
+
+ sei();
+
+ // blink
+ short timeout = 1000;
+ short delta = 10;
while (true) {
- // flip
- PORTB ^= (1 << PORTB5);
+ // bitflip
+ xbi(&PORTB, PORTB5);
- // busyloop
- _delay_ms(1000);
+ timer_sleep(timeout);
+
+ timeout += delta;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stdlib.h Thu Apr 03 18:49:18 2014 +0300
@@ -0,0 +1,32 @@
+#include <util/delay.h>
+
+#define false 0
+#define true 1
+
+typedef volatile uint8_t ioport_t;
+
+static inline ioport_t tbi(ioport_t *port, int bit)
+{
+ return *port & (1 << bit);
+}
+
+static inline void sbi(ioport_t *port, int bit)
+{
+ *port |= (1 << bit);
+}
+
+static inline void cbi(ioport_t *port, int bit)
+{
+ *port &= ~(1 << bit);
+}
+
+static inline void xbi(ioport_t *port, int bit)
+{
+ *port ^= (1 << bit);
+}
+
+void delay_1s ()
+{
+ // busyloop
+ _delay_ms(1000);
+}