2022-05-14 13:07:58 +00:00
// fan control and check
# include "fancheck.h"
# include "cardreader.h"
# include "ultralcd.h"
# include "sound.h"
# include "messages.h"
# include "temperature.h"
# include "stepper.h"
# define FAN_CHECK_PERIOD 5000 //5s
# define FAN_CHECK_DURATION 100 //100ms
# ifdef FANCHECK
volatile uint8_t fan_check_error = EFCE_OK ;
# endif
# if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
# ifdef EXTRUDER_ALTFAN_DETECT
static struct
{
uint8_t isAltfan : 1 ;
uint8_t altfanOverride : 1 ;
} altfanStatus ;
# endif //EXTRUDER_ALTFAN_DETECT
unsigned long extruder_autofan_last_check = _millis ( ) ;
bool fan_measuring = false ;
static uint8_t fanState = 0 ;
# endif
# if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
# if defined(FAN_PIN) && FAN_PIN > -1
# if EXTRUDER_0_AUTO_FAN_PIN == FAN_PIN
# error "You cannot set EXTRUDER_0_AUTO_FAN_PIN equal to FAN_PIN"
# endif
# endif
void setExtruderAutoFanState ( uint8_t state )
{
//If bit 1 is set (0x02), then the extruder fan speed won't be adjusted according to temperature. Useful for forcing
//the fan to either On or Off during certain tests/errors.
fanState = state ;
newFanSpeed = 0 ;
if ( fanState & 0x01 )
{
# ifdef EXTRUDER_ALTFAN_DETECT
if ( altfanStatus . isAltfan & & ! altfanStatus . altfanOverride ) newFanSpeed = EXTRUDER_ALTFAN_SPEED_SILENT ;
else newFanSpeed = EXTRUDER_AUTO_FAN_SPEED ;
# else //EXTRUDER_ALTFAN_DETECT
newFanSpeed = EXTRUDER_AUTO_FAN_SPEED ;
# endif //EXTRUDER_ALTFAN_DETECT
}
timer4_set_fan0 ( newFanSpeed ) ;
}
# if (defined(FANCHECK) && (((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1)))))
void countFanSpeed ( )
{
//SERIAL_ECHOPGM("edge counter 1:"); MYSERIAL.println(fan_edge_counter[1]);
fan_speed [ 0 ] = ( fan_edge_counter [ 0 ] * ( float ( 250 ) / ( _millis ( ) - extruder_autofan_last_check ) ) ) ;
fan_speed [ 1 ] = ( fan_edge_counter [ 1 ] * ( float ( 250 ) / ( _millis ( ) - extruder_autofan_last_check ) ) ) ;
/*SERIAL_ECHOPGM("time interval: "); MYSERIAL.println(_millis() - extruder_autofan_last_check);
SERIAL_ECHOPGM ( " extruder fan speed: " ) ; MYSERIAL . print ( fan_speed [ 0 ] ) ; SERIAL_ECHOPGM ( " ; edge counter: " ) ; MYSERIAL . println ( fan_edge_counter [ 0 ] ) ;
SERIAL_ECHOPGM ( " print fan speed: " ) ; MYSERIAL . print ( fan_speed [ 1 ] ) ; SERIAL_ECHOPGM ( " ; edge counter: " ) ; MYSERIAL . println ( fan_edge_counter [ 1 ] ) ;
SERIAL_ECHOLNPGM ( " " ) ; */
fan_edge_counter [ 0 ] = 0 ;
fan_edge_counter [ 1 ] = 0 ;
}
//! Prints serialMsg to serial port, displays lcdMsg onto the LCD and beeps.
//! Extracted from fanSpeedError to save some space.
//! @param serialMsg pointer into PROGMEM, this text will be printed to the serial port
//! @param lcdMsg pointer into PROGMEM, this text will be printed onto the LCD
static void fanSpeedErrorBeep ( const char * serialMsg , const char * lcdMsg ) {
SERIAL_ECHOLNRPGM ( serialMsg ) ;
if ( get_message_level ( ) = = 0 ) {
Sound_MakeCustom ( 200 , 0 , true ) ;
LCD_ALERTMESSAGERPGM ( lcdMsg ) ;
}
}
void fanSpeedError ( unsigned char _fan ) {
if ( get_message_level ( ) ! = 0 & & isPrintPaused ) return ;
//to ensure that target temp. is not set to zero in case that we are resuming print
if ( card . sdprinting | | usb_timer . running ( ) ) {
if ( heating_status ! = HeatingStatus : : NO_HEATING ) {
lcd_print_stop ( ) ;
}
else {
fan_check_error = EFCE_DETECTED ; //plans error for next processed command
}
}
else {
// SERIAL_PROTOCOLLNRPGM(MSG_OCTOPRINT_PAUSED); //Why pause octoprint? usb_timer.running() would be true in that case, so there is no need for this.
setTargetHotend0 ( 0 ) ;
heating_status = HeatingStatus : : NO_HEATING ;
fan_check_error = EFCE_REPORTED ;
}
switch ( _fan ) {
case 0 : // extracting the same code from case 0 and case 1 into a function saves 72B
fanSpeedErrorBeep ( PSTR ( " Extruder fan speed is lower than expected " ) , MSG_FANCHECK_EXTRUDER ) ;
break ;
case 1 :
fanSpeedErrorBeep ( PSTR ( " Print fan speed is lower than expected " ) , MSG_FANCHECK_PRINT ) ;
break ;
}
}
void checkFanSpeed ( )
{
uint8_t max_fan_errors [ 2 ] ;
# ifdef FAN_SOFT_PWM
max_fan_errors [ 1 ] = 3 ; // 15 seconds (Print fan)
max_fan_errors [ 0 ] = 2 ; // 10 seconds (Extruder fan)
# else //FAN_SOFT_PWM
max_fan_errors [ 1 ] = 15 ; // 15 seconds (Print fan)
max_fan_errors [ 0 ] = 5 ; // 5 seconds (Extruder fan)
# endif //FAN_SOFT_PWM
if ( fans_check_enabled )
fans_check_enabled = ( eeprom_read_byte ( ( uint8_t * ) EEPROM_FAN_CHECK_ENABLED ) > 0 ) ;
static uint8_t fan_speed_errors [ 2 ] = { 0 , 0 } ;
# if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 >-1))
if ( ( fan_speed [ 0 ] < 20 ) & & ( current_temperature [ 0 ] > EXTRUDER_AUTO_FAN_TEMPERATURE ) ) { fan_speed_errors [ 0 ] + + ; }
else fan_speed_errors [ 0 ] = 0 ;
# endif
# if (defined(FANCHECK) && defined(TACH_1) && (TACH_1 >-1))
if ( ( fan_speed [ 1 ] < 5 ) & & ( ( blocks_queued ( ) ? block_buffer [ block_buffer_tail ] . fan_speed : fanSpeed ) > MIN_PRINT_FAN_SPEED ) ) fan_speed_errors [ 1 ] + + ;
else fan_speed_errors [ 1 ] = 0 ;
# endif
// drop the fan_check_error flag when both fans are ok
if ( fan_speed_errors [ 0 ] = = 0 & & fan_speed_errors [ 1 ] = = 0 & & fan_check_error = = EFCE_REPORTED ) {
// we may even send some info to the LCD from here
fan_check_error = EFCE_FIXED ;
}
if ( ( fan_check_error = = EFCE_FIXED ) & & ! PRINTER_ACTIVE ) {
fan_check_error = EFCE_OK ; //if the issue is fixed while the printer is doing nothing, reenable processing immediately.
lcd_reset_alert_level ( ) ; //for another fan speed error
}
if ( fans_check_enabled & & ( fan_check_error = = EFCE_OK ) )
{
for ( uint8_t fan = 0 ; fan < 2 ; fan + + )
{
if ( fan_speed_errors [ fan ] > max_fan_errors [ fan ] )
{
fan_speed_errors [ fan ] = 0 ;
fanSpeedError ( fan ) ;
}
}
}
}
# endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
# ifdef EXTRUDER_ALTFAN_DETECT
ISR ( INT6_vect ) {
fan_edge_counter [ 0 ] + + ;
}
bool extruder_altfan_detect ( )
{
setExtruderAutoFanState ( 3 ) ;
SET_INPUT ( TACH_0 ) ;
uint8_t overrideVal = eeprom_read_byte ( ( uint8_t * ) EEPROM_ALTFAN_OVERRIDE ) ;
if ( overrideVal = = EEPROM_EMPTY_VALUE )
{
overrideVal = ( calibration_status ( ) = = CALIBRATION_STATUS_CALIBRATED ) ? 1 : 0 ;
eeprom_update_byte ( ( uint8_t * ) EEPROM_ALTFAN_OVERRIDE , overrideVal ) ;
}
altfanStatus . altfanOverride = overrideVal ;
CRITICAL_SECTION_START ;
EICRB & = ~ ( 1 < < ISC61 ) ;
EICRB | = ( 1 < < ISC60 ) ;
EIMSK | = ( 1 < < INT6 ) ;
fan_edge_counter [ 0 ] = 0 ;
CRITICAL_SECTION_END ;
extruder_autofan_last_check = _millis ( ) ;
_delay ( 1000 ) ;
EIMSK & = ~ ( 1 < < INT6 ) ;
countFanSpeed ( ) ;
altfanStatus . isAltfan = fan_speed [ 0 ] > 100 ;
setExtruderAutoFanState ( 1 ) ;
return altfanStatus . isAltfan ;
}
void altfanOverride_toggle ( )
{
altfanStatus . altfanOverride = ! altfanStatus . altfanOverride ;
eeprom_update_byte ( ( uint8_t * ) EEPROM_ALTFAN_OVERRIDE , altfanStatus . altfanOverride ) ;
}
bool altfanOverride_get ( )
{
return altfanStatus . altfanOverride ;
}
# endif //EXTRUDER_ALTFAN_DETECT
void checkExtruderAutoFans ( )
{
# if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1
if ( ! ( fanState & 0x02 ) )
{
fanState & = ~ 1 ;
fanState | = current_temperature [ 0 ] > EXTRUDER_AUTO_FAN_TEMPERATURE ;
}
setExtruderAutoFanState ( fanState ) ;
# endif
}
# endif // any extruder auto fan pins set
# if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 > -1))
2022-05-14 22:54:34 +00:00
void readFanTach ( ) {
2022-05-14 13:07:58 +00:00
# ifdef FAN_SOFT_PWM
if ( READ ( TACH_0 ) ! = fan_state [ 0 ] ) {
if ( fan_measuring ) fan_edge_counter [ 0 ] + + ;
fan_state [ 0 ] = ! fan_state [ 0 ] ;
}
# else //FAN_SOFT_PWM
if ( READ ( TACH_0 ) ! = fan_state [ 0 ] ) {
fan_edge_counter [ 0 ] + + ;
fan_state [ 0 ] = ! fan_state [ 0 ] ;
}
# endif
//if (READ(TACH_1) != fan_state[1]) {
// fan_edge_counter[1] ++;
// fan_state[1] = !fan_state[1];
//}
}
# endif //TACH_0
2022-05-14 22:54:34 +00:00
void checkFans ( )
2022-05-14 13:07:58 +00:00
{
# ifndef DEBUG_DISABLE_FANCHECK
# if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1)
# ifdef FAN_SOFT_PWM
# ifdef FANCHECK
if ( ( _millis ( ) - extruder_autofan_last_check > FAN_CHECK_PERIOD ) & & ( ! fan_measuring ) ) {
extruder_autofan_last_check = _millis ( ) ;
fanSpeedBckp = fanSpeedSoftPwm ;
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
// printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
fanSpeedSoftPwm = 255 ;
}
fan_measuring = true ;
}
if ( ( _millis ( ) - extruder_autofan_last_check > FAN_CHECK_DURATION ) & & ( fan_measuring ) ) {
countFanSpeed ( ) ;
checkFanSpeed ( ) ;
//printf_P(PSTR("fanSpeedSoftPwm 1: %d\n"), fanSpeedSoftPwm);
fanSpeedSoftPwm = fanSpeedBckp ;
//printf_P(PSTR("fan PWM: %d; extr fanSpeed measured: %d; print fan speed measured: %d \n"), fanSpeedBckp, fan_speed[0], fan_speed[1]);
extruder_autofan_last_check = _millis ( ) ;
fan_measuring = false ;
}
# endif //FANCHECK
checkExtruderAutoFans ( ) ;
# else //FAN_SOFT_PWM
if ( _millis ( ) - extruder_autofan_last_check > 1000 ) // only need to check fan state very infrequently
{
# if (defined(FANCHECK) && ((defined(TACH_0) && (TACH_0 >-1)) || (defined(TACH_1) && (TACH_1 > -1))))
countFanSpeed ( ) ;
checkFanSpeed ( ) ;
# endif //(defined(TACH_0) && TACH_0 >-1) || (defined(TACH_1) && TACH_1 > -1)
checkExtruderAutoFans ( ) ;
extruder_autofan_last_check = _millis ( ) ;
}
# endif //FAN_SOFT_PWM
# endif
# endif //DEBUG_DISABLE_FANCHECK
}
void hotendFanSetFullSpeed ( )
{
# ifdef EXTRUDER_ALTFAN_DETECT
altfanStatus . altfanOverride = 1 ; //full speed
# endif //EXTRUDER_ALTFAN_DETECT
setExtruderAutoFanState ( 3 ) ;
SET_OUTPUT ( FAN_PIN ) ;
# ifdef FAN_SOFT_PWM
fanSpeedSoftPwm = 255 ;
# else //FAN_SOFT_PWM
analogWrite ( FAN_PIN , 255 ) ;
# endif //FAN_SOFT_PWM
fanSpeed = 255 ;
}