1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
7  * ----------------------------------------------------------------------------
8  *
9  * Simple AVR demonstration.  Controls a LED that can be directly
10  * connected from OC1/OC1A to GND.  The brightness of the LED is
11  * controlled with the PWM.  After each period of the PWM, the PWM
12  * value is either incremented or decremented, that's all.
13  *
14  * $Id: demo.c 1637 2008-03-17 21:49:41Z joerg_wunsch $
15  */
16 
17 #include <inttypes.h>
18 #include <avr/io.h>
19 #include <avr/interrupt.h>
20 #include <avr/sleep.h>
21 
22 #include "iocompat.h"		/* Note [1] */
23 
24 enum { UP, DOWN };
25 
ISR(TIMER1_OVF_vect)26 ISR (TIMER1_OVF_vect)		/* Note [2] */
27 {
28     static uint16_t pwm;	/* Note [3] */
29     static uint8_t direction;
30 
31     switch (direction)		/* Note [4] */
32     {
33         case UP:
34             if (++pwm == TIMER1_TOP)
35                 direction = DOWN;
36             break;
37 
38         case DOWN:
39             if (--pwm == 0)
40                 direction = UP;
41             break;
42     }
43 
44     OCR = pwm;			/* Note [5] */
45 }
46 
47 void
ioinit(void)48 ioinit (void)			/* Note [6] */
49 {
50     /* Timer 1 is 10-bit PWM (8-bit PWM on some ATtinys). */
51     TCCR1A = TIMER1_PWM_INIT;
52     /*
53      * Start timer 1.
54      *
55      * NB: TCCR1A and TCCR1B could actually be the same register, so
56      * take care to not clobber it.
57      */
58     TCCR1B |= TIMER1_CLOCKSOURCE;
59     /*
60      * Run any device-dependent timer 1 setup hook if present.
61      */
62 #if defined(TIMER1_SETUP_HOOK)
63     TIMER1_SETUP_HOOK();
64 #endif
65 
66     /* Set PWM value to 0. */
67     OCR = 0;
68 
69     /* Enable OC1 as output. */
70     DDROC = _BV (OC1);
71 
72     /* Enable timer 1 overflow interrupt. */
73     TIMSK = _BV (TOIE1);
74     sei ();
75 }
76 
77 int
main(void)78 main (void)
79 {
80 
81     ioinit ();
82 
83     /* loop forever, the interrupts are doing the rest */
84 
85     for (;;)			/* Note [7] */
86         sleep_mode();
87 
88     return (0);
89 }
90