Fixed race condition in getticks.
[kokare.git] / kokare.c
CommitLineData
31415646
FT
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <inttypes.h>
2f37b902 4#include <math.h>
31415646 5
2378926d
FT
6#define SEGA 4
7#define SEGB 2
8#define SEGC 1
9#define SEGD 32
10#define SEGE 64
11#define SEGF 16
12#define SEGG 8
13#define SEGP 128
31415646
FT
14
15uint8_t font[16] = {
16 SEGA | SEGB | SEGC | SEGD | SEGE | SEGF,
17 SEGB | SEGC,
18 SEGA | SEGB | SEGD | SEGE | SEGG,
19 SEGA | SEGB | SEGC | SEGD | SEGG,
20 SEGB | SEGC | SEGF | SEGG,
21 SEGA | SEGC | SEGD | SEGF | SEGG,
22 SEGA | SEGC | SEGD | SEGE | SEGF | SEGG,
23 SEGA | SEGB | SEGC,
24 SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG,
25 SEGA | SEGB | SEGC | SEGD | SEGF | SEGG,
26 SEGA | SEGB | SEGC | SEGE | SEGF | SEGG,
27 SEGC | SEGD | SEGE | SEGF | SEGG,
28 SEGA | SEGD | SEGE | SEGF,
29 SEGB | SEGC | SEGD | SEGE | SEGG,
30 SEGA | SEGD | SEGE | SEGF | SEGG,
31 SEGA | SEGE | SEGF | SEGG,
32};
33/* LED */
34uint8_t dsp[2] = {0, 0};
35char leda = 0;
36char ledc = 0;
37/* Timer */
26e5097c 38volatile int oticks = 0;
59d1e985 39unsigned long mnow;
31415646 40/* Pulse counter */
26e5097c 41volatile char pstate = 0;
31415646
FT
42char pval = 0;
43/* Switch */
26e5097c 44volatile char sstate = 0;
31415646
FT
45int stime = 0;
46/* Temp sensor */
26e5097c
FT
47volatile char tstate = 0;
48volatile char tlock = 0;
31415646
FT
49unsigned long tstart;
50unsigned long ttime;
51unsigned long ttimea = 10000;
c1346a55 52char tavgok = 0;
2f37b902
FT
53/* Conversion loop */
54int tempk;
55volatile ktok = 0;
31415646 56/* Zero-cross detector*/
26e5097c 57volatile char zok = 0;
c7732766 58volatile char ztime = 0;
31415646 59/* Triac */
59d1e985
FT
60char trstate = 0;
61char tron = 0;
c7732766
FT
62volatile char trtime;
63volatile char trdelay = 0;
31415646
FT
64
65void init(void)
66{
c7732766 67 /* Timer init
8c536798 68 * Timer 0 cycles the Triac
c7732766 69 * Timer 1 is used for global timing
8c536798 70 * Timer 2 cycles the LED display
c7732766
FT
71 */
72 OCR0A = 100;
73 TCCR0A = 2;
74 TCCR0B = 1;
75 TIMSK0 = 2;
31415646
FT
76 TCCR1A = 0;
77 TCCR1B = 1;
78 TIMSK1 = 1;
8c536798
FT
79 OCR2A = 16;
80 TCCR2A = 2;
81 TCCR2B = 4;
82 TIMSK2 = 2;
31415646
FT
83
84 /*
85 * B0..2 = Pulse sensor
86 * B3..5 = ISP
87 * B6..7 = CLK
88 */
c1346a55 89 DDRB = 0x38;
31415646
FT
90 PORTB = 0x07;
91 PCMSK0 = 0x07;
92 PCICR = 0x01;
93 /*
94 * C0..5 = LEDA0..5
95 * C6 = /RESET
96 * C7 = NC
97 */
98 DDRC = 0x3f;
99 PORTC = 0x00;
100 /*
101 * D0 = Triac
102 * D1 = NTC FET
103 * D2 = ZCD (INT0)
104 * D3 = NTC Op-amp (INT1)
105 * D4..5 = LEDA6..7
106 * D6..7 = LEDC0..1
107 */
108 DDRD = 0xf3;
109 PORTD = 0x00;
110 EICRA = 0x0d;
111 EIMSK = 0x03;
112}
113
114unsigned char bindisp(unsigned char num)
115{
116 unsigned char ret;
117
118 ret = 0;
119 if(num & 1)
120 ret |= SEGA;
121 if(num & 2)
122 ret |= SEGB;
123 if(num & 4)
124 ret |= SEGC;
125 if(num & 8)
126 ret |= SEGD;
127 if(num & 16)
128 ret |= SEGE;
129 if(num & 32)
130 ret |= SEGF;
131 if(num & 64)
132 ret |= SEGG;
133 if(num & 128)
134 ret |= SEGP;
135 return(ret);
136}
137
138void display(char num)
139{
140 dsp[0] = font[(num / 10) % 10];
141 dsp[1] = font[num % 10];
142}
143
144void disphex(unsigned char num)
145{
146 dsp[0] = font[(num & 0xf0) >> 4];
147 dsp[1] = font[num & 0x0f];
148}
149
cd17a211
FT
150/*
151 * This version is used outside interrupts.
152 * It spins until no overflow has happened.
153 */
31415646
FT
154unsigned long getticks(void)
155{
cd17a211
FT
156 uint16_t v;
157 unsigned long r;
158
159 do {
160 v = oticks;
161 r = TCNT1 + (((unsigned long)oticks) << 16);
162 } while(v != oticks);
163 return(r);
164}
165
166/*
167 * This version is used in interrupts
168 */
169unsigned long getticks2(void)
170{
171 uint16_t v;
172 unsigned long r;
173
174 v = TCNT1;
175 r = v + (((unsigned long)oticks) << 16);
176 if((TIFR1 & 0x01) && !(v & 0x8000))
177 return(r + 0x10000);
178 else
179 return(r);
31415646
FT
180}
181
182void ledcycle(void)
183{
31415646
FT
184 uint8_t c, d, v;
185
8c536798
FT
186 if(++leda >= 8) {
187 leda = 0;
188 if(++ledc >= 2)
189 ledc = 0;
190 }
191 if(dsp[ledc] & (1 << leda)) {
192 if(leda < 6) {
193 c = 1 << leda;
194 d = 0;
31415646 195 } else {
8c536798
FT
196 c = 0;
197 d = 0x10 << (leda - 6);
31415646 198 }
8c536798
FT
199 d |= ledc?0x40:0x80;
200 } else {
201 c = d = 0;
31415646 202 }
8c536798
FT
203 PORTC = c;
204 PORTD = (PORTD & 0x0f) | d;
31415646
FT
205}
206
207void tempcycle(void)
208{
31415646
FT
209 if(tstate == 0) {
210 if((PIND & 8) && (tlock == 0)) {
c7732766 211 cli();
31415646 212 PORTD |= 2;
c7732766 213 sei();
59d1e985 214 tstart = mnow;
31415646
FT
215 tstate = 1;
216 }
217 } else if(tstate == 1) {
59d1e985 218 if(mnow - tstart > 1000) {
c7732766 219 cli();
31415646 220 PORTD &= ~2;
c7732766 221 sei();
31415646 222 tstate = 0;
59d1e985 223 tstart = mnow;
31415646
FT
224 }
225 }
226}
227
228void calcavg(void)
229{
230 if(tlock == 1) {
231 tlock = 2;
232 ttimea = ((ttimea * 15) + ttime) >> 4;
233 tlock = 0;
c1346a55 234 tavgok = 1;
31415646
FT
235 }
236}
237
2f37b902
FT
238void convcycle(void)
239{
240 static char state = 0;
241 static unsigned long last = 0;
242 static float a, ra, l, t;
243
244 /*
245 * Theoretically:
246 * t = RC * ln(2) => R = t / (C * ln(2))
247 * R = A * exp(B / T) => T = B / ln(R / A)
248 * T = B / ln(R / (A * C * ln(2)))
249 * In the following:
250 * a = ttimea as float
251 * C = 1e6 / (A * C * ln(2))
252 * ra = a * C
253 * l = ln(ra)
254 * t = B / l
255 * Note, temperature is in Kelvin
256 */
257#define C 9.792934
258#define B 4020.0
259 if(state == 0) {
260 if((mnow - last > 200000) && tavgok) {
261 a = (float)ttimea;
262 state = 1;
263 tavgok = 0;
9ac074a9 264 last = mnow;
2f37b902
FT
265 }
266 } else if(state == 1) {
267 ra = a * C;
268 state = 2;
269 } else if(state == 2) {
270 l = log(ra);
271 state = 3;
272 } else if(state == 3) {
273 t = B / l;
274 state = 4;
275 } else if(state == 4) {
276 tempk = (int)t;
277 ktok = 1;
278 state = 0;
279 }
280}
281
31415646
FT
282int main(void)
283{
174dfeb5 284 int state, cur, run;
c1346a55 285 unsigned long utime;
31415646 286
c1346a55 287 state = 0;
174dfeb5
FT
288 cur = 100;
289 run = 0;
31415646
FT
290 init();
291 sei();
292 display(0);
59d1e985 293
31415646 294 while(1) {
59d1e985 295 mnow = getticks();
31415646
FT
296 tempcycle();
297 calcavg();
2f37b902 298 convcycle();
31415646 299
63e3aac7 300#if 1
c1346a55
FT
301 /*
302 * User interface
303 */
304 if(state == 0) {
305 /* Display temperature */
2f37b902
FT
306 if(ktok) {
307 ktok = 0;
308 if((tempk >= 273) && (tempk <= 372)) {
309 display(tempk - 273);
c1346a55 310 } else {
2f37b902 311 dsp[0] = dsp[1] = SEGG;
c1346a55
FT
312 }
313 }
174dfeb5 314 if(pval != 0)
c1346a55 315 state = 1;
2f37b902
FT
316 if(sstate == 2) {
317 sstate = 0;
174dfeb5 318 if(stime > 10)
2f37b902 319 state = 2;
174dfeb5
FT
320 else
321 run = !run;
2f37b902 322 }
174dfeb5
FT
323 if(run)
324 dsp[1] |= SEGP;
325 else
326 dsp[1] &= ~SEGP;
c1346a55 327 } else if(state == 1) {
174dfeb5 328 /* Temp setting */
c1346a55
FT
329 if(pval != 0) {
330 cur += pval;
331 pval = 0;
332 if(cur < 0)
333 cur = 0;
174dfeb5
FT
334 if(cur > 100)
335 cur = 100;
336 if(cur < 100)
337 display(cur);
338 else
339 dsp[0] = dsp[1] = SEGG;
c1346a55
FT
340 utime = mnow;
341 }
174dfeb5 342 if(mnow - utime > 1000000)
c1346a55 343 state = 0;
2f37b902 344 if(sstate == 2) {
174dfeb5 345 run = !run;
2f37b902
FT
346 sstate = 0;
347 }
348 } else if(state == 2) {
174dfeb5 349 /* Display raw temp time reading */
2f37b902
FT
350 if(ttimea < 20000) {
351 display((ttimea / 100) % 100);
352 dsp[0] |= SEGP;
353 if(ttimea >= 10000)
354 dsp[1] |= SEGP;
355 } else {
356 display(ttimea / 1000);
357 }
358 if(sstate == 2) {
359 state = 0;
360 sstate = 0;
361 }
c1346a55 362 }
174dfeb5
FT
363 /*
364 * Set Triac to match temperature
365 */
366 if(run) {
367 if(tempk - 273 < cur) {
368 tron = 1;
369 if(cur - (tempk - 273) > 5) {
370 /* For some reason, the Triac currently doesn't
371 * trigger on one of the AC half-cycles below 0.7
372 * ms. */
373 trdelay = 7;
374 } else if(cur - (tempk - 273) >= 3) {
375 trdelay = 20;
376 } else if(cur - (tempk - 273) >= 2) {
377 trdelay = 40;
378 } else {
379 trdelay = 70;
380 }
381 } else {
382 tron = 0;
383 }
384 } else {
385 tron = 0;
386 }
c1346a55 387#endif
31415646
FT
388 /*
389 dsp[0] = bindisp((ttimea & 0xff00) >> 8);
390 dsp[1] = bindisp(ttimea & 0x00ff);
391 */
392 /*
393 disphex((ttimea & 0xff000) >> 12);
394 */
495bea06 395#if 0
59d1e985
FT
396 /*
397 Temp display
398 */
31415646
FT
399 if(ttimea < 20000) {
400 display((ttimea / 100) % 100);
401 dsp[0] |= SEGP;
402 if(ttimea >= 10000)
403 dsp[1] |= SEGP;
404 } else {
405 display(ttimea / 1000);
406 }
59d1e985 407#endif
2378926d 408#if 0
72ef9ac1
FT
409 /*
410 * ZVD debug
411 */
412 if(zok) {
413 if(++cur > 99)
414 cur = 0;
415 display(cur);
416 zok = 0;
417 }
63e3aac7 418#endif
c1346a55 419#if 0
495bea06
FT
420 /*
421 Phony Triac control
422 */
423 if(pval != 0) {
424 cur += pval;
425 if(cur < 0)
426 cur = 0;
427 if(cur > 99)
428 cur = 99;
429 display(cur);
c7732766 430 trdelay = 99 - cur;
495bea06
FT
431 pval = 0;
432 }
433 if(sstate == 2) {
434 tron = !tron;
435 sstate = 0;
436 }
4f42f213
FT
437 if(tron)
438 dsp[1] |= SEGP;
439 else
440 dsp[1] &= ~SEGP;
495bea06 441#endif
59d1e985 442#if 0
31415646 443 /*
59d1e985
FT
444 Pulse counter display
445 */
31415646
FT
446 cur += pval;
447 pval = 0;
448 if(sstate == 2) {
449 cur = stime;
450 sstate = 0;
451 }
452 if(cur > 99)
453 cur = 99;
454 if(cur < -99)
455 cur = -99;
456 if(cur < 0) {
457 display(-cur);
458 dsp[0] |= SEGP;
459 } else {
460 display(cur);
461 }
4f42f213
FT
462 if(PINB & 4)
463 dsp[1] |= SEGP;
59d1e985 464#endif
31415646
FT
465 }
466}
467
468ISR(SIG_INTERRUPT0)
469{
c7732766 470 ztime = 0;
59d1e985 471 zok = 1;
31415646
FT
472}
473
474ISR(SIG_INTERRUPT1)
475{
476 unsigned long now;
477
cd17a211 478 now = getticks2();
31415646
FT
479 if(tstate == 0) {
480 tstate = 1;
481 if(tlock != 2)
482 ttime = now - tstart;
483 tstart = now;
484 PORTD |= 2;
485 tlock = 1;
486 }
487}
488
c7732766
FT
489ISR(SIG_OUTPUT_COMPARE0A)
490{
491 if(trstate == 0) {
492 ztime++;
493 if(tron && (ztime >= trdelay)) {
494 PORTD |= 1;
495 trstate = 1;
496 trtime = 0;
497 }
498 } else if(trstate == 1) {
499 trtime++;
500 if(trtime >= 5) {
501 PORTD &= ~1;
502 trstate = 0;
503 }
504 }
505}
506
8c536798
FT
507ISR(SIG_OUTPUT_COMPARE2A)
508{
509 ledcycle();
510}
511
31415646
FT
512ISR(SIG_OVERFLOW1)
513{
31415646
FT
514 oticks++;
515}
516
517ISR(SIG_PIN_CHANGE0)
518{
4f42f213 519 if((sstate == 0) && !(PINB & 4)) {
31415646
FT
520 stime = oticks;
521 sstate = 1;
522 }
4f42f213 523 if((sstate == 1) && (PINB & 4)) {
31415646
FT
524 stime = oticks - stime;
525 sstate = 2;
526 }
527 if(pstate == 0) {
528 if((PINB & 2) == 0) {
529 pstate = 1;
2378926d 530 } else if((PINB & 1) == 0) {
31415646
FT
531 pstate = 2;
532 }
533 } else if(pstate == 1) {
2378926d 534 if((PINB & 1) == 0) {
31415646
FT
535 pval++;
536 pstate = 3;
537 } else {
538 pstate = 0;
539 }
540 } else if(pstate == 2) {
541 if((PINB & 2) == 0) {
542 pval--;
543 pstate = 3;
544 } else {
545 pstate = 0;
546 }
547 } else {
2378926d 548 if((PINB & 2) && (PINB & 1))
31415646
FT
549 pstate = 0;
550 }
551}