mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-26 21:36:21 +00:00
⚡️ Controller Fan software PWM (etc.) (#23102)
Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
This commit is contained in:
parent
49e233e06f
commit
e0c439fe91
@ -54,8 +54,8 @@ Timer get_pwm_timer(const pin_t pin) {
|
||||
case TIMER1A: case TIMER1B:
|
||||
#endif
|
||||
break;
|
||||
#if defined(TCCR2) || defined(TCCR2A)
|
||||
#ifdef TCCR2
|
||||
#if HAS_TCCR2 || defined(TCCR2A)
|
||||
#if HAS_TCCR2
|
||||
case TIMER2: {
|
||||
Timer timer = {
|
||||
/*TCCRnQ*/ { &TCCR2, nullptr, nullptr },
|
||||
@ -200,16 +200,7 @@ void set_pwm_frequency(const pin_t pin, int f_desired) {
|
||||
res = res_temp_fast;
|
||||
j = i;
|
||||
// Set the Wave Generation Mode to FAST PWM
|
||||
if (timer.n == 2) {
|
||||
wgm = (
|
||||
#if ENABLED(USE_OCR2A_AS_TOP)
|
||||
WGM2_FAST_PWM_OCR2A
|
||||
#else
|
||||
WGM2_FAST_PWM
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else wgm = WGM_FAST_PWM_ICRn;
|
||||
wgm = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM) : WGM_FAST_PWM_ICRn;
|
||||
}
|
||||
// If PHASE CORRECT values are closes to desired f
|
||||
else if (f_phase_diff < f_diff) {
|
||||
@ -217,16 +208,7 @@ void set_pwm_frequency(const pin_t pin, int f_desired) {
|
||||
res = res_temp_phase_correct;
|
||||
j = i;
|
||||
// Set the Wave Generation Mode to PWM PHASE CORRECT
|
||||
if (timer.n == 2) {
|
||||
wgm = (
|
||||
#if ENABLED(USE_OCR2A_AS_TOP)
|
||||
WGM2_PWM_PC_OCR2A
|
||||
#else
|
||||
WGM2_PWM_PC
|
||||
#endif
|
||||
);
|
||||
}
|
||||
else wgm = WGM_PWM_PC_ICRn;
|
||||
wgm = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC) : WGM_PWM_PC_ICRn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -234,9 +216,7 @@ void set_pwm_frequency(const pin_t pin, int f_desired) {
|
||||
_SET_CSn(timer.TCCRnQ, j);
|
||||
|
||||
if (timer.n == 2) {
|
||||
#if ENABLED(USE_OCR2A_AS_TOP)
|
||||
_SET_OCRnQ(timer.OCRnQ, 0, res); // Set OCR2A value (TOP) = res
|
||||
#endif
|
||||
TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer.OCRnQ, 0, res)); // Set OCR2A value (TOP) = res
|
||||
}
|
||||
else
|
||||
_SET_ICRn(timer.ICRn, res); // Set ICRn value (TOP) = res
|
||||
@ -257,15 +237,9 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255
|
||||
Timer timer = get_pwm_timer(pin);
|
||||
if (timer.n == 0) return; // Don't proceed if protected timer or not recognized
|
||||
// Set compare output mode to CLEAR -> SET or SET -> CLEAR (if inverted)
|
||||
_SET_COMnQ(timer.TCCRnQ, (timer.q
|
||||
#ifdef TCCR2
|
||||
+ (timer.q == 2) // COM20 is on bit 4 of TCCR2, thus requires q + 1 in the macro
|
||||
#endif
|
||||
), COM_CLEAR_SET + invert
|
||||
);
|
||||
|
||||
uint16_t top = (timer.n == 2) ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
|
||||
_SET_OCRnQ(timer.OCRnQ, timer.q, (v * top + v_size / 2) / v_size); // Scale 8/16-bit v to top value
|
||||
_SET_COMnQ(timer.TCCRnQ, timer.q TERN_(HAS_TCCR2, + (timer.q == 2)), COM_CLEAR_SET + invert); // COM20 is on bit 4 of TCCR2, so +1 for q==2
|
||||
const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
|
||||
_SET_OCRnQ(timer.OCRnQ, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -211,32 +211,32 @@ enum ClockSource2 : char {
|
||||
|
||||
// Set Clock Select bits
|
||||
// Ex: SET_CS3(PRESCALER_64);
|
||||
#ifdef TCCR2
|
||||
#define HAS_TCCR2 1
|
||||
#endif
|
||||
#define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0))
|
||||
#define _SET_CS0(V) _SET_CS(0,V)
|
||||
#define _SET_CS1(V) _SET_CS(1,V)
|
||||
#ifdef TCCR2
|
||||
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
|
||||
#else
|
||||
#define _SET_CS2(V) _SET_CS(2,V)
|
||||
#endif
|
||||
#define _SET_CS3(V) _SET_CS(3,V)
|
||||
#define _SET_CS4(V) _SET_CS(4,V)
|
||||
#define _SET_CS5(V) _SET_CS(5,V)
|
||||
#define SET_CS0(V) _SET_CS0(CS_##V)
|
||||
#define SET_CS1(V) _SET_CS1(CS_##V)
|
||||
#ifdef TCCR2
|
||||
|
||||
#if HAS_TCCR2
|
||||
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
|
||||
#define SET_CS2(V) _SET_CS2(CS2_##V)
|
||||
#else
|
||||
#define _SET_CS2(V) _SET_CS(2,V)
|
||||
#define SET_CS2(V) _SET_CS2(CS_##V)
|
||||
#endif
|
||||
|
||||
#define SET_CS3(V) _SET_CS3(CS_##V)
|
||||
#define SET_CS4(V) _SET_CS4(CS_##V)
|
||||
#define SET_CS5(V) _SET_CS5(CS_##V)
|
||||
#define SET_CS(T,V) SET_CS##T(V)
|
||||
// Runtime (see set_pwm_frequency)
|
||||
#define _SET_CSn(TCCRnQ, V) do{ \
|
||||
(*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0)); \
|
||||
}while(0)
|
||||
#define _SET_CSn(TCCRnQ, V) (*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0))
|
||||
|
||||
// Set Compare Mode bits
|
||||
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
|
||||
@ -247,21 +247,15 @@ enum ClockSource2 : char {
|
||||
#define SET_COMC(T,V) SET_COM(T,C,V)
|
||||
#define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0)
|
||||
// Runtime (see set_pwm_duty)
|
||||
#define _SET_COMnQ(TCCRnQ, Q, V) do{ \
|
||||
(*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q)))); \
|
||||
}while(0)
|
||||
#define _SET_COMnQ(TCCRnQ, Q, V) (*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q))))
|
||||
|
||||
// Set OCRnQ register
|
||||
// Runtime (see set_pwm_duty):
|
||||
#define _SET_OCRnQ(OCRnQ, Q, V) do{ \
|
||||
(*(OCRnQ)[(Q)] = (0x0000) | (int(V) & 0xFFFF)); \
|
||||
}while(0)
|
||||
#define _SET_OCRnQ(OCRnQ, Q, V) (*(OCRnQ)[Q] = int(V) & 0xFFFF)
|
||||
|
||||
// Set ICRn register (one per timer)
|
||||
// Runtime (see set_pwm_frequency)
|
||||
#define _SET_ICRn(ICRn, V) do{ \
|
||||
(*(ICRn) = (0x0000) | (int(V) & 0xFFFF)); \
|
||||
}while(0)
|
||||
#define _SET_ICRn(ICRn, V) (*(ICRn) = int(V) & 0xFFFF)
|
||||
|
||||
// Set Noise Canceler bit
|
||||
// Ex: SET_ICNC(2,1)
|
||||
|
@ -28,7 +28,7 @@
|
||||
/**
|
||||
* Checks for FAST PWM
|
||||
*/
|
||||
#if ENABLED(FAST_PWM_FAN) && (ENABLED(USE_OCR2A_AS_TOP) && defined(TCCR2))
|
||||
#if ALL(FAST_PWM_FAN, USE_OCR2A_AS_TOP, HAS_TCCR2)
|
||||
#error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2"
|
||||
#endif
|
||||
|
||||
|
@ -102,7 +102,7 @@ void PRINT_ARRAY_NAME(uint8_t x) {
|
||||
return true; \
|
||||
} else return false
|
||||
|
||||
|
||||
#define ABTEST(N) defined(TCCR##N##A) && defined(COM##N##A1)
|
||||
|
||||
/**
|
||||
* Print a pin's PWM status.
|
||||
@ -113,7 +113,7 @@ static bool pwm_status(uint8_t pin) {
|
||||
|
||||
switch (digitalPinToTimer_DEBUG(pin)) {
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0A1)
|
||||
#if ABTEST(0)
|
||||
#ifdef TIMER0A
|
||||
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
|
||||
PWM_CASE(0, A);
|
||||
@ -122,7 +122,7 @@ static bool pwm_status(uint8_t pin) {
|
||||
PWM_CASE(0, B);
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1A1)
|
||||
#if ABTEST(1)
|
||||
PWM_CASE(1, A);
|
||||
PWM_CASE(1, B);
|
||||
#if defined(COM1C1) && defined(TIMER1C)
|
||||
@ -130,12 +130,12 @@ static bool pwm_status(uint8_t pin) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
#if ABTEST(2)
|
||||
PWM_CASE(2, A);
|
||||
PWM_CASE(2, B);
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
#if ABTEST(3)
|
||||
PWM_CASE(3, A);
|
||||
PWM_CASE(3, B);
|
||||
#ifdef COM3C1
|
||||
@ -149,7 +149,7 @@ static bool pwm_status(uint8_t pin) {
|
||||
PWM_CASE(4, C);
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5A1)
|
||||
#if ABTEST(5)
|
||||
PWM_CASE(5, A);
|
||||
PWM_CASE(5, B);
|
||||
PWM_CASE(5, C);
|
||||
@ -166,16 +166,16 @@ static bool pwm_status(uint8_t pin) {
|
||||
const volatile uint8_t* const PWM_other[][3] PROGMEM = {
|
||||
{ &TCCR0A, &TCCR0B, &TIMSK0 },
|
||||
{ &TCCR1A, &TCCR1B, &TIMSK1 },
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
#if ABTEST(2)
|
||||
{ &TCCR2A, &TCCR2B, &TIMSK2 },
|
||||
#endif
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
#if ABTEST(3)
|
||||
{ &TCCR3A, &TCCR3B, &TIMSK3 },
|
||||
#endif
|
||||
#ifdef TCCR4A
|
||||
{ &TCCR4A, &TCCR4B, &TIMSK4 },
|
||||
#endif
|
||||
#if defined(TCCR5A) && defined(COM5A1)
|
||||
#if ABTEST(5)
|
||||
{ &TCCR5A, &TCCR5B, &TIMSK5 },
|
||||
#endif
|
||||
};
|
||||
@ -195,11 +195,11 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
|
||||
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, 0 },
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
#if ABTEST(2)
|
||||
{ &OCR2A, &OCR2B, 0 },
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
#if ABTEST(3)
|
||||
#ifdef COM3C1
|
||||
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, (const uint8_t*)&OCR3C },
|
||||
#else
|
||||
@ -211,7 +211,7 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
|
||||
{ (const uint8_t*)&OCR4A, (const uint8_t*)&OCR4B, (const uint8_t*)&OCR4C },
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5A1)
|
||||
#if ABTEST(5)
|
||||
{ (const uint8_t*)&OCR5A, (const uint8_t*)&OCR5B, (const uint8_t*)&OCR5C },
|
||||
#endif
|
||||
};
|
||||
@ -281,7 +281,7 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
|
||||
static void pwm_details(uint8_t pin) {
|
||||
switch (digitalPinToTimer_DEBUG(pin)) {
|
||||
|
||||
#if defined(TCCR0A) && defined(COM0A1)
|
||||
#if ABTEST(0)
|
||||
#ifdef TIMER0A
|
||||
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
|
||||
case TIMER0A: timer_prefix(0, 'A', 3); break;
|
||||
@ -290,7 +290,7 @@ static void pwm_details(uint8_t pin) {
|
||||
case TIMER0B: timer_prefix(0, 'B', 3); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR1A) && defined(COM1A1)
|
||||
#if ABTEST(1)
|
||||
case TIMER1A: timer_prefix(1, 'A', 4); break;
|
||||
case TIMER1B: timer_prefix(1, 'B', 4); break;
|
||||
#if defined(COM1C1) && defined(TIMER1C)
|
||||
@ -298,12 +298,12 @@ static void pwm_details(uint8_t pin) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(TCCR2A) && defined(COM2A1)
|
||||
#if ABTEST(2)
|
||||
case TIMER2A: timer_prefix(2, 'A', 3); break;
|
||||
case TIMER2B: timer_prefix(2, 'B', 3); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR3A) && defined(COM3A1)
|
||||
#if ABTEST(3)
|
||||
case TIMER3A: timer_prefix(3, 'A', 4); break;
|
||||
case TIMER3B: timer_prefix(3, 'B', 4); break;
|
||||
#ifdef COM3C1
|
||||
@ -317,7 +317,7 @@ static void pwm_details(uint8_t pin) {
|
||||
case TIMER4C: timer_prefix(4, 'C', 4); break;
|
||||
#endif
|
||||
|
||||
#if defined(TCCR5A) && defined(COM5A1)
|
||||
#if ABTEST(5)
|
||||
case TIMER5A: timer_prefix(5, 'A', 4); break;
|
||||
case TIMER5B: timer_prefix(5, 'B', 4); break;
|
||||
case TIMER5C: timer_prefix(5, 'C', 4); break;
|
||||
@ -351,7 +351,6 @@ static void pwm_details(uint8_t pin) {
|
||||
#endif
|
||||
} // pwm_details
|
||||
|
||||
|
||||
#ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs
|
||||
int digitalRead_mod(const int8_t pin) { // same as digitalRead except the PWM stop section has been removed
|
||||
const uint8_t port = digitalPinToPort_DEBUG(pin);
|
||||
@ -397,3 +396,5 @@ static void pwm_details(uint8_t pin) {
|
||||
|
||||
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0)
|
||||
#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0)
|
||||
|
||||
#undef ABTEST
|
||||
|
@ -72,10 +72,14 @@ void ControllerFan::update() {
|
||||
? settings.active_speed : settings.idle_speed
|
||||
);
|
||||
|
||||
#if ENABLED(FAN_SOFT_PWM)
|
||||
thermalManager.soft_pwm_controller_speed = speed;
|
||||
#else
|
||||
if (PWM_PIN(CONTROLLER_FAN_PIN))
|
||||
set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed);
|
||||
else
|
||||
WRITE(CONTROLLER_FAN_PIN, speed);
|
||||
WRITE(CONTROLLER_FAN_PIN, speed > 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,10 +266,10 @@ void menu_advanced_settings();
|
||||
void menu_controller_fan() {
|
||||
START_MENU();
|
||||
BACK_ITEM(MSG_CONFIGURATION);
|
||||
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_IDLE_SPEED, &controllerFan.settings.idle_speed, _MAX(1, CONTROLLERFAN_SPEED_MIN) - 1, 255);
|
||||
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_IDLE_SPEED, &controllerFan.settings.idle_speed, CONTROLLERFAN_SPEED_MIN, 255);
|
||||
EDIT_ITEM(bool, MSG_CONTROLLER_FAN_AUTO_ON, &controllerFan.settings.auto_mode);
|
||||
if (controllerFan.settings.auto_mode) {
|
||||
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_SPEED, &controllerFan.settings.active_speed, _MAX(1, CONTROLLERFAN_SPEED_MIN) - 1, 255);
|
||||
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_SPEED, &controllerFan.settings.active_speed, CONTROLLERFAN_SPEED_MIN, 255);
|
||||
EDIT_ITEM(uint16_4, MSG_CONTROLLER_FAN_DURATION, &controllerFan.settings.duration, 0, 4800);
|
||||
}
|
||||
END_MENU();
|
||||
|
@ -41,6 +41,10 @@
|
||||
#include "../feature/spindle_laser.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(USE_CONTROLLER_FAN)
|
||||
#include "../feature/controllerfan.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(EMERGENCY_PARSER)
|
||||
#include "motion.h"
|
||||
#endif
|
||||
@ -302,6 +306,10 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED);
|
||||
uint8_t Temperature::coolerfan_speed; // = 0
|
||||
#endif
|
||||
|
||||
#if BOTH(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
|
||||
uint8_t Temperature::soft_pwm_controller_speed;
|
||||
#endif
|
||||
|
||||
// Init fans according to whether they're native PWM or Software PWM
|
||||
#ifdef BOARD_OPENDRAIN_MOSFETS
|
||||
#define _INIT_SOFT_FAN(P) OUT_WRITE_OD(P, FAN_INVERTING ? LOW : HIGH)
|
||||
@ -3021,6 +3029,10 @@ void Temperature::isr() {
|
||||
static SoftPWM soft_pwm_cooler;
|
||||
#endif
|
||||
|
||||
#if BOTH(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
|
||||
static SoftPWM soft_pwm_controller;
|
||||
#endif
|
||||
|
||||
#define WRITE_FAN(n, v) WRITE(FAN##n##_PIN, (v) ^ FAN_INVERTING)
|
||||
|
||||
#if DISABLED(SLOW_PWM_HEATERS)
|
||||
@ -3056,6 +3068,10 @@ void Temperature::isr() {
|
||||
_PWM_MOD(COOLER, soft_pwm_cooler, temp_cooler);
|
||||
#endif
|
||||
|
||||
#if BOTH(USE_CONTROLLER_FAN, FAN_SOFT_PWM)
|
||||
WRITE(CONTROLLER_FAN_PIN, soft_pwm_controller.add(pwm_mask, soft_pwm_controller_speed));
|
||||
#endif
|
||||
|
||||
#if ENABLED(FAN_SOFT_PWM)
|
||||
#define _FAN_PWM(N) do{ \
|
||||
uint8_t &spcf = soft_pwm_count_fan[N]; \
|
||||
@ -3132,6 +3148,9 @@ void Temperature::isr() {
|
||||
#if HAS_FAN7
|
||||
if (soft_pwm_count_fan[7] <= pwm_count_tmp) WRITE_FAN(7, LOW);
|
||||
#endif
|
||||
#if ENABLED(USE_CONTROLLER_FAN)
|
||||
if (soft_pwm_controller.count <= pwm_count_tmp) WRITE(CONTROLLER_FAN_PIN, LOW);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -387,6 +387,10 @@ class Temperature {
|
||||
soft_pwm_count_fan[FAN_COUNT];
|
||||
#endif
|
||||
|
||||
#if BOTH(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
|
||||
static uint8_t soft_pwm_controller_speed;
|
||||
#endif
|
||||
|
||||
#if ENABLED(PREVENT_COLD_EXTRUSION)
|
||||
static bool allow_cold_extrude;
|
||||
static celsius_t extrude_min_temp;
|
||||
|
Loading…
Reference in New Issue
Block a user