timer: Avoid infinite cycle timer on TCNT write
[simavr] / examples / board_timer_64led / atmega168_timer_64led.c
1 /*
2         atmega168_timer_64led.c
3         
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it under the terms of the GNU General Public License as published by
10         the Free Software Foundation, either version 3 of the License, or
11         (at your option) any later version.
12
13         simavr is distributed in the hope that it will be useful,
14         but WITHOUT ANY WARRANTY; without even the implied warranty of
15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16         GNU General Public License for more details.
17
18         You should have received a copy of the GNU General Public License
19         along with simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <avr/io.h>
23 #include <avr/interrupt.h>
24 #include <util/delay.h>
25 #include <avr/sleep.h>
26
27 #include "atmega168_timer_64led.h"
28
29 // for linker, emulator, and programmer's sake
30 #include "avr_mcu_section.h"
31 AVR_MCU(F_CPU, "atmega168");
32
33 PIN_DEFINE(SRESET, D, PD4, 1);
34 //PIN_DEFINE(SOE, D, PD6, 1);           // pwm AIN0/OC0A
35 PIN_DEFINE(SLATCH, D, PD7, 1);
36
37 PIN_DEFINE(BSTART, C, PC0, 1);  // PCI6
38 PIN_DEFINE(BSTOP, B, PB1, 1);   // PCI1
39 PIN_DEFINE(BRESET, B, PB0, 1);  // PCI0
40
41
42 #define TICK_HZ                                 4
43
44 enum {
45         TICK_SECOND                     = TICK_HZ,
46         TICK_250MS                      = (TICK_SECOND / 4),
47         TICK_500MS                      = (TICK_SECOND / 2),
48         TICK_750MS                      = (TICK_500MS + TICK_250MS),
49         TICK_MAX                        = 0x7f,
50
51         TICK_TIMER_DISABLED             = 0xff
52 };
53
54 volatile uint32_t tickCount;
55 struct tick_t {
56         uint8_t delay;
57         void (*callback)(struct tick_t *);
58 };
59
60 enum EDelayIndex {
61         delay_Second    = 0,
62         delay_Update,
63         delay_DisplayChange,
64         delay_StopFade,
65
66         timer_MAX
67 };
68
69 struct tick_t timer[timer_MAX];
70
71 #define tick_timer_fired(_t) (timer[(_t)].delay == 0)
72 #define tick_timer_reset(_t, _v) timer[(_t)].delay = (_v)
73
74 ISR(TIMER2_COMPA_vect)          // handler for Output Compare 1 overflow interrupt
75 {
76         sei();
77         tickCount++;
78
79         // decrement delay lines
80         for (char i = 0; i < timer_MAX; i++)
81                 if (timer[(int)i].delay && timer[(int)i].delay != TICK_TIMER_DISABLED) {
82                         timer[(int)i].delay--;
83                         if (timer[(int)i].delay == 0 && timer[(int)i].callback)
84                                 timer[(int)i].callback(&timer[(int)i]);
85                 }
86 }
87
88
89 void tick_init()
90 {
91         /*
92                 Timer 2 as RTC
93          */
94         // needs to do that before changing the timer registers
95         // ASYNC timer using a 32k crystal
96         ASSR |= (1 << AS2);
97     TCCR2A = (1 << WGM21);
98     TCCR2B = (3 << CS20);
99     OCR2A = 127;
100     TIMSK2  |= (1 << OCIE2A);
101 }
102
103
104 enum EKEYS {
105         KEY_RESET = 0,  // 0x01
106         KEY_STOP,               // 0x02
107         KEY_START,              // 0x04
108         KEY_MAX
109 };
110
111 enum EState {
112         state_ShowTime = 0,
113         state_ShowHour,
114         state_Sleep,
115         
116         state_IncrementTime = (1 << 7),
117         
118         state_MAX
119 } ;
120
121 uint8_t state = state_ShowTime | state_IncrementTime;
122 uint8_t digits[4];
123
124 enum EDecimal {
125         d_second = 0, d_10second, d_minute, d_10minute, d_hour, d_10hour, d_100hour, d_MAX
126 };
127 const uint8_t decimal_max[d_MAX] = { 10, 6, 10, 6, 10, 10, 10 };
128 uint8_t decimal[d_MAX] = {0,0,0,0,0,0,0};
129 uint8_t decimalChanged = 0;
130
131 uint8_t keyState;// = 0x7;
132 uint8_t keyEvent = 0;
133 uint8_t keyDebounce[KEY_MAX];
134 uint8_t lastKeyValue; // = 0; // use to detect which pin(s) triggered the interupt
135
136 #define PWM_MAX_DUTY_CYCLE 0xFF
137
138 #define STANDBY_DELAY   60
139
140 uint8_t pwmRunning = PWM_MAX_DUTY_CYCLE - (PWM_MAX_DUTY_CYCLE >> 4);
141 uint8_t pwmStopped = PWM_MAX_DUTY_CYCLE - (PWM_MAX_DUTY_CYCLE >> 6);
142 uint16_t stopTimerCount;
143
144 void pwmInit(void)
145 {
146     /* 
147        Start Timer 0 with no clock prescaler and phase correct 
148        fast PWM mode. Output on PD6 (OC0A). 
149     */
150     TCCR0A =  (1<<COM0A1)|(0<<COM0A0)|(0<<COM0B1)|(0<<COM0B0)
151              |(1<<WGM01) |(1<<WGM00);
152     TCCR0B =  (0<<FOC0A) |(0<<FOC0B) |(0<<WGM02)
153              |(0<<CS01)  |(1<<CS00);
154 //      TIMSK0 = (1 << OCIE0A);
155         
156     // Reset counter
157     TCNT0 = 0;
158
159     // Set duty cycle to 1/16th duty
160 //    OCR0A  = PWM_MAX_DUTY_CYCLE - (PWM_MAX_DUTY_CYCLE >> 4);
161         OCR0A = pwmRunning;
162 }
163
164 static inline void pwmSet(uint8_t pwm)
165 {
166         OCR0A = pwm;
167 }
168
169
170 void decimalInc()
171 {
172         for (uint8_t in = 0; in < d_MAX; in++) {
173                 decimal[in]++;
174                 decimalChanged |= (1 << in);
175                 if (decimal[in] == decimal_max[in]) {
176                         decimal[in] = 0;
177                 } else
178                         break;
179         }
180 }
181
182 /*
183                         0x01 0x01
184                 0x20            0x02
185                 0x20            0x02
186                         0x40 0x40
187                 0x10            0x04
188                 0x10            0x04
189                         0x08 0x08
190   */
191 const uint8_t   digits2led[10]= {
192         0x3f, 0x06, 0x5b, 79, 102, 109, 125, 7, 0x7f, 111
193 };
194
195 struct {
196         uint8_t b[16];  
197         uint8_t in : 4;
198         uint8_t out : 4;        
199 } spi;
200
201 void spi_init()
202 {
203         spi.in = spi.out = 0;
204                 
205         SPCR =  (1 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | 
206                         (0 << CPOL) | (0 << CPHA) | (0 << SPR0);
207         SPSR =  (0 << SPI2X);
208 }
209
210 void spi_start()
211 {
212         uint8_t b;
213         if (spi.in != spi.out) {
214                 b = spi.b[spi.in++];
215                 SPDR = b;
216         }               
217 }
218
219 /*
220  * SPI FIFO and it's interupt function. The function just pushes the
221  * 'next' byte into the SPI register, and if there are no more bytes, it
222  * toggles the 'latch' PIN of the 74H595 to update all the LEDS in one go.
223  *
224  * There is a potential small race condition here where 2 sets of four bytes
225  * are sent in sequence, but the probability is that 64 bits will be sent 
226  * before the latch trigges instead of 32; and if they were /that/ close it
227  * doesn'nt make a difference anyway.
228  * One way to solve that would be to have a 'terminator' or 'flush' signal
229  * queued along the byte stream.
230  */
231
232 ISR(SPI_STC_vect)
233 {
234         uint8_t b;
235         if (spi.in != spi.out) {
236                 b = spi.b[spi.in++];
237                 SPDR = b;
238         } else {
239                 // fifo is empty, tell the 74hc595 to latch the shift register
240                 SET_SLATCH();
241                 CLR_SLATCH();
242         }
243 }
244
245 void startShowTime()
246 {
247         state = (state & ~0xf) | state_ShowTime;
248 }
249
250 void startShowHours(uint8_t timeout /*= 4 * TICK_SECOND*/)
251 {
252         if (timer[delay_DisplayChange].delay != TICK_TIMER_DISABLED)
253                 tick_timer_reset(delay_DisplayChange, timeout);
254         state = (state & ~0xf) | state_ShowHour;
255 }
256
257 void updateTimer();
258 void sleepTimer();
259 void wakeTimer();
260 int startTimer();
261 int stopTimer();
262 void resetTimer();
263
264 void sleepTimer()
265 {
266         state = state_Sleep;
267         tick_timer_reset(delay_Second, 0);
268         tick_timer_reset(delay_Update, 0);
269         pwmSet(0xff);           // stop the LEDs completely
270 }
271
272 void wakeTimer()
273 {
274         stopTimerCount = 0;
275         if (state == state_Sleep) {
276                 startShowTime();
277                 tick_timer_reset(delay_Second, TICK_SECOND);
278                 tick_timer_reset(delay_Update, 1);
279                 pwmSet(pwmRunning);
280                 updateTimer();
281         } else
282                 pwmSet(pwmRunning);
283 }
284
285 int startTimer()
286 {
287         if (state & state_IncrementTime)
288                 return 0;
289         wakeTimer();
290         tick_timer_reset(delay_Second, TICK_SECOND);
291         tick_timer_reset(delay_Update, 1);
292         state |= state_IncrementTime;
293         return 1;
294 }
295
296 int stopTimer()
297 {
298         wakeTimer();
299         if (!(state & state_IncrementTime))
300                 return 0;
301         state &= ~state_IncrementTime;
302         stopTimerCount = 0;
303         tick_timer_reset(delay_StopFade, 10 * TICK_SECOND);
304         return 1;
305 }
306
307 void resetTimer()
308 {
309         wakeTimer();
310         startShowTime();
311         tick_timer_reset(delay_Second, TICK_SECOND);
312         tick_timer_reset(delay_Update, 1);
313         for (uint8_t bi = 0; bi < d_MAX; bi++)
314                 decimal[bi] = 0;
315 }
316
317 void updateTimer()
318 {
319         if (OCR0A == 0xff)      // if the display is off, don't update anything
320                 return;
321         if (!(state & state_IncrementTime) || timer[delay_Second].delay <= 2) {
322                 switch (state & ~state_IncrementTime) {
323                         case state_ShowTime:
324                                 digits[1] |= 0x80;
325                                 digits[2] |= 0x80;
326                                 break;
327                         case state_ShowHour:
328                                 if (state & state_IncrementTime)
329                                         digits[0] |= 0x80;
330                                 break;
331                 }
332         }            
333         cli();
334         // interupts are stopped here, so there is no race condition
335         int restart = spi.out == spi.in;
336         for (uint8_t bi = 0; bi < 4; bi++)
337                 spi.b[spi.out++] = digits[bi];
338         if (restart)
339                 spi_start();
340         sei();
341 }
342
343 void updateTimerDisplay()
344 {
345         do {
346                 switch (state & ~state_IncrementTime) {
347                         case state_ShowTime: {
348                                 if (decimalChanged & (1 << d_hour)) {
349                                         startShowHours(4 * TICK_SECOND);
350                                         break;
351                                 }
352                                 decimalChanged = 0;
353                                 for (uint8_t bi = 0; bi < 4; bi++)
354                                         digits[bi] = digits2led[decimal[bi]];
355
356                                 if (!(state & state_IncrementTime)) {
357                                         digits[1] |= 0x80;
358                                         digits[2] |= 0x80;                                      
359                                 }
360                         }       break;
361                         case state_ShowHour: {
362                                 if (tick_timer_fired(delay_DisplayChange)) {
363                                         decimalChanged = 1;
364                                         startShowTime();
365                                         break;
366                                 }
367                                 decimalChanged = 0;
368                                 for (uint8_t bi = 0; bi < 4; bi++)
369                                         digits[bi] = 0;
370                                 
371                                 if (decimal[d_100hour]) {
372                                         digits[3] = digits2led[decimal[d_100hour]];
373                                         digits[2] = digits2led[decimal[d_10hour]];
374                                         digits[1] = digits2led[decimal[d_hour]];
375                                 } else if (decimal[d_10hour]) {
376                                         digits[3] = digits2led[decimal[d_10hour]];
377                                         digits[2] = digits2led[decimal[d_hour]];                                        
378                                 } else {
379                                         digits[2] = digits2led[decimal[d_hour]];                                        
380                                 }
381                                 digits[0] = 116; // 'h'
382                         }       break;
383         //              case state_Sleep: {
384                                 /* nothing to do */
385         //              }       break;
386                 }
387         } while (decimalChanged);
388 }
389
390 /*
391  * Called every seconds to update the visuals
392  */
393 void second_timer_callback(struct tick_t *t)
394 {
395         t->delay = TICK_SECOND;
396         
397         if (state & state_IncrementTime) {
398                 pwmSet(pwmRunning);
399                 decimalInc();
400         } else {
401                 if (tick_timer_fired(delay_StopFade)) {
402                         stopTimerCount++;
403                         if (stopTimerCount >= STANDBY_DELAY) {
404                                 if (OCR0A < 0xff) {
405                                         if ((stopTimerCount & 0xf) == 0) // very gradualy fade out to zero (notch every 8 secs)
406                                                 OCR0A++;
407                                 } else
408                                         sleepTimer(); // this will stop the one second timer
409                         } else {
410                                 if (OCR0A != pwmStopped) {
411                                         if (OCR0A > pwmStopped)
412                                                 OCR0A--;
413                                         else
414                                                 OCR0A++;
415                                 }
416                         }
417                 }                       
418         }
419         updateTimerDisplay();
420 }
421
422 /*
423  * Called every tick, to push the four bytes of the counter into the shift registers
424  */
425 void update_timer_callback(struct tick_t *t)
426 {
427         t->delay = 1;
428         updateTimer();
429 }
430
431 static void updateKeyValues()
432 {
433         uint8_t keyValue = (PINB & 3) | ((PINC & 1) << 2);
434         
435         for (uint8_t ki = 0; ki < KEY_MAX; ki++)
436                 if ((keyValue & (1 << ki)) != (lastKeyValue & (1 << ki)))
437                         keyDebounce[ki] = 0;
438                 
439         lastKeyValue = keyValue;
440 }
441
442 // pin change interupt
443 ISR(PCINT0_vect)                { updateKeyValues(); }
444 ISR(PCINT1_vect)                { updateKeyValues(); }
445
446 int main(void)
447 {
448         PORTD = 0;
449         DDRD = 0xff;
450
451         // set power reduction register, disable everything we don't need
452         PRR = (1 << PRTWI) | (1 << PRTIM1) | (1 << PRUSART0) | (1 << PRADC);
453
454         DDRB = ~3; PORTB = 3; // pullups on PB0/PB1
455         DDRC = ~1; PORTC = 1; // pullups on PC0
456         PCMSK0 = (1 << PCINT1) | (1 << PCINT0); // enable interupt for these pins
457         PCMSK1 = (1 << PCINT8);                                 // enable interupt for these pins
458         PCICR = (1 << PCIE0) | (1 << PCIE1);    // PCIE0 enable pin interupt PCINT7..0.
459
460         tick_init();
461
462         startShowHours(4 * TICK_SECOND);
463         
464         timer[delay_Second].callback = second_timer_callback;
465         timer[delay_Update].callback = update_timer_callback;
466         second_timer_callback(&timer[delay_Second]);    // get started
467         update_timer_callback(&timer[delay_Update]);    // get started
468
469     startTimer();
470     updateKeyValues();
471     keyState = lastKeyValue;
472     
473         SET_SRESET();
474
475         spi_init();
476         pwmInit();
477                 
478     sei();
479         
480     for (;;) {    /* main event loop */
481         /* If our internal ideal of which keys are down is different from the one that has been
482                         updated via the interrupts, we start counting. If the 'different' key(s) stays the same for
483                         50ms, we declare it an 'event' and update the internal key state
484                  */
485         if (keyState != lastKeyValue) {
486                 for (uint8_t ki = 0; ki < KEY_MAX; ki++)
487                         if ((keyState & (1 << ki)) != (lastKeyValue & (1 << ki))) {
488                                 if (keyDebounce[ki] < 50) {
489                                         keyDebounce[ki]++;
490                                         if (keyDebounce[ki] == 50) {
491                                                 keyEvent |= (1 << ki);
492                                                 keyState =      (keyState & ~(1 << ki)) | (lastKeyValue & (1 << ki)); 
493                                         }
494                                 }
495                         }
496                 /*
497                  * if a Key changed state, let's check it out
498                  */
499                 if (keyEvent) {
500                         if ((keyEvent & (1 << KEY_START)) &&  (keyState & (1 << KEY_START)) == 0) {
501                                 if (!startTimer())
502                                         startShowHours(4 * TICK_SECOND);
503                         }
504                         if ((keyEvent & (1 << KEY_STOP)) && (keyState & (1 << KEY_STOP)) == 0) {
505                                 if (!stopTimer())
506                                         startShowHours(4 * TICK_SECOND);
507                         }
508                         if ((keyEvent & (1 << KEY_RESET)) && (keyState & (1 << KEY_RESET)) == 0) {
509                                 resetTimer();
510                         }
511                         keyEvent = 0;
512                         updateTimerDisplay();
513                         updateTimer();
514                 }
515                 delay_ms(1);
516         } else {
517                 sleep_mode();
518         }
519     }
520     return 0;
521 }