ALTFAN implementation (#2692)

* ALTFAN implementation

* Use CRITICAL_SECTION macros

* Use uint16_t instead of unsigned int

* Add forgotten CRITICAL_SECTION

* Documentation
This commit is contained in:
Alex Voinea 2020-06-01 18:58:15 +03:00 committed by GitHub
parent eb44ee0f57
commit 751f810dd7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 256 additions and 109 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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<<OCIE2B);
TIMSK2 |= (1<<OCIE2B);
timer4_init(); //for tone and Extruder fan PWM
// Wait for temperature measurement to settle
_delay(250);
@ -1357,9 +1355,11 @@ void temp_runaway_stop(bool isPreheat, bool isBed)
isBed ? LCD_ALERTMESSAGEPGM("BED PREHEAT ERROR") : LCD_ALERTMESSAGEPGM("PREHEAT ERROR");
SERIAL_ERROR_START;
isBed ? SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HEATBED)") : SERIAL_ERRORLNPGM(" THERMAL RUNAWAY ( PREHEAT HOTEND)");
SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
#ifdef EXTRUDER_ALTFAN_DETECT
extruderFanIsAltfan = false; //full speed
#endif //EXTRUDER_ALTFAN_DETECT
setExtruderAutoFanState(3);
SET_OUTPUT(FAN_PIN);
WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
#ifdef FAN_SOFT_PWM
fanSpeedSoftPwm = 255;
#else //FAN_SOFT_PWM
@ -1441,12 +1441,14 @@ void max_temp_error(uint8_t e) {
#endif
SET_OUTPUT(EXTRUDER_0_AUTO_FAN_PIN);
SET_OUTPUT(FAN_PIN);
SET_OUTPUT(BEEPER);
WRITE(FAN_PIN, 1);
WRITE(EXTRUDER_0_AUTO_FAN_PIN, 1);
WRITE(BEEPER, 1);
#ifdef EXTRUDER_ALTFAN_DETECT
extruderFanIsAltfan = false; //full speed
#endif //EXTRUDER_ALTFAN_DETECT
setExtruderAutoFanState(3);
// fanSpeed will consumed by the check_axes_activity() routine.
fanSpeed=255;
if (farm_mode) { prusa_statistics(93); }

View File

@ -245,7 +245,7 @@ FORCE_INLINE void autotempShutdown(){
void PID_autotune(float temp, int extruder, int ncycles);
void setExtruderAutoFanState(int pin, bool state);
void setExtruderAutoFanState(uint8_t state);
void checkExtruderAutoFans();
@ -270,10 +270,12 @@ void check_fans();
void check_min_temp();
void check_max_temp();
#endif
#ifdef EXTRUDER_ALTFAN_DETECT
extern bool extruder_altfan_detect();
#endif //EXTRUDER_ALTFAN_DETECT
extern unsigned long extruder_autofan_last_check;
extern uint8_t fanSpeedBckp;
extern bool fan_measuring;
#endif

126
Firmware/tone04.c Normal file
View File

@ -0,0 +1,126 @@
//tone04.c
// use atmega timer4 as main tone timer instead of timer2
// timer2 is used for System timer.
#include "system_timer.h"
#include "Configuration_prusa.h"
#ifdef SYSTEM_TIMER_2
#include <avr/io.h>
#include <avr/interrupt.h>
#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

25
Firmware/tone04.h Normal file
View File

@ -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 <inttypes.h>
#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

View File

@ -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"));

View File

@ -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