# HG changeset patch # User Tero Marttila # Date 1396540158 -10800 # Node ID f01fb659e54d386e0dd3598ebe04ea96a26e429d # Parent 50dc2f4d90fd07e5e96e66a407146f6a51ca62b3 hello: timer-based sleeps diff -r 50dc2f4d90fd -r f01fb659e54d hello.c --- 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 -#include +#include "stdlib.h" -#define false 0 -#define true 1 +#include -#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; } } diff -r 50dc2f4d90fd -r f01fb659e54d stdlib.h --- /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 + +#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); +}