chiark / gitweb /
Wrap the call to turn off the bed heater in a #if to prevent a compile error on board...
[marlin.git] / Marlin / temperature.cpp
1 /*
2   temperature.c - temperature control
3   Part of Marlin
4   
5  Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
6  
7  This program is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11  
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16  
17  You should have received a copy of the GNU General Public License
18  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /*
22  This firmware is a mashup between Sprinter and grbl.
23   (https://github.com/kliment/Sprinter)
24   (https://github.com/simen/grbl/tree)
25  
26  It has preliminary support for Matthew Roberts advance algorithm 
27     http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
28
29  */
30
31
32 #include "Marlin.h"
33 #include "ultralcd.h"
34 #include "temperature.h"
35 #include "watchdog.h"
36
37 //===========================================================================
38 //=============================public variables============================
39 //===========================================================================
40 int target_raw[EXTRUDERS] = { 0 };
41 int target_raw_bed = 0;
42 #ifdef BED_LIMIT_SWITCHING
43 int target_bed_low_temp =0;  
44 int target_bed_high_temp =0;
45 #endif
46 int current_raw[EXTRUDERS] = { 0 };
47 int current_raw_bed = 0;
48
49 #ifdef PIDTEMP
50   // used external
51   float pid_setpoint[EXTRUDERS] = { 0.0 };
52   
53   float Kp=DEFAULT_Kp;
54   float Ki=(DEFAULT_Ki*PID_dT);
55   float Kd=(DEFAULT_Kd/PID_dT);
56   #ifdef PID_ADD_EXTRUSION_RATE
57     float Kc=DEFAULT_Kc;
58   #endif
59 #endif //PIDTEMP
60   
61   
62 //===========================================================================
63 //=============================private variables============================
64 //===========================================================================
65 static volatile bool temp_meas_ready = false;
66
67 static unsigned long  previous_millis_bed_heater;
68 //static unsigned long previous_millis_heater;
69
70 #ifdef PIDTEMP
71   //static cannot be external:
72   static float temp_iState[EXTRUDERS] = { 0 };
73   static float temp_dState[EXTRUDERS] = { 0 };
74   static float pTerm[EXTRUDERS];
75   static float iTerm[EXTRUDERS];
76   static float dTerm[EXTRUDERS];
77   //int output;
78   static float pid_error[EXTRUDERS];
79   static float temp_iState_min[EXTRUDERS];
80   static float temp_iState_max[EXTRUDERS];
81   // static float pid_input[EXTRUDERS];
82   // static float pid_output[EXTRUDERS];
83   static bool pid_reset[EXTRUDERS];
84 #endif //PIDTEMP
85   static unsigned char soft_pwm[EXTRUDERS];
86   
87 #ifdef WATCHPERIOD
88   int watch_raw[EXTRUDERS] = { -1000 }; // the first value used for all
89   int watch_oldtemp[3] = {0,0,0};
90   unsigned long watchmillis = 0;
91 #endif //WATCHPERIOD
92
93 // Init min and max temp with extreme values to prevent false errors during startup
94   static int minttemp[EXTRUDERS] = { 0 };
95   static int maxttemp[EXTRUDERS] = { 16383 }; // the first value used for all
96   static int bed_minttemp = 0;
97   static int bed_maxttemp = 16383;
98   static void *heater_ttbl_map[EXTRUDERS] = { (void *)heater_0_temptable
99 #if EXTRUDERS > 1
100                                             , (void *)heater_1_temptable
101 #endif
102 #if EXTRUDERS > 2
103                                             , (void *)heater_2_temptable
104 #endif
105 #if EXTRUDERS > 3
106   #error Unsupported number of extruders
107 #endif
108   };
109   static int heater_ttbllen_map[EXTRUDERS] = { heater_0_temptable_len
110 #if EXTRUDERS > 1
111                                              , heater_1_temptable_len
112 #endif
113 #if EXTRUDERS > 2
114                                              , heater_2_temptable_len
115 #endif
116 #if EXTRUDERS > 3
117   #error Unsupported number of extruders
118 #endif
119   };
120
121 //===========================================================================
122 //=============================   functions      ============================
123 //===========================================================================
124
125 void PID_autotune(float temp)
126 {
127   float input;
128   int cycles=0;
129   bool heating = true;
130
131   unsigned long temp_millis = millis();
132   unsigned long t1=temp_millis;
133   unsigned long t2=temp_millis;
134   long t_high;
135   long t_low;
136
137   long bias=127;
138   long d = 127;
139   float Ku, Tu;
140   float Kp, Ki, Kd;
141   float max, min;
142   
143   SERIAL_ECHOLN("PID Autotune start");
144   
145   disable_heater(); // switch off all heaters.
146   
147   soft_pwm[0] = 255>>1;
148     
149   for(;;) {
150
151     if(temp_meas_ready == true) { // temp sample ready
152       CRITICAL_SECTION_START;
153       temp_meas_ready = false;
154       CRITICAL_SECTION_END;
155       input = analog2temp(current_raw[0], 0);
156       
157       max=max(max,input);
158       min=min(min,input);
159       if(heating == true && input > temp) {
160         if(millis() - t2 > 5000) { 
161           heating=false;
162           soft_pwm[0] = (bias - d) >> 1;
163           t1=millis();
164           t_high=t1 - t2;
165           max=temp;
166         }
167       }
168       if(heating == false && input < temp) {
169         if(millis() - t1 > 5000) {
170           heating=true;
171           t2=millis();
172           t_low=t2 - t1;
173           if(cycles > 0) {
174             bias += (d*(t_high - t_low))/(t_low + t_high);
175             bias = constrain(bias, 20 ,235);
176             if(bias > 127) d = 254 - bias;
177             else d = bias;
178
179             SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias);
180             SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d);
181             SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min);
182             SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max);
183             if(cycles > 2) {
184               Ku = (4.0*d)/(3.14159*(max-min)/2.0);
185               Tu = ((float)(t_low + t_high)/1000.0);
186               SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku);
187               SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu);
188               Kp = 0.6*Ku;
189               Ki = 2*Kp/Tu;
190               Kd = Kp*Tu/8;
191               SERIAL_PROTOCOLLNPGM(" Clasic PID ")
192               SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
193               SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
194               SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
195               /*
196               Kp = 0.33*Ku;
197               Ki = Kp/Tu;
198               Kd = Kp*Tu/3;
199               SERIAL_PROTOCOLLNPGM(" Some overshoot ")
200               SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
201               SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
202               SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
203               Kp = 0.2*Ku;
204               Ki = 2*Kp/Tu;
205               Kd = Kp*Tu/3;
206               SERIAL_PROTOCOLLNPGM(" No overshoot ")
207               SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
208               SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
209               SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
210               */
211             }
212           }
213           soft_pwm[0] = (bias + d) >> 1;
214           cycles++;
215           min=temp;
216         }
217       } 
218     }
219     if(input > (temp + 20)) {
220       SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature to high");
221       return;
222     }
223     if(millis() - temp_millis > 2000) {
224       temp_millis = millis();
225       SERIAL_PROTOCOLPGM("ok T:");
226       SERIAL_PROTOCOL(degHotend(0));   
227       SERIAL_PROTOCOLPGM(" @:");
228       SERIAL_PROTOCOLLN(getHeaterPower(0));       
229     }
230     if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) {
231       SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout");
232       return;
233     }
234     if(cycles > 5) {
235       SERIAL_PROTOCOLLNPGM("PID Autotune finished ! Place the Kp, Ki and Kd constants in the configuration.h");
236       return;
237     }
238     LCD_STATUS;
239   }
240 }
241
242 void updatePID()
243 {
244 #ifdef PIDTEMP
245   for(int e = 0; e < EXTRUDERS; e++) { 
246      temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;  
247   }
248 #endif
249 }
250   
251 int getHeaterPower(int heater) {
252   return soft_pwm[heater];
253 }
254
255 void manage_heater()
256 {
257   #ifdef USE_WATCHDOG
258     wd_reset();
259   #endif
260   
261   float pid_input;
262   float pid_output;
263
264   if(temp_meas_ready != true)   //better readability
265     return; 
266
267   CRITICAL_SECTION_START;
268   temp_meas_ready = false;
269   CRITICAL_SECTION_END;
270
271   for(int e = 0; e < EXTRUDERS; e++) 
272   {
273
274   #ifdef PIDTEMP
275     pid_input = analog2temp(current_raw[e], e);
276
277     #ifndef PID_OPENLOOP
278         pid_error[e] = pid_setpoint[e] - pid_input;
279         if(pid_error[e] > 10) {
280           pid_output = PID_MAX;
281           pid_reset[e] = true;
282         }
283         else if(pid_error[e] < -10) {
284           pid_output = 0;
285           pid_reset[e] = true;
286         }
287         else {
288           if(pid_reset[e] == true) {
289             temp_iState[e] = 0.0;
290             pid_reset[e] = false;
291           }
292           pTerm[e] = Kp * pid_error[e];
293           temp_iState[e] += pid_error[e];
294           temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]);
295           iTerm[e] = Ki * temp_iState[e];
296           //K1 defined in Configuration.h in the PID settings
297           #define K2 (1.0-K1)
298           dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
299           temp_dState[e] = pid_input;
300           pid_output = constrain(pTerm[e] + iTerm[e] - dTerm[e], 0, PID_MAX);
301         }
302     #endif //PID_OPENLOOP
303     #ifdef PID_DEBUG
304     SERIAL_ECHOLN(" PIDDEBUG "<<e<<": Input "<<pid_input<<" Output "<<pid_output" pTerm "<<pTerm[e]<<" iTerm "<<iTerm[e]<<" dTerm "<<dTerm[e]);  
305     #endif //PID_DEBUG
306   #else /* PID off */
307     pid_output = 0;
308     if(current_raw[e] < target_raw[e]) {
309       pid_output = PID_MAX;
310     }
311   #endif
312
313     // Check if temperature is within the correct range
314     if((current_raw[e] > minttemp[e]) && (current_raw[e] < maxttemp[e])) 
315     {
316       soft_pwm[e] = (int)pid_output >> 1;
317     }
318     else {
319       soft_pwm[e] = 0;
320     }
321   } // End extruder for loop
322   
323   #ifdef WATCHPERIOD
324     if(watchmillis && millis() - watchmillis > WATCHPERIOD){
325         if(watch_oldtemp[0] >= degHotend(active_extruder)){
326             setTargetHotend(0,active_extruder);
327             LCD_MESSAGEPGM("Heating failed");
328             SERIAL_ECHO_START;
329             SERIAL_ECHOLN("Heating failed");
330         }else{
331             watchmillis = 0;
332         }
333     }
334   #endif
335   
336   if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL)
337     return;
338   previous_millis_bed_heater = millis();
339   
340   #if TEMP_BED_PIN > -1
341   
342     #ifndef BED_LIMIT_SWITCHING
343       // Check if temperature is within the correct range
344       if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) {
345         if(current_raw_bed >= target_raw_bed)
346         {
347           WRITE(HEATER_BED_PIN,LOW);
348         }
349         else 
350         {
351           WRITE(HEATER_BED_PIN,HIGH);
352         }
353       }
354       else {
355         WRITE(HEATER_BED_PIN,LOW);
356       }
357     #else //#ifdef BED_LIMIT_SWITCHING
358       // Check if temperature is within the correct band
359       if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) {
360         if(current_raw_bed > target_bed_high_temp)
361         {
362           WRITE(HEATER_BED_PIN,LOW);
363         }
364         else 
365           if(current_raw_bed <= target_bed_low_temp)
366         {
367           WRITE(HEATER_BED_PIN,HIGH);
368         }
369       }
370       else {
371         WRITE(HEATER_BED_PIN,LOW);
372       }
373     #endif
374   #endif
375 }
376
377 #define PGM_RD_W(x)   (short)pgm_read_word(&x)
378 // Takes hot end temperature value as input and returns corresponding raw value. 
379 // For a thermistor, it uses the RepRap thermistor temp table.
380 // This is needed because PID in hydra firmware hovers around a given analog value, not a temp value.
381 // This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware.
382 int temp2analog(int celsius, uint8_t e) {
383   if(e >= EXTRUDERS)
384   {
385       SERIAL_ERROR_START;
386       SERIAL_ERROR((int)e);
387       SERIAL_ERRORLNPGM(" - Invalid extruder number!");
388       kill();
389   }
390   #ifdef HEATER_0_USES_MAX6675
391     if (e == 0)
392     {
393       return celsius * 4;
394     }
395   #endif
396   if(heater_ttbl_map[e] != 0)
397   {
398     int raw = 0;
399     byte i;
400     short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
401
402     for (i=1; i<heater_ttbllen_map[e]; i++)
403     {
404       if (PGM_RD_W((*tt)[i][1]) < celsius)
405       {
406         raw = PGM_RD_W((*tt)[i-1][0]) + 
407           (celsius - PGM_RD_W((*tt)[i-1][1])) * 
408           (PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0])) /
409           (PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1]));  
410         break;
411       }
412     }
413
414     // Overflow: Set to last value in the table
415     if (i == heater_ttbllen_map[e]) raw = PGM_RD_W((*tt)[i-1][0]);
416
417     return (1023 * OVERSAMPLENR) - raw;
418   }
419   return ((celsius-TEMP_SENSOR_AD595_OFFSET)/TEMP_SENSOR_AD595_GAIN) * (1024.0 / (5.0 * 100.0) ) * OVERSAMPLENR;
420 }
421
422 // Takes bed temperature value as input and returns corresponding raw value. 
423 // For a thermistor, it uses the RepRap thermistor temp table.
424 // This is needed because PID in hydra firmware hovers around a given analog value, not a temp value.
425 // This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware.
426 int temp2analogBed(int celsius) {
427 #ifdef BED_USES_THERMISTOR
428     int raw = 0;
429     byte i;
430     
431     for (i=1; i<bedtemptable_len; i++)
432     {
433       if (PGM_RD_W(bedtemptable[i][1]) < celsius)
434       {
435         raw = PGM_RD_W(bedtemptable[i-1][0]) + 
436           (celsius - PGM_RD_W(bedtemptable[i-1][1])) * 
437           (PGM_RD_W(bedtemptable[i][0]) - PGM_RD_W(bedtemptable[i-1][0])) /
438           (PGM_RD_W(bedtemptable[i][1]) - PGM_RD_W(bedtemptable[i-1][1]));
439       
440         break;
441       }
442     }
443
444     // Overflow: Set to last value in the table
445     if (i == bedtemptable_len) raw = PGM_RD_W(bedtemptable[i-1][0]);
446
447     return (1023 * OVERSAMPLENR) - raw;
448 #elif defined BED_USES_AD595
449     return lround(((celsius-TEMP_SENSOR_AD595_OFFSET)/TEMP_SENSOR_AD595_GAIN) * (1024.0 * OVERSAMPLENR/ (5.0 * 100.0) ) );
450 #else
451     #warning No heater-type defined for the bed.
452     return 0;
453 #endif
454 }
455
456 // Derived from RepRap FiveD extruder::getTemperature()
457 // For hot end temperature measurement.
458 float analog2temp(int raw, uint8_t e) {
459   if(e >= EXTRUDERS)
460   {
461       SERIAL_ERROR_START;
462       SERIAL_ERROR((int)e);
463       SERIAL_ERRORLNPGM(" - Invalid extruder number !");
464       kill();
465   } 
466   #ifdef HEATER_0_USES_MAX6675
467     if (e == 0)
468     {
469       return 0.25 * raw;
470     }
471   #endif
472
473   if(heater_ttbl_map[e] != 0)
474   {
475     float celsius = 0;
476     byte i;  
477     short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
478
479     raw = (1023 * OVERSAMPLENR) - raw;
480     for (i=1; i<heater_ttbllen_map[e]; i++)
481     {
482       if (PGM_RD_W((*tt)[i][0]) > raw)
483       {
484         celsius = PGM_RD_W((*tt)[i-1][1]) + 
485           (raw - PGM_RD_W((*tt)[i-1][0])) * 
486           (float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) /
487           (float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0]));
488         break;
489       }
490     }
491
492     // Overflow: Set to last value in the table
493     if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]);
494
495     return celsius;
496   }
497   return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
498 }
499
500 // Derived from RepRap FiveD extruder::getTemperature()
501 // For bed temperature measurement.
502 float analog2tempBed(int raw) {
503   #ifdef BED_USES_THERMISTOR
504     float celsius = 0;
505     byte i;
506
507     raw = (1023 * OVERSAMPLENR) - raw;
508
509     for (i=1; i<bedtemptable_len; i++)
510     {
511       if (PGM_RD_W(bedtemptable[i][0]) > raw)
512       {
513         celsius  = PGM_RD_W(bedtemptable[i-1][1]) + 
514           (raw - PGM_RD_W(bedtemptable[i-1][0])) * 
515           (float)(PGM_RD_W(bedtemptable[i][1]) - PGM_RD_W(bedtemptable[i-1][1])) /
516           (float)(PGM_RD_W(bedtemptable[i][0]) - PGM_RD_W(bedtemptable[i-1][0]));
517         break;
518       }
519     }
520
521     // Overflow: Set to last value in the table
522     if (i == bedtemptable_len) celsius = PGM_RD_W(bedtemptable[i-1][1]);
523
524     return celsius;
525   #elif defined BED_USES_AD595
526     return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
527   #else
528     #warning No heater-type defined for the bed.
529     return 0;
530   #endif
531 }
532
533 void tp_init()
534 {
535   // Finish init of mult extruder arrays 
536   for(int e = 0; e < EXTRUDERS; e++) {
537     // populate with the first value 
538 #ifdef WATCHPERIOD
539     watch_raw[e] = watch_raw[0];
540 #endif
541     maxttemp[e] = maxttemp[0];
542 #ifdef PIDTEMP
543     temp_iState_min[e] = 0.0;
544     temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
545 #endif //PIDTEMP
546   }
547
548   #if (HEATER_0_PIN > -1) 
549     SET_OUTPUT(HEATER_0_PIN);
550   #endif  
551   #if (HEATER_1_PIN > -1) 
552     SET_OUTPUT(HEATER_1_PIN);
553   #endif  
554   #if (HEATER_2_PIN > -1) 
555     SET_OUTPUT(HEATER_2_PIN);
556   #endif  
557   #if (HEATER_BED_PIN > -1) 
558     SET_OUTPUT(HEATER_BED_PIN);
559   #endif  
560   #if (FAN_PIN > -1) 
561     SET_OUTPUT(FAN_PIN);
562   #endif  
563
564   #ifdef HEATER_0_USES_MAX6675
565     #ifndef SDSUPPORT
566       SET_OUTPUT(MAX_SCK_PIN);
567       WRITE(MAX_SCK_PIN,0);
568     
569       SET_OUTPUT(MAX_MOSI_PIN);
570       WRITE(MAX_MOSI_PIN,1);
571     
572       SET_INPUT(MAX_MISO_PIN);
573       WRITE(MAX_MISO_PIN,1);
574     #endif
575     
576     SET_OUTPUT(MAX6675_SS);
577     WRITE(MAX6675_SS,1);
578   #endif
579
580   // Set analog inputs
581   ADCSRA = 1<<ADEN | 1<<ADSC | 1<<ADIF | 0x07;
582   DIDR0 = 0;
583   #ifdef DIDR2
584     DIDR2 = 0;
585   #endif
586   #if (TEMP_0_PIN > -1)
587     #if TEMP_0_PIN < 8
588        DIDR0 |= 1 << TEMP_0_PIN; 
589     #else
590        DIDR2 |= 1<<(TEMP_0_PIN - 8); 
591     #endif
592   #endif
593   #if (TEMP_1_PIN > -1)
594     #if TEMP_1_PIN < 8
595        DIDR0 |= 1<<TEMP_1_PIN; 
596     #else
597        DIDR2 |= 1<<(TEMP_1_PIN - 8); 
598     #endif
599   #endif
600   #if (TEMP_2_PIN > -1)
601     #if TEMP_2_PIN < 8
602        DIDR0 |= 1 << TEMP_2_PIN; 
603     #else
604        DIDR2 = 1<<(TEMP_2_PIN - 8); 
605     #endif
606   #endif
607   #if (TEMP_BED_PIN > -1)
608     #if TEMP_BED_PIN < 8
609        DIDR0 |= 1<<TEMP_BED_PIN; 
610     #else
611        DIDR2 |= 1<<(TEMP_BED_PIN - 8); 
612     #endif
613   #endif
614   
615   // Use timer0 for temperature measurement
616   // Interleave temperature interrupt with millies interrupt
617   OCR0B = 128;
618   TIMSK0 |= (1<<OCIE0B);  
619   
620   // Wait for temperature measurement to settle
621   delay(250);
622
623 #ifdef HEATER_0_MINTEMP
624   minttemp[0] = temp2analog(HEATER_0_MINTEMP, 0);
625 #endif //MINTEMP
626 #ifdef HEATER_0_MAXTEMP
627   maxttemp[0] = temp2analog(HEATER_0_MAXTEMP, 0);
628 #endif //MAXTEMP
629
630 #if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP)
631   minttemp[1] = temp2analog(HEATER_1_MINTEMP, 1);
632 #endif // MINTEMP 1
633 #if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP)
634   maxttemp[1] = temp2analog(HEATER_1_MAXTEMP, 1);
635 #endif //MAXTEMP 1
636
637 #if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP)
638   minttemp[2] = temp2analog(HEATER_2_MINTEMP, 2);
639 #endif //MINTEMP 2
640 #if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP)
641   maxttemp[2] = temp2analog(HEATER_2_MAXTEMP, 2);
642 #endif //MAXTEMP 2
643
644 #ifdef BED_MINTEMP
645   bed_minttemp = temp2analogBed(BED_MINTEMP);
646 #endif //BED_MINTEMP
647 #ifdef BED_MAXTEMP
648   bed_maxttemp = temp2analogBed(BED_MAXTEMP);
649 #endif //BED_MAXTEMP
650 }
651
652
653
654 void setWatch() 
655 {  
656 #ifdef WATCHPERIOD
657   int t = 0;
658   for (int e = 0; e < EXTRUDERS; e++)
659   {
660     if(isHeatingHotend(e))
661     watch_oldtemp[0] = degHotend(0);
662     {
663       t = max(t,millis());
664       watch_raw[e] = current_raw[e];
665     } 
666   }
667   watchmillis = t;
668 #endif 
669 }
670
671
672 void disable_heater()
673 {
674   for(int i=0;i<EXTRUDERS;i++)
675     setTargetHotend(0,i);
676   setTargetBed(0);
677   #if TEMP_0_PIN > -1
678   target_raw[0]=0;
679   soft_pwm[0]=0;
680    #if HEATER_0_PIN > -1  
681      WRITE(HEATER_0_PIN,LOW);
682    #endif
683   #endif
684      
685   #if TEMP_1_PIN > -1
686     target_raw[1]=0;
687     soft_pwm[1]=0;
688     #if HEATER_1_PIN > -1 
689       WRITE(HEATER_1_PIN,LOW);
690     #endif
691   #endif
692       
693   #if TEMP_2_PIN > -1
694     target_raw[2]=0;
695     soft_pwm[2]=0;
696     #if HEATER_2_PIN > -1  
697       WRITE(HEATER_2_PIN,LOW);
698     #endif
699   #endif 
700
701   #if TEMP_BED_PIN > -1
702     target_raw_bed=0;
703     #if HEATER_BED_PIN > -1  
704       WRITE(HEATER_BED_PIN,LOW);
705     #endif
706   #endif 
707 }
708
709 void max_temp_error(uint8_t e) {
710   disable_heater();
711   if(IsStopped() == false) {
712     SERIAL_ERROR_START;
713     SERIAL_ERRORLN((int)e);
714     SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !");
715   }
716 }
717
718 void min_temp_error(uint8_t e) {
719   disable_heater();
720   if(IsStopped() == false) {
721     SERIAL_ERROR_START;
722     SERIAL_ERRORLN((int)e);
723     SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
724   }
725 }
726
727 void bed_max_temp_error(void) {
728 #if HEATER_BED_PIN > -1
729   WRITE(HEATER_BED_PIN, 0);
730 #endif
731   if(IsStopped() == false) {
732     SERIAL_ERROR_START;
733     SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !!");
734   }
735 }
736
737 #define HEAT_INTERVAL 250
738 #ifdef HEATER_0_USES_MAX6675
739 long max6675_previous_millis = -HEAT_INTERVAL;
740 int max6675_temp = 2000;
741
742 int read_max6675()
743 {
744   if (millis() - max6675_previous_millis < HEAT_INTERVAL) 
745     return max6675_temp;
746   
747   max6675_previous_millis = millis();
748   max6675_temp = 0;
749     
750   #ifdef        PRR
751     PRR &= ~(1<<PRSPI);
752   #elif defined PRR0
753     PRR0 &= ~(1<<PRSPI);
754   #endif
755   
756   SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0);
757   
758   // enable TT_MAX6675
759   WRITE(MAX6675_SS, 0);
760   
761   // ensure 100ns delay - a bit extra is fine
762   delay(1);
763   
764   // read MSB
765   SPDR = 0;
766   for (;(SPSR & (1<<SPIF)) == 0;);
767   max6675_temp = SPDR;
768   max6675_temp <<= 8;
769   
770   // read LSB
771   SPDR = 0;
772   for (;(SPSR & (1<<SPIF)) == 0;);
773   max6675_temp |= SPDR;
774   
775   // disable TT_MAX6675
776   WRITE(MAX6675_SS, 1);
777
778   if (max6675_temp & 4) 
779   {
780     // thermocouple open
781     max6675_temp = 2000;
782   }
783   else 
784   {
785     max6675_temp = max6675_temp >> 3;
786   }
787
788   return max6675_temp;
789 }
790 #endif
791
792
793 // Timer 0 is shared with millies
794 ISR(TIMER0_COMPB_vect)
795 {
796   //these variables are only accesible from the ISR, but static, so they don't loose their value
797   static unsigned char temp_count = 0;
798   static unsigned long raw_temp_0_value = 0;
799   static unsigned long raw_temp_1_value = 0;
800   static unsigned long raw_temp_2_value = 0;
801   static unsigned long raw_temp_bed_value = 0;
802   static unsigned char temp_state = 0;
803   static unsigned char pwm_count = 1;
804   static unsigned char soft_pwm_0;
805   static unsigned char soft_pwm_1;
806   static unsigned char soft_pwm_2;
807   
808   if(pwm_count == 0){
809     soft_pwm_0 = soft_pwm[0];
810     if(soft_pwm_0 > 0) WRITE(HEATER_0_PIN,1);
811     #if EXTRUDERS > 1
812     soft_pwm_1 = soft_pwm[1];
813     if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1);
814     #endif
815     #if EXTRUDERS > 2
816     soft_pwm_2 = soft_pwm[2];
817     if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1);
818     #endif
819   }
820   if(soft_pwm_0 <= pwm_count) WRITE(HEATER_0_PIN,0);
821   #if EXTRUDERS > 1
822   if(soft_pwm_1 <= pwm_count) WRITE(HEATER_1_PIN,0);
823   #endif
824   #if EXTRUDERS > 2
825   if(soft_pwm_2 <= pwm_count) WRITE(HEATER_2_PIN,0);
826   #endif
827   
828   pwm_count++;
829   pwm_count &= 0x7f;
830   
831   switch(temp_state) {
832     case 0: // Prepare TEMP_0
833       #if (TEMP_0_PIN > -1)
834         #if TEMP_0_PIN > 7
835           ADCSRB = 1<<MUX5;
836         #else
837           ADCSRB = 0;
838         #endif
839         ADMUX = ((1 << REFS0) | (TEMP_0_PIN & 0x07));
840         ADCSRA |= 1<<ADSC; // Start conversion
841       #endif
842       #ifdef ULTIPANEL
843         buttons_check();
844       #endif
845       temp_state = 1;
846       break;
847     case 1: // Measure TEMP_0
848       #if (TEMP_0_PIN > -1)
849         raw_temp_0_value += ADC;
850       #endif
851       #ifdef HEATER_0_USES_MAX6675 // TODO remove the blocking
852         raw_temp_0_value = read_max6675();
853       #endif
854       temp_state = 2;
855       break;
856     case 2: // Prepare TEMP_BED
857       #if (TEMP_BED_PIN > -1)
858         #if TEMP_BED_PIN > 7
859           ADCSRB = 1<<MUX5;
860         #endif
861         ADMUX = ((1 << REFS0) | (TEMP_BED_PIN & 0x07));
862         ADCSRA |= 1<<ADSC; // Start conversion
863       #endif
864       #ifdef ULTIPANEL
865         buttons_check();
866       #endif
867       temp_state = 3;
868       break;
869     case 3: // Measure TEMP_BED
870       #if (TEMP_BED_PIN > -1)
871         raw_temp_bed_value += ADC;
872       #endif
873       temp_state = 4;
874       break;
875     case 4: // Prepare TEMP_1
876       #if (TEMP_1_PIN > -1)
877         #if TEMP_1_PIN > 7
878           ADCSRB = 1<<MUX5;
879         #else
880           ADCSRB = 0;
881         #endif
882         ADMUX = ((1 << REFS0) | (TEMP_1_PIN & 0x07));
883         ADCSRA |= 1<<ADSC; // Start conversion
884       #endif
885       #ifdef ULTIPANEL
886         buttons_check();
887       #endif
888       temp_state = 5;
889       break;
890     case 5: // Measure TEMP_1
891       #if (TEMP_1_PIN > -1)
892         raw_temp_1_value += ADC;
893       #endif
894       temp_state = 6;
895       break;
896     case 6: // Prepare TEMP_2
897       #if (TEMP_2_PIN > -1)
898         #if TEMP_2_PIN > 7
899           ADCSRB = 1<<MUX5;
900         #else
901           ADCSRB = 0;
902         #endif
903         ADMUX = ((1 << REFS0) | (TEMP_2_PIN & 0x07));
904         ADCSRA |= 1<<ADSC; // Start conversion
905       #endif
906       #ifdef ULTIPANEL
907         buttons_check();
908       #endif
909       temp_state = 7;
910       break;
911     case 7: // Measure TEMP_2
912       #if (TEMP_2_PIN > -1)
913         raw_temp_2_value += ADC;
914       #endif
915       temp_state = 0;
916       temp_count++;
917       break;
918 //    default:
919 //      SERIAL_ERROR_START;
920 //      SERIAL_ERRORLNPGM("Temp measurement error!");
921 //      break;
922   }
923     
924   if(temp_count >= 16) // 8 ms * 16 = 128ms.
925   {
926     #if defined(HEATER_0_USES_AD595) || defined(HEATER_0_USES_MAX6675)
927       current_raw[0] = raw_temp_0_value;
928     #else
929       current_raw[0] = 16383 - raw_temp_0_value;
930     #endif
931
932 #if EXTRUDERS > 1    
933     #ifdef HEATER_1_USES_AD595
934       current_raw[1] = raw_temp_1_value;
935     #else
936       current_raw[1] = 16383 - raw_temp_1_value;
937     #endif
938 #endif
939     
940 #if EXTRUDERS > 2
941     #ifdef HEATER_2_USES_AD595
942       current_raw[2] = raw_temp_2_value;
943     #else
944       current_raw[2] = 16383 - raw_temp_2_value;
945     #endif
946 #endif
947     
948     #ifdef BED_USES_AD595
949       current_raw_bed = raw_temp_bed_value;
950     #else
951       current_raw_bed = 16383 - raw_temp_bed_value;
952     #endif
953     
954     temp_meas_ready = true;
955     temp_count = 0;
956     raw_temp_0_value = 0;
957     raw_temp_1_value = 0;
958     raw_temp_2_value = 0;
959     raw_temp_bed_value = 0;
960
961     for(unsigned char e = 0; e < EXTRUDERS; e++) {
962        if(current_raw[e] >= maxttemp[e]) {
963           target_raw[e] = 0;
964           max_temp_error(e);
965           #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
966           {
967             Stop();;
968           }
969           #endif
970        }
971        if(current_raw[e] <= minttemp[e]) {
972           target_raw[e] = 0;
973           min_temp_error(e);
974           #ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
975           {
976             Stop();
977           }
978           #endif
979        }
980     }
981   
982 #if defined(BED_MAXTEMP) && (HEATER_BED_PIN > -1)
983     if(current_raw_bed >= bed_maxttemp) {
984        target_raw_bed = 0;
985        bed_max_temp_error();
986        Stop();
987     }
988 #endif
989   }
990 }
991