2 atmega168_timer_64led.c
4 Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
6 This file is part of simavr.
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.
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.
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/>.
23 #include <avr/interrupt.h>
24 #include <util/delay.h>
25 #include <avr/sleep.h>
27 #include "atmega168_timer_64led.h"
29 // for linker, emulator, and programmer's sake
30 #include "avr_mcu_section.h"
31 AVR_MCU(F_CPU, "atmega168");
33 PIN_DEFINE(SRESET, D, PD4, 1);
34 //PIN_DEFINE(SOE, D, PD6, 1); // pwm AIN0/OC0A
35 PIN_DEFINE(SLATCH, D, PD7, 1);
37 PIN_DEFINE(BSTART, C, PC0, 1); // PCI6
38 PIN_DEFINE(BSTOP, B, PB1, 1); // PCI1
39 PIN_DEFINE(BRESET, B, PB0, 1); // PCI0
45 TICK_SECOND = TICK_HZ,
46 TICK_250MS = (TICK_SECOND / 4),
47 TICK_500MS = (TICK_SECOND / 2),
48 TICK_750MS = (TICK_500MS + TICK_250MS),
51 TICK_TIMER_DISABLED = 0xff
54 volatile uint32_t tickCount;
57 void (*callback)(struct tick_t *);
69 struct tick_t timer[timer_MAX];
71 #define tick_timer_fired(_t) (timer[(_t)].delay == 0)
72 #define tick_timer_reset(_t, _v) timer[(_t)].delay = (_v)
74 ISR(TIMER2_COMPA_vect) // handler for Output Compare 1 overflow interrupt
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]);
94 // needs to do that before changing the timer registers
95 // ASYNC timer using a 32k crystal
97 TCCR2A = (1 << WGM21);
100 TIMSK2 |= (1 << OCIE2A);
105 KEY_RESET = 0, // 0x01
116 state_IncrementTime = (1 << 7),
121 uint8_t state = state_ShowTime | state_IncrementTime;
125 d_second = 0, d_10second, d_minute, d_10minute, d_hour, d_10hour, d_100hour, d_MAX
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;
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
136 #define PWM_MAX_DUTY_CYCLE 0xFF
138 #define STANDBY_DELAY 60
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;
147 Start Timer 0 with no clock prescaler and phase correct
148 fast PWM mode. Output on PD6 (OC0A).
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);
159 // Set duty cycle to 1/16th duty
160 // OCR0A = PWM_MAX_DUTY_CYCLE - (PWM_MAX_DUTY_CYCLE >> 4);
164 static inline void pwmSet(uint8_t pwm)
172 for (uint8_t in = 0; in < d_MAX; in++) {
174 decimalChanged |= (1 << in);
175 if (decimal[in] == decimal_max[in]) {
191 const uint8_t digits2led[10]= {
192 0x3f, 0x06, 0x5b, 79, 102, 109, 125, 7, 0x7f, 111
203 spi.in = spi.out = 0;
205 SPCR = (1 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) |
206 (0 << CPOL) | (0 << CPHA) | (0 << SPR0);
213 if (spi.in != spi.out) {
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.
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.
235 if (spi.in != spi.out) {
239 // fifo is empty, tell the 74hc595 to latch the shift register
247 state = (state & ~0xf) | state_ShowTime;
250 void startShowHours(uint8_t timeout /*= 4 * TICK_SECOND*/)
252 if (timer[delay_DisplayChange].delay != TICK_TIMER_DISABLED)
253 tick_timer_reset(delay_DisplayChange, timeout);
254 state = (state & ~0xf) | state_ShowHour;
267 tick_timer_reset(delay_Second, 0);
268 tick_timer_reset(delay_Update, 0);
269 pwmSet(0xff); // stop the LEDs completely
275 if (state == state_Sleep) {
277 tick_timer_reset(delay_Second, TICK_SECOND);
278 tick_timer_reset(delay_Update, 1);
287 if (state & state_IncrementTime)
290 tick_timer_reset(delay_Second, TICK_SECOND);
291 tick_timer_reset(delay_Update, 1);
292 state |= state_IncrementTime;
299 if (!(state & state_IncrementTime))
301 state &= ~state_IncrementTime;
303 tick_timer_reset(delay_StopFade, 10 * TICK_SECOND);
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++)
319 if (OCR0A == 0xff) // if the display is off, don't update anything
321 if (!(state & state_IncrementTime) || timer[delay_Second].delay <= 2) {
322 switch (state & ~state_IncrementTime) {
328 if (state & state_IncrementTime)
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];
343 void updateTimerDisplay()
346 switch (state & ~state_IncrementTime) {
347 case state_ShowTime: {
348 if (decimalChanged & (1 << d_hour)) {
349 startShowHours(4 * TICK_SECOND);
353 for (uint8_t bi = 0; bi < 4; bi++)
354 digits[bi] = digits2led[decimal[bi]];
356 if (!(state & state_IncrementTime)) {
361 case state_ShowHour: {
362 if (tick_timer_fired(delay_DisplayChange)) {
368 for (uint8_t bi = 0; bi < 4; bi++)
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]];
379 digits[2] = digits2led[decimal[d_hour]];
381 digits[0] = 116; // 'h'
383 // case state_Sleep: {
387 } while (decimalChanged);
391 * Called every seconds to update the visuals
393 void second_timer_callback(struct tick_t *t)
395 t->delay = TICK_SECOND;
397 if (state & state_IncrementTime) {
401 if (tick_timer_fired(delay_StopFade)) {
403 if (stopTimerCount >= STANDBY_DELAY) {
405 if ((stopTimerCount & 0xf) == 0) // very gradualy fade out to zero (notch every 8 secs)
408 sleepTimer(); // this will stop the one second timer
410 if (OCR0A != pwmStopped) {
411 if (OCR0A > pwmStopped)
419 updateTimerDisplay();
423 * Called every tick, to push the four bytes of the counter into the shift registers
425 void update_timer_callback(struct tick_t *t)
431 static void updateKeyValues()
433 uint8_t keyValue = (PINB & 3) | ((PINC & 1) << 2);
435 for (uint8_t ki = 0; ki < KEY_MAX; ki++)
436 if ((keyValue & (1 << ki)) != (lastKeyValue & (1 << ki)))
439 lastKeyValue = keyValue;
442 // pin change interupt
443 ISR(PCINT0_vect) { updateKeyValues(); }
444 ISR(PCINT1_vect) { updateKeyValues(); }
451 // set power reduction register, disable everything we don't need
452 PRR = (1 << PRTWI) | (1 << PRTIM1) | (1 << PRUSART0) | (1 << PRADC);
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.
462 startShowHours(4 * TICK_SECOND);
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
471 keyState = lastKeyValue;
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
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) {
490 if (keyDebounce[ki] == 50) {
491 keyEvent |= (1 << ki);
492 keyState = (keyState & ~(1 << ki)) | (lastKeyValue & (1 << ki));
497 * if a Key changed state, let's check it out
500 if ((keyEvent & (1 << KEY_START)) && (keyState & (1 << KEY_START)) == 0) {
502 startShowHours(4 * TICK_SECOND);
504 if ((keyEvent & (1 << KEY_STOP)) && (keyState & (1 << KEY_STOP)) == 0) {
506 startShowHours(4 * TICK_SECOND);
508 if ((keyEvent & (1 << KEY_RESET)) && (keyState & (1 << KEY_RESET)) == 0) {
512 updateTimerDisplay();