diff --git a/Firmware/Marlin_main.cpp b/Firmware/Marlin_main.cpp index 36764b21..799e5e9d 100755 --- a/Firmware/Marlin_main.cpp +++ b/Firmware/Marlin_main.cpp @@ -1252,6 +1252,13 @@ void setup() w25x20cl_err_msg(); printf_P(_n("W25X20CL not responding.\n")); } +#ifdef EXTRUDER_ALTFAN_DETECT + SERIAL_ECHORPGM(_n("Extruder fan type: ")); + if (extruder_altfan_detect()) + SERIAL_ECHOLNRPGM(PSTR("ALTFAN")); + else + SERIAL_ECHOLNRPGM(PSTR("NOCTUA")); +#endif //EXTRUDER_ALTFAN_DETECT plan_init(); // Initialize planner; diff --git a/Firmware/system_timer.h b/Firmware/system_timer.h index 626e8234..9906460a 100644 --- a/Firmware/system_timer.h +++ b/Firmware/system_timer.h @@ -8,11 +8,12 @@ #ifdef SYSTEM_TIMER_2 #include "timer02.h" +#include "tone04.h" #define _millis millis2 #define _micros micros2 #define _delay delay2 -#define _tone tone -#define _noTone noTone +#define _tone tone4 +#define _noTone noTone4 #define timer02_set_pwm0(pwm0) diff --git a/Firmware/temperature.cpp b/Firmware/temperature.cpp index f6f8f320..c019514c 100755 --- a/Firmware/temperature.cpp +++ b/Firmware/temperature.cpp @@ -143,14 +143,18 @@ static volatile bool temp_meas_ready = false; #ifdef FAN_SOFT_PWM static unsigned char soft_pwm_fan; #endif -#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) - unsigned long extruder_autofan_last_check = _millis(); - uint8_t fanSpeedBckp = 255; - bool fan_measuring = false; -#endif +uint8_t fanSpeedBckp = 255; + +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) + unsigned long extruder_autofan_last_check = _millis(); + + bool fan_measuring = false; + uint8_t fanState = 0; +#ifdef EXTRUDER_ALTFAN_DETECT + bool extruderFanIsAltfan = false; //set to Noctua +#endif //EXTRUDER_ALTFAN_DETECT +#endif #if EXTRUDERS > 3 @@ -210,6 +214,35 @@ static void temp_runaway_check(int _heater_id, float _target_temperature, float static void temp_runaway_stop(bool isPreheat, bool isBed); #endif +#ifdef EXTRUDER_ALTFAN_DETECT +ISR(INT6_vect) { + fan_edge_counter[0]++; +} + +bool extruder_altfan_detect() +{ + setExtruderAutoFanState(3); + + SET_INPUT(TACH_0); + 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(); + extruderFanIsAltfan = fan_speed[0] > 100; + setExtruderAutoFanState(1); + return extruderFanIsAltfan; +} +#endif //EXTRUDER_ALTFAN_DETECT + // return "false", if all extruder-heaters are 'off' (ie. "true", if any heater is 'on') bool checkAllHotends(void) { @@ -239,9 +272,7 @@ bool checkAllHotends(void) const uint8_t safety_check_cycles_count = (extruder < 0) ? 45 : 10; //10 cycles / 20s delay for extruder and 45 cycles / 90s for heatbed float temp_ambient; -#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) +#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) unsigned long extruder_autofan_last_check = _millis(); #endif @@ -289,9 +320,7 @@ bool checkAllHotends(void) max=max(max,input); min=min(min,input); - #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) if(_millis() - extruder_autofan_last_check > 2500) { checkExtruderAutoFans(); extruder_autofan_last_check = _millis(); @@ -447,29 +476,31 @@ int getHeaterPower(int heater) { return soft_pwm[heater]; } -#if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) +#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 - #if EXTRUDER_1_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_1_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #if EXTRUDER_2_AUTO_FAN_PIN == FAN_PIN - #error "You cannot set EXTRUDER_2_AUTO_FAN_PIN equal to FAN_PIN" - #endif - #endif + #endif -void setExtruderAutoFanState(int pin, bool state) +void setExtruderAutoFanState(uint8_t state) { - unsigned char newFanSpeed = (state != 0) ? EXTRUDER_AUTO_FAN_SPEED : 0; - // this idiom allows both digital and PWM fan outputs (see M42 handling). - pinMode(pin, OUTPUT); - digitalWrite(pin, newFanSpeed); - //analogWrite(pin, newFanSpeed); + //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; + uint8_t newFanSpeed = 0; + if (fanState & 0x01) + { +#ifdef EXTRUDER_ALTFAN_DETECT + if (extruderFanIsAltfan) 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))))) @@ -503,7 +534,7 @@ void checkFanSpeed() fans_check_enabled = (eeprom_read_byte((uint8_t*)EEPROM_FAN_CHECK_ENABLED) > 0); static unsigned char fan_speed_errors[2] = { 0,0 }; #if (defined(FANCHECK) && defined(TACH_0) && (TACH_0 >-1)) - if ((fan_speed[0] == 0) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)){ fan_speed_errors[0]++;} + if ((fan_speed[0] < 20) && (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE)){ fan_speed_errors[0]++;} else{ fan_speed_errors[0] = 0; host_keepalive(); @@ -577,47 +608,14 @@ void fanSpeedError(unsigned char _fan) { void checkExtruderAutoFans() { - uint8_t fanState = 0; - - // which fan pins need to be turned on? - #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 - if (current_temperature[0] > EXTRUDER_AUTO_FAN_TEMPERATURE) - fanState |= 1; - #endif - #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 - if (current_temperature[1] > EXTRUDER_AUTO_FAN_TEMPERATURE) - { - if (EXTRUDER_1_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else - fanState |= 2; - } - #endif - #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 - if (current_temperature[2] > EXTRUDER_AUTO_FAN_TEMPERATURE) - { - if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_0_AUTO_FAN_PIN) - fanState |= 1; - else if (EXTRUDER_2_AUTO_FAN_PIN == EXTRUDER_1_AUTO_FAN_PIN) - fanState |= 2; - else - fanState |= 4; - } - #endif - - // update extruder auto fan states - #if defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1 - setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, (fanState & 1) != 0); - #endif - #if defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1 - if (EXTRUDER_1_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_1_AUTO_FAN_PIN, (fanState & 2) != 0); - #endif - #if defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1 - if (EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_0_AUTO_FAN_PIN - && EXTRUDER_2_AUTO_FAN_PIN != EXTRUDER_1_AUTO_FAN_PIN) - setExtruderAutoFanState(EXTRUDER_2_AUTO_FAN_PIN, (fanState & 4) != 0); - #endif +#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 @@ -737,9 +735,7 @@ void manage_heater() #define FAN_CHECK_DURATION 100 //100ms #ifndef DEBUG_DISABLE_FANCHECK - #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_1_AUTO_FAN_PIN) && EXTRUDER_1_AUTO_FAN_PIN > -1) || \ - (defined(EXTRUDER_2_AUTO_FAN_PIN) && EXTRUDER_2_AUTO_FAN_PIN > -1) + #if (defined(EXTRUDER_0_AUTO_FAN_PIN) && EXTRUDER_0_AUTO_FAN_PIN > -1) #ifdef FAN_SOFT_PWM #ifdef FANCHECK @@ -1098,7 +1094,9 @@ void tp_init() timer0_init(); OCR2B = 128; - TIMSK2 |= (1< +#include +#include "pins.h" + +#ifndef CRITICAL_SECTION_START + #define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli(); + #define CRITICAL_SECTION_END SREG = _sreg; +#endif //CRITICAL_SECTION_START + + +#include "fastio.h" + +void timer4_init(void) +{ + CRITICAL_SECTION_START; + + SET_OUTPUT(BEEPER); + WRITE(BEEPER, LOW); + + SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); + + // Set timer mode 9 (PWM,Phase and Frequency Correct) + // Prescaler is CLK/1024 + // Output compare is disabled on all timer pins + // Input capture is disabled + // All interrupts are disabled + TCCR4A = (1 << WGM40); + TCCR4B = (1 << WGM43) | (1 << CS42) | (1 << CS40); + OCR4A = 255; + OCR4B = 255; + OCR4C = 255; + TIMSK4 = 0; + + CRITICAL_SECTION_END; +} + +#ifdef EXTRUDER_0_AUTO_FAN_PIN +void timer4_set_fan0(uint8_t duty) +{ + if (duty == 0 || duty == 255) + { + // We use digital logic if the duty cycle is 0% or 100% + TCCR4A &= ~(1 << COM4C1); + OCR4C = 0; + WRITE(EXTRUDER_0_AUTO_FAN_PIN, duty); + } + else + { + // Use the timer for fan speed. Enable the timer compare output and set the duty cycle. + // This function also handles the impossible scenario of a fan speed change during a Tone. + // Better be safe than sorry. + CRITICAL_SECTION_START; + // Enable the PWM output on the fan pin. + TCCR4A |= (1 << COM4C1); + OCR4C = (((uint32_t)duty) * ((uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255))) / ((uint32_t)255); + CRITICAL_SECTION_END; + } +} +#endif //EXTRUDER_0_AUTO_FAN_PIN + +// Because of the timer mode change, we need two interrupts. We could also try to assume that the frequency is x2 +// and use a TOGGLE(), but this seems to work well enough so I left it as it is now. +ISR(TIMER4_COMPA_vect) +{ + WRITE(BEEPER, 1); +} + +ISR(TIMER4_OVF_vect) +{ + WRITE(BEEPER, 0); +} + +void tone4(__attribute__((unused)) uint8_t _pin, uint16_t frequency) +{ + //this ocr and prescalarbits calculation is taken from the Arduino core and simplified for one type of timer only + uint8_t prescalarbits = 0b001; + uint32_t ocr = F_CPU / frequency / 2 - 1; + + if (ocr > 0xffff) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalarbits = 0b011; + } + + CRITICAL_SECTION_START; + // Set calcualted prescaler + TCCR4B = (TCCR4B & 0b11111000) | prescalarbits; +#ifdef EXTRUDER_0_AUTO_FAN_PIN + // Scale the fan PWM duty cycle so that it remains constant, but at the tone frequency + OCR4C = (((uint32_t)OCR4C) * ocr) / (uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255); +#endif //EXTRUDER_0_AUTO_FAN_PIN + // Set calcualted ocr + OCR4A = ocr; + // Enable Output compare A interrupt and timer overflow interrupt + TIMSK4 |= (1 << OCIE4A) | (1 << TOIE4); + CRITICAL_SECTION_END; +} + +void noTone4(__attribute__((unused)) uint8_t _pin) +{ + CRITICAL_SECTION_START; + // Revert prescaler to CLK/1024 + TCCR4B = (TCCR4B & 0b11111000) | (1 << CS42) | (1 << CS40); +#ifdef EXTRUDER_0_AUTO_FAN_PIN + // Scale the fan OCR back to the original value. + OCR4C = (((uint32_t)OCR4C) * (uint32_t)255) / (uint32_t)((TIMSK4 & (1 << OCIE4A))?OCR4A:255); +#endif //EXTRUDER_0_AUTO_FAN_PIN + OCR4A = 255; + // Disable Output compare A interrupt and timer overflow interrupt + TIMSK4 &= ~((1 << OCIE4A) | (1 << TOIE4)); + CRITICAL_SECTION_END; + // Turn beeper off if it was on when noTone was called + WRITE(BEEPER, 0); +} + + +#endif //SYSTEM_TIMER_2 diff --git a/Firmware/tone04.h b/Firmware/tone04.h new file mode 100644 index 00000000..f11eeb6c --- /dev/null +++ b/Firmware/tone04.h @@ -0,0 +1,25 @@ +//tone04.h +// use atmega timer4 as main tone timer instead of timer2 +// timer2 is used for System timer. +#ifndef TIMER04_H +#define TIMER04_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif //defined(__cplusplus) + +extern void timer4_init(void); + +extern void timer4_set_fan0(uint8_t duty); + +extern void tone4(uint8_t _pin, uint16_t frequency); + +extern void noTone4(uint8_t _pin); + +#if defined(__cplusplus) +} +#endif //defined(__cplusplus) + +#endif //TIMER02_H diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index a9fa50d1..e32b6ad1 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6673,7 +6673,7 @@ static bool fan_error_selftest() fanSpeedSoftPwm = 255; #endif //FAN_SOFT_PWM manage_heater(); //enables print fan - setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //force enables the extruder fan untill the first manage_heater() call. + setExtruderAutoFanState(3); //force enables the extruder fan #ifdef FAN_SOFT_PWM extruder_autofan_last_check = _millis(); fan_measuring = true; @@ -6681,6 +6681,7 @@ static bool fan_error_selftest() _delay(1000); //delay_keep_alive would turn off extruder fan, because temerature is too low (maybe) manage_heater(); fanSpeed = 0; + setExtruderAutoFanState(1); //releases lock on the extruder fan #ifdef FAN_SOFT_PWM fanSpeedSoftPwm = 0; #endif //FAN_SOFT_PWM @@ -8468,8 +8469,7 @@ static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite, lcd_set_cursor(0, 1); if(check_opposite == true) lcd_puts_P(_T(MSG_SELFTEST_COOLING_FAN)); else lcd_puts_P(_T(MSG_SELFTEST_EXTRUDER_FAN)); - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); + setExtruderAutoFanState(3); break; case 1: // object cooling fan @@ -8498,23 +8498,6 @@ static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite, lcd_button_pressed = false; do { - switch (_fan) - { - case 0: - // extruder cooling fan - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1); - break; - case 1: - // object cooling fan - SET_OUTPUT(FAN_PIN); -#ifdef FAN_SOFT_PWM - fanSpeedSoftPwm = 255; -#else //FAN_SOFT_PWM - analogWrite(FAN_PIN, 255); -#endif //FAN_SOFT_PWM - break; - } if (abs((enc_dif - lcd_encoder_diff)) > 2) { if (enc_dif > lcd_encoder_diff) { _result = !check_opposite; @@ -8541,8 +8524,7 @@ static bool lcd_selftest_manual_fan_check(int _fan, bool check_opposite, } while (!lcd_clicked()); KEEPALIVE_STATE(IN_HANDLER); - SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN); - WRITE(EXTRUDER_0_AUTO_FAN_PIN, 0); + setExtruderAutoFanState(0); SET_OUTPUT(FAN_PIN); #ifdef FAN_SOFT_PWM fanSpeedSoftPwm = 0; @@ -8562,13 +8544,13 @@ static FanCheck lcd_selftest_fan_auto(int _fan) case 0: fanSpeed = 0; manage_heater(); //turn off fan - setExtruderAutoFanState(EXTRUDER_0_AUTO_FAN_PIN, 1); //extruder fan + setExtruderAutoFanState(3); //extruder fan #ifdef FAN_SOFT_PWM extruder_autofan_last_check = _millis(); fan_measuring = true; #endif //FAN_SOFT_PWM - _delay(2000); //delay_keep_alive would turn off extruder fan, because temerature is too low - + _delay(2000); + setExtruderAutoFanState(0); //extruder fan manage_heater(); //count average fan speed from 2s delay and turn off fans printf_P(PSTR("Test 1:\n")); diff --git a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h index ad714c23..1179ae6b 100644 --- a/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h +++ b/Firmware/variants/1_75mm_MK3S-EINSy10a-E3Dv6full.h @@ -331,6 +331,8 @@ #define EXTRUDER_2_AUTO_FAN_PIN -1 #define EXTRUDER_AUTO_FAN_TEMPERATURE 50 #define EXTRUDER_AUTO_FAN_SPEED 255 // == full speed +#define EXTRUDER_ALTFAN_DETECT +#define EXTRUDER_ALTFAN_SPEED_SILENT 128