fancheck.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // fan control and check
  2. #include "fancheck.h"
  3. #include "cardreader.h"
  4. #include "ultralcd.h"
  5. #include "sound.h"
  6. #include "messages.h"
  7. #include "temperature.h"
  8. #include "stepper.h"
  9. #define FAN_CHECK_PERIOD 5000 //5s
  10. #define FAN_CHECK_DURATION 100 //100ms
  11. #ifdef FANCHECK
  12. volatile uint8_t fan_check_error = EFCE_OK;
  13. #endif
  14. #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
  15. #ifdef EXTRUDER_ALTFAN_DETECT
  16. static struct
  17. {
  18. uint8_t isAltfan : 1;
  19. uint8_t altfanOverride : 1;
  20. } altfanStatus;
  21. #endif //EXTRUDER_ALTFAN_DETECT
  22. unsigned long extruder_autofan_last_check = _millis();
  23. bool fan_measuring = false;
  24. static uint8_t fanState = 0;
  25. #endif
  26. #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
  27. #if defined(FAN_PIN) && FAN_PIN > -1
  28. #if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN
  29. #error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN"
  30. #endif
  31. #endif
  32. void setExtruderAutoFanState(uint8_t state)
  33. {
  34. //If bit 1 is set (0x02), then the hotend fan speed won't be adjusted according to temperature. Useful for forcing
  35. //the fan to either On or Off during certain tests/errors.
  36. fanState = state;
  37. newFanSpeed = 0;
  38. if (fanState & 0x01)
  39. {
  40. #ifdef EXTRUDER_ALTFAN_DETECT
  41. if (altfanStatus.isAltfan && !altfanStatus.altfanOverride) newFanSpeed = EXTRUDER_ALTFAN_SPEED_SILENT;
  42. else newFanSpeed = EXTRUDER_AUTO_FAN_SPEED;
  43. #else //EXTRUDER_ALTFAN_DETECT
  44. newFanSpeed = EXTRUDER_AUTO_FAN_SPEED;
  45. #endif //EXTRUDER_ALTFAN_DETECT
  46. }
  47. timer4_set_fan0(newFanSpeed);
  48. }
  49. #if (defined(FANCHECK) && (((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1)))))
  50. void countFanSpeed()
  51. {
  52. //SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]);
  53. fan_speed[0] = (fan_edge_counter[0] * (float(250) / (_millis() - extruder_autofan_last_check)));
  54. fan_speed[1] = (fan_edge_counter[1] * (float(250) / (_millis() - extruder_autofan_last_check)));
  55. /*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(_millis() - extruder_autofan_last_check);
  56. SERIAL_ECHOPGM("hotend fan speed:"); MYSERIAL.print(fan_speed[0]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[0]);
  57. SERIAL_ECHOPGM("print fan speed:"); MYSERIAL.print(fan_speed[1]); SERIAL_ECHOPGM("; edge counter:"); MYSERIAL.println(fan_edge_counter[1]);
  58. SERIAL_ECHOLNPGM(" ");*/
  59. fan_edge_counter[0] = 0;
  60. fan_edge_counter[1] = 0;
  61. }
  62. //! Prints serialMsg to serial port, displays lcdMsg onto the LCD and beeps.
  63. //! Extracted from fanSpeedError to save some space.
  64. //! @param serialMsg pointer into PROGMEM, this text will be printed to the serial port
  65. //! @param lcdMsg pointer into PROGMEM, this text will be printed onto the LCD
  66. static void fanSpeedErrorBeep(const char *serialMsg, const char *lcdMsg){
  67. SERIAL_ECHOLNRPGM(serialMsg);
  68. if (get_message_level() == 0) {
  69. Sound_MakeCustom(200,0,true);
  70. LCD_ALERTMESSAGERPGM(lcdMsg);
  71. }
  72. }
  73. void fanSpeedError(unsigned char _fan) {
  74. if (fan_check_error == EFCE_REPORTED) return;
  75. fan_check_error = EFCE_REPORTED;
  76. if (IS_SD_PRINTING || usb_timer.running()) {
  77. // A print is ongoing, pause the print normally
  78. if(!isPrintPaused) {
  79. if (usb_timer.running())
  80. lcd_pause_usb_print();
  81. else
  82. lcd_pause_print();
  83. }
  84. }
  85. else {
  86. // Nothing is going on, but still turn off heaters and report the error
  87. setTargetHotend0(0);
  88. heating_status = HeatingStatus::NO_HEATING;
  89. }
  90. switch (_fan) {
  91. case 0: // extracting the same code from case 0 and case 1 into a function saves 72B
  92. fanSpeedErrorBeep(PSTR("Hotend fan speed is lower than expected"), MSG_FANCHECK_HOTEND);
  93. break;
  94. case 1:
  95. fanSpeedErrorBeep(PSTR("Print fan speed is lower than expected"), MSG_FANCHECK_PRINT);
  96. break;
  97. }
  98. }
  99. void checkFanSpeed()
  100. {
  101. uint8_t max_fan_errors[2];
  102. #ifdef FAN_SOFT_PWM
  103. max_fan_errors[1] = 3; // 15 seconds (Print fan)
  104. max_fan_errors[0] = 2; // 10 seconds (Hotend fan)
  105. #else //FAN_SOFT_PWM
  106. max_fan_errors[1] = 15; // 15 seconds (Print fan)
  107. max_fan_errors[0] = 5; // 5 seconds (Hotend fan)
  108. #endif //FAN_SOFT_PWM
  109. if(fans_check_enabled)
  110. fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0);
  111. static uint8_t fan_speed_errors[2] = { 0,0 };
  112. #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 >-1))
  113. if ((fan_speed[0] < 20) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)){ fan_speed_errors[0]++;}
  114. else fan_speed_errors[0] = 0;
  115. #endif
  116. #if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
  117. if ((fan_speed[1] < 5) && ((blocks_queued() ? block_buffer[block_buffer_tail].fan_speed : fanSpeed) > MIN_PRINT_FAN_SPEED)) fan_speed_errors[1]++;
  118. else fan_speed_errors[1] = 0;
  119. #endif
  120. // drop the fan_check_error flag when both fans are ok
  121. if( fan_speed_errors[0] == 0 && fan_speed_errors[1] == 0 && fan_check_error == EFCE_REPORTED){
  122. // we may even send some info to the LCD from here
  123. fan_check_error = EFCE_FIXED;
  124. }
  125. if ((fan_check_error == EFCE_FIXED) && !printer_active()){
  126. fan_check_error = EFCE_OK; //if the issue is fixed while the printer is doing nothing, reenable processing immediately.
  127. lcd_reset_alert_level(); //for another fan speed error
  128. }
  129. if (fans_check_enabled && (fan_check_error == EFCE_OK))
  130. {
  131. for (uint8_t fan = 0; fan < 2; fan++)
  132. {
  133. if (fan_speed_errors[fan] > max_fan_errors[fan])
  134. {
  135. fan_speed_errors[fan] = 0;
  136. fanSpeedError(fan);
  137. }
  138. }
  139. }
  140. }
  141. #endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
  142. #ifdef EXTRUDER_ALTFAN_DETECT
  143. ISR(INT6_vect) {
  144. fan_edge_counter[0]++;
  145. }
  146. bool extruder_altfan_detect()
  147. {
  148. setExtruderAutoFanState(3);
  149. SET_INPUT(TACH_0);
  150. uint8_t overrideVal = eeprom_read_byte((uint8_t *)EEPROM_ALTFAN_OVERRIDE);
  151. if (overrideVal == EEPROM_EMPTY_VALUE)
  152. {
  153. overrideVal = (calibration_status() == CALIBRATION_STATUS_CALIBRATED) ? 1 : 0;
  154. eeprom_update_byte((uint8_t *)EEPROM_ALTFAN_OVERRIDE, overrideVal);
  155. }
  156. altfanStatus.altfanOverride = overrideVal;
  157. CRITICAL_SECTION_START;
  158. EICRB &= ~(1 << ISC61);
  159. EICRB |= (1 << ISC60);
  160. EIMSK |= (1 << INT6);
  161. fan_edge_counter[0] = 0;
  162. CRITICAL_SECTION_END;
  163. extruder_autofan_last_check = _millis();
  164. _delay(1000);
  165. EIMSK &= ~(1 << INT6);
  166. countFanSpeed();
  167. altfanStatus.isAltfan = fan_speed[0] > 100;
  168. setExtruderAutoFanState(1);
  169. return altfanStatus.isAltfan;
  170. }
  171. void altfanOverride_toggle()
  172. {
  173. altfanStatus.altfanOverride = !altfanStatus.altfanOverride;
  174. eeprom_update_byte((uint8_t *)EEPROM_ALTFAN_OVERRIDE, altfanStatus.altfanOverride);
  175. }
  176. bool altfanOverride_get()
  177. {
  178. return altfanStatus.altfanOverride;
  179. }
  180. #endif //EXTRUDER_ALTFAN_DETECT
  181. void checkExtruderAutoFans()
  182. {
  183. #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
  184. if (!(fanState & 0x02))
  185. {
  186. fanState &= ~1;
  187. fanState |= current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE;
  188. fanState |= get_temp_error();
  189. }
  190. setExtruderAutoFanState(fanState);
  191. #endif
  192. }
  193. #endif // any extruder auto fan pins set
  194. #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
  195. void readFanTach() {
  196. #ifdef FAN_SOFT_PWM
  197. if (READ(TACH_0) != fan_state[0]) {
  198. if(fan_measuring) fan_edge_counter[0] ++;
  199. fan_state[0] = !fan_state[0];
  200. }
  201. #else //FAN_SOFT_PWM
  202. if (READ(TACH_0) != fan_state[0]) {
  203. fan_edge_counter[0] ++;
  204. fan_state[0] = !fan_state[0];
  205. }
  206. #endif
  207. //if (READ(TACH_1) != fan_state[1]) {
  208. // fan_edge_counter[1] ++;
  209. // fan_state[1] = !fan_state[1];
  210. //}
  211. }
  212. #endif //TACH_0
  213. void checkFans()
  214. {
  215. #ifndef DEBUG_DISABLE_FANCHECK
  216. #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
  217. #ifdef FAN_SOFT_PWM
  218. #ifdef FANCHECK
  219. if ((_millis() - extruder_autofan_last_check > FAN_CHECK_PERIOD) && (!fan_measuring)) {
  220. extruder_autofan_last_check = _millis();
  221. fanSpeedBckp = fanSpeedSoftPwm;
  222. if (fanSpeedSoftPwm >= MIN_PRINT_FAN_SPEED) { //if we are in rage where we are doing fan check, set full PWM range for a short time to measure fan RPM by reading tacho signal without modulation by PWM signal
  223. // printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
  224. fanSpeedSoftPwm = 255;
  225. }
  226. fan_measuring = true;
  227. }
  228. if ((_millis() - extruder_autofan_last_check > FAN_CHECK_DURATION) && (fan_measuring)) {
  229. countFanSpeed();
  230. checkFanSpeed();
  231. //printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
  232. fanSpeedSoftPwm = fanSpeedBckp;
  233. //printf_P(PSTR("fan PWM: %d; extr fanSpeed measured: %d; print fan speed measured: %d \n"), fanSpeedBckp, fan_speed[0], fan_speed[1]);
  234. extruder_autofan_last_check = _millis();
  235. fan_measuring = false;
  236. }
  237. #endif //FANCHECK
  238. checkExtruderAutoFans();
  239. #else //FAN_SOFT_PWM
  240. if(_millis() - extruder_autofan_last_check > 1000) // only need to check fan state very infrequently
  241. {
  242. #if (defined(FANCHECK) && ((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1))))
  243. countFanSpeed();
  244. checkFanSpeed();
  245. #endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
  246. checkExtruderAutoFans();
  247. extruder_autofan_last_check = _millis();
  248. }
  249. #endif //FAN_SOFT_PWM
  250. #endif
  251. #endif //DEBUG_DISABLE_FANCHECK
  252. }
  253. void hotendFanSetFullSpeed()
  254. {
  255. #ifdef EXTRUDER_ALTFAN_DETECT
  256. altfanStatus.altfanOverride = 1; //full speed
  257. #endif //EXTRUDER_ALTFAN_DETECT
  258. setExtruderAutoFanState(3);
  259. SET_OUTPUT(FAN_PIN);
  260. #ifdef FAN_SOFT_PWM
  261. fanSpeedSoftPwm = 255;
  262. #else //FAN_SOFT_PWM
  263. analogWrite(FAN_PIN, 255);
  264. #endif //FAN_SOFT_PWM
  265. fanSpeed = 255;
  266. }