Skip to content

Commit 8ee368b

Browse files
⚡️ Controller Fan software PWM (etc.) (#23102)
Co-authored-by: Scott Lahteine <[email protected]>
1 parent 5fa4631 commit 8ee368b

File tree

8 files changed

+76
-80
lines changed

8 files changed

+76
-80
lines changed

Marlin/src/HAL/AVR/fast_pwm.cpp

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ Timer get_pwm_timer(const pin_t pin) {
5454
case TIMER1A: case TIMER1B:
5555
#endif
5656
break;
57-
#if defined(TCCR2) || defined(TCCR2A)
58-
#ifdef TCCR2
57+
#if HAS_TCCR2 || defined(TCCR2A)
58+
#if HAS_TCCR2
5959
case TIMER2: {
6060
Timer timer = {
6161
/*TCCRnQ*/ { &TCCR2, nullptr, nullptr },
@@ -200,43 +200,23 @@ void set_pwm_frequency(const pin_t pin, int f_desired) {
200200
res = res_temp_fast;
201201
j = i;
202202
// Set the Wave Generation Mode to FAST PWM
203-
if (timer.n == 2) {
204-
wgm = (
205-
#if ENABLED(USE_OCR2A_AS_TOP)
206-
WGM2_FAST_PWM_OCR2A
207-
#else
208-
WGM2_FAST_PWM
209-
#endif
210-
);
211-
}
212-
else wgm = WGM_FAST_PWM_ICRn;
203+
wgm = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM) : WGM_FAST_PWM_ICRn;
213204
}
214205
// If PHASE CORRECT values are closes to desired f
215206
else if (f_phase_diff < f_diff) {
216207
f = f_temp_phase_correct;
217208
res = res_temp_phase_correct;
218209
j = i;
219210
// Set the Wave Generation Mode to PWM PHASE CORRECT
220-
if (timer.n == 2) {
221-
wgm = (
222-
#if ENABLED(USE_OCR2A_AS_TOP)
223-
WGM2_PWM_PC_OCR2A
224-
#else
225-
WGM2_PWM_PC
226-
#endif
227-
);
228-
}
229-
else wgm = WGM_PWM_PC_ICRn;
211+
wgm = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC) : WGM_PWM_PC_ICRn;
230212
}
231213
}
232214
}
233215
_SET_WGMnQ(timer.TCCRnQ, wgm);
234216
_SET_CSn(timer.TCCRnQ, j);
235217

236218
if (timer.n == 2) {
237-
#if ENABLED(USE_OCR2A_AS_TOP)
238-
_SET_OCRnQ(timer.OCRnQ, 0, res); // Set OCR2A value (TOP) = res
239-
#endif
219+
TERN_(USE_OCR2A_AS_TOP, _SET_OCRnQ(timer.OCRnQ, 0, res)); // Set OCR2A value (TOP) = res
240220
}
241221
else
242222
_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
257237
Timer timer = get_pwm_timer(pin);
258238
if (timer.n == 0) return; // Don't proceed if protected timer or not recognized
259239
// Set compare output mode to CLEAR -> SET or SET -> CLEAR (if inverted)
260-
_SET_COMnQ(timer.TCCRnQ, (timer.q
261-
#ifdef TCCR2
262-
+ (timer.q == 2) // COM20 is on bit 4 of TCCR2, thus requires q + 1 in the macro
263-
#endif
264-
), COM_CLEAR_SET + invert
265-
);
266-
267-
uint16_t top = (timer.n == 2) ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
268-
_SET_OCRnQ(timer.OCRnQ, timer.q, (v * top + v_size / 2) / v_size); // Scale 8/16-bit v to top value
240+
_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
241+
const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
242+
_SET_OCRnQ(timer.OCRnQ, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value
269243
}
270244

271245
#else

Marlin/src/HAL/AVR/fastio.h

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -211,32 +211,32 @@ enum ClockSource2 : char {
211211

212212
// Set Clock Select bits
213213
// Ex: SET_CS3(PRESCALER_64);
214+
#ifdef TCCR2
215+
#define HAS_TCCR2 1
216+
#endif
214217
#define _SET_CS(T,V) (TCCR##T##B = (TCCR##T##B & ~(0x7 << CS##T##0)) | ((int(V) & 0x7) << CS##T##0))
215218
#define _SET_CS0(V) _SET_CS(0,V)
216219
#define _SET_CS1(V) _SET_CS(1,V)
217-
#ifdef TCCR2
218-
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
219-
#else
220-
#define _SET_CS2(V) _SET_CS(2,V)
221-
#endif
222220
#define _SET_CS3(V) _SET_CS(3,V)
223221
#define _SET_CS4(V) _SET_CS(4,V)
224222
#define _SET_CS5(V) _SET_CS(5,V)
225223
#define SET_CS0(V) _SET_CS0(CS_##V)
226224
#define SET_CS1(V) _SET_CS1(CS_##V)
227-
#ifdef TCCR2
225+
226+
#if HAS_TCCR2
227+
#define _SET_CS2(V) (TCCR2 = (TCCR2 & ~(0x7 << CS20)) | (int(V) << CS20))
228228
#define SET_CS2(V) _SET_CS2(CS2_##V)
229229
#else
230+
#define _SET_CS2(V) _SET_CS(2,V)
230231
#define SET_CS2(V) _SET_CS2(CS_##V)
231232
#endif
233+
232234
#define SET_CS3(V) _SET_CS3(CS_##V)
233235
#define SET_CS4(V) _SET_CS4(CS_##V)
234236
#define SET_CS5(V) _SET_CS5(CS_##V)
235237
#define SET_CS(T,V) SET_CS##T(V)
236238
// Runtime (see set_pwm_frequency)
237-
#define _SET_CSn(TCCRnQ, V) do{ \
238-
(*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0)); \
239-
}while(0)
239+
#define _SET_CSn(TCCRnQ, V) (*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0))
240240

241241
// Set Compare Mode bits
242242
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
@@ -247,21 +247,15 @@ enum ClockSource2 : char {
247247
#define SET_COMC(T,V) SET_COM(T,C,V)
248248
#define SET_COMS(T,V1,V2,V3) do{ SET_COMA(T,V1); SET_COMB(T,V2); SET_COMC(T,V3); }while(0)
249249
// Runtime (see set_pwm_duty)
250-
#define _SET_COMnQ(TCCRnQ, Q, V) do{ \
251-
(*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q)))); \
252-
}while(0)
250+
#define _SET_COMnQ(TCCRnQ, Q, V) (*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << (6-2*(Q)))) | (int(V) << (6-2*(Q))))
253251

254252
// Set OCRnQ register
255253
// Runtime (see set_pwm_duty):
256-
#define _SET_OCRnQ(OCRnQ, Q, V) do{ \
257-
(*(OCRnQ)[(Q)] = (0x0000) | (int(V) & 0xFFFF)); \
258-
}while(0)
254+
#define _SET_OCRnQ(OCRnQ, Q, V) (*(OCRnQ)[Q] = int(V) & 0xFFFF)
259255

260256
// Set ICRn register (one per timer)
261257
// Runtime (see set_pwm_frequency)
262-
#define _SET_ICRn(ICRn, V) do{ \
263-
(*(ICRn) = (0x0000) | (int(V) & 0xFFFF)); \
264-
}while(0)
258+
#define _SET_ICRn(ICRn, V) (*(ICRn) = int(V) & 0xFFFF)
265259

266260
// Set Noise Canceler bit
267261
// Ex: SET_ICNC(2,1)

Marlin/src/HAL/AVR/inc/SanityCheck.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
/**
2929
* Checks for FAST PWM
3030
*/
31-
#if ENABLED(FAST_PWM_FAN) && (ENABLED(USE_OCR2A_AS_TOP) && defined(TCCR2))
31+
#if ALL(FAST_PWM_FAN, USE_OCR2A_AS_TOP, HAS_TCCR2)
3232
#error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2"
3333
#endif
3434

Marlin/src/HAL/AVR/pinsDebug.h

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ void PRINT_ARRAY_NAME(uint8_t x) {
102102
return true; \
103103
} else return false
104104

105-
105+
#define ABTEST(N) defined(TCCR##N##A) && defined(COM##N##A1)
106106

107107
/**
108108
* Print a pin's PWM status.
@@ -113,7 +113,7 @@ static bool pwm_status(uint8_t pin) {
113113

114114
switch (digitalPinToTimer_DEBUG(pin)) {
115115

116-
#if defined(TCCR0A) && defined(COM0A1)
116+
#if ABTEST(0)
117117
#ifdef TIMER0A
118118
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
119119
PWM_CASE(0, A);
@@ -122,20 +122,20 @@ static bool pwm_status(uint8_t pin) {
122122
PWM_CASE(0, B);
123123
#endif
124124

125-
#if defined(TCCR1A) && defined(COM1A1)
125+
#if ABTEST(1)
126126
PWM_CASE(1, A);
127127
PWM_CASE(1, B);
128-
#if defined(COM1C1) && defined(TIMER1C)
129-
PWM_CASE(1, C);
130-
#endif
128+
#if defined(COM1C1) && defined(TIMER1C)
129+
PWM_CASE(1, C);
130+
#endif
131131
#endif
132132

133-
#if defined(TCCR2A) && defined(COM2A1)
133+
#if ABTEST(2)
134134
PWM_CASE(2, A);
135135
PWM_CASE(2, B);
136136
#endif
137137

138-
#if defined(TCCR3A) && defined(COM3A1)
138+
#if ABTEST(3)
139139
PWM_CASE(3, A);
140140
PWM_CASE(3, B);
141141
#ifdef COM3C1
@@ -149,7 +149,7 @@ static bool pwm_status(uint8_t pin) {
149149
PWM_CASE(4, C);
150150
#endif
151151

152-
#if defined(TCCR5A) && defined(COM5A1)
152+
#if ABTEST(5)
153153
PWM_CASE(5, A);
154154
PWM_CASE(5, B);
155155
PWM_CASE(5, C);
@@ -166,16 +166,16 @@ static bool pwm_status(uint8_t pin) {
166166
const volatile uint8_t* const PWM_other[][3] PROGMEM = {
167167
{ &TCCR0A, &TCCR0B, &TIMSK0 },
168168
{ &TCCR1A, &TCCR1B, &TIMSK1 },
169-
#if defined(TCCR2A) && defined(COM2A1)
169+
#if ABTEST(2)
170170
{ &TCCR2A, &TCCR2B, &TIMSK2 },
171171
#endif
172-
#if defined(TCCR3A) && defined(COM3A1)
172+
#if ABTEST(3)
173173
{ &TCCR3A, &TCCR3B, &TIMSK3 },
174174
#endif
175175
#ifdef TCCR4A
176176
{ &TCCR4A, &TCCR4B, &TIMSK4 },
177177
#endif
178-
#if defined(TCCR5A) && defined(COM5A1)
178+
#if ABTEST(5)
179179
{ &TCCR5A, &TCCR5B, &TIMSK5 },
180180
#endif
181181
};
@@ -195,11 +195,11 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
195195
{ (const uint8_t*)&OCR1A, (const uint8_t*)&OCR1B, 0 },
196196
#endif
197197

198-
#if defined(TCCR2A) && defined(COM2A1)
198+
#if ABTEST(2)
199199
{ &OCR2A, &OCR2B, 0 },
200200
#endif
201201

202-
#if defined(TCCR3A) && defined(COM3A1)
202+
#if ABTEST(3)
203203
#ifdef COM3C1
204204
{ (const uint8_t*)&OCR3A, (const uint8_t*)&OCR3B, (const uint8_t*)&OCR3C },
205205
#else
@@ -211,7 +211,7 @@ const volatile uint8_t* const PWM_OCR[][3] PROGMEM = {
211211
{ (const uint8_t*)&OCR4A, (const uint8_t*)&OCR4B, (const uint8_t*)&OCR4C },
212212
#endif
213213

214-
#if defined(TCCR5A) && defined(COM5A1)
214+
#if ABTEST(5)
215215
{ (const uint8_t*)&OCR5A, (const uint8_t*)&OCR5B, (const uint8_t*)&OCR5C },
216216
#endif
217217
};
@@ -281,7 +281,7 @@ void timer_prefix(uint8_t T, char L, uint8_t N) { // T - timer L - pwm N -
281281
static void pwm_details(uint8_t pin) {
282282
switch (digitalPinToTimer_DEBUG(pin)) {
283283

284-
#if defined(TCCR0A) && defined(COM0A1)
284+
#if ABTEST(0)
285285
#ifdef TIMER0A
286286
#if !AVR_AT90USB1286_FAMILY // not available in Teensyduino type IDEs
287287
case TIMER0A: timer_prefix(0, 'A', 3); break;
@@ -290,20 +290,20 @@ static void pwm_details(uint8_t pin) {
290290
case TIMER0B: timer_prefix(0, 'B', 3); break;
291291
#endif
292292

293-
#if defined(TCCR1A) && defined(COM1A1)
293+
#if ABTEST(1)
294294
case TIMER1A: timer_prefix(1, 'A', 4); break;
295295
case TIMER1B: timer_prefix(1, 'B', 4); break;
296296
#if defined(COM1C1) && defined(TIMER1C)
297297
case TIMER1C: timer_prefix(1, 'C', 4); break;
298298
#endif
299299
#endif
300300

301-
#if defined(TCCR2A) && defined(COM2A1)
301+
#if ABTEST(2)
302302
case TIMER2A: timer_prefix(2, 'A', 3); break;
303303
case TIMER2B: timer_prefix(2, 'B', 3); break;
304304
#endif
305305

306-
#if defined(TCCR3A) && defined(COM3A1)
306+
#if ABTEST(3)
307307
case TIMER3A: timer_prefix(3, 'A', 4); break;
308308
case TIMER3B: timer_prefix(3, 'B', 4); break;
309309
#ifdef COM3C1
@@ -317,7 +317,7 @@ static void pwm_details(uint8_t pin) {
317317
case TIMER4C: timer_prefix(4, 'C', 4); break;
318318
#endif
319319

320-
#if defined(TCCR5A) && defined(COM5A1)
320+
#if ABTEST(5)
321321
case TIMER5A: timer_prefix(5, 'A', 4); break;
322322
case TIMER5B: timer_prefix(5, 'B', 4); break;
323323
case TIMER5C: timer_prefix(5, 'C', 4); break;
@@ -351,7 +351,6 @@ static void pwm_details(uint8_t pin) {
351351
#endif
352352
} // pwm_details
353353

354-
355354
#ifndef digitalRead_mod // Use Teensyduino's version of digitalRead - it doesn't disable the PWMs
356355
int digitalRead_mod(const int8_t pin) { // same as digitalRead except the PWM stop section has been removed
357356
const uint8_t port = digitalPinToPort_DEBUG(pin);
@@ -397,3 +396,5 @@ static void pwm_details(uint8_t pin) {
397396

398397
#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0)
399398
#define PRINT_PIN_ANALOG(p) do{ sprintf_P(buffer, PSTR(" (A%2d) "), DIGITAL_PIN_TO_ANALOG_PIN(pin)); SERIAL_ECHO(buffer); }while(0)
399+
400+
#undef ABTEST

Marlin/src/feature/controllerfan.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,14 @@ void ControllerFan::update() {
7272
? settings.active_speed : settings.idle_speed
7373
);
7474

75-
if (PWM_PIN(CONTROLLER_FAN_PIN))
76-
set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed);
77-
else
78-
WRITE(CONTROLLER_FAN_PIN, speed);
75+
#if ENABLED(FAN_SOFT_PWM)
76+
thermalManager.soft_pwm_controller_speed = speed;
77+
#else
78+
if (PWM_PIN(CONTROLLER_FAN_PIN))
79+
set_pwm_duty(pin_t(CONTROLLER_FAN_PIN), speed);
80+
else
81+
WRITE(CONTROLLER_FAN_PIN, speed > 0);
82+
#endif
7983
}
8084
}
8185

Marlin/src/lcd/menu/menu_configuration.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,10 +266,10 @@ void menu_advanced_settings();
266266
void menu_controller_fan() {
267267
START_MENU();
268268
BACK_ITEM(MSG_CONFIGURATION);
269-
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_IDLE_SPEED, &controllerFan.settings.idle_speed, _MAX(1, CONTROLLERFAN_SPEED_MIN) - 1, 255);
269+
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_IDLE_SPEED, &controllerFan.settings.idle_speed, CONTROLLERFAN_SPEED_MIN, 255);
270270
EDIT_ITEM(bool, MSG_CONTROLLER_FAN_AUTO_ON, &controllerFan.settings.auto_mode);
271271
if (controllerFan.settings.auto_mode) {
272-
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_SPEED, &controllerFan.settings.active_speed, _MAX(1, CONTROLLERFAN_SPEED_MIN) - 1, 255);
272+
EDIT_ITEM_FAST(percent, MSG_CONTROLLER_FAN_SPEED, &controllerFan.settings.active_speed, CONTROLLERFAN_SPEED_MIN, 255);
273273
EDIT_ITEM(uint16_4, MSG_CONTROLLER_FAN_DURATION, &controllerFan.settings.duration, 0, 4800);
274274
}
275275
END_MENU();

Marlin/src/module/temperature.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
#include "../feature/spindle_laser.h"
4242
#endif
4343

44+
#if ENABLED(USE_CONTROLLER_FAN)
45+
#include "../feature/controllerfan.h"
46+
#endif
47+
4448
#if ENABLED(EMERGENCY_PARSER)
4549
#include "motion.h"
4650
#endif
@@ -302,6 +306,10 @@ PGMSTR(str_t_heating_failed, STR_T_HEATING_FAILED);
302306
uint8_t Temperature::coolerfan_speed; // = 0
303307
#endif
304308

309+
#if BOTH(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
310+
uint8_t Temperature::soft_pwm_controller_speed;
311+
#endif
312+
305313
// Init fans according to whether they're native PWM or Software PWM
306314
#ifdef BOARD_OPENDRAIN_MOSFETS
307315
#define _INIT_SOFT_FAN(P) OUT_WRITE_OD(P, FAN_INVERTING ? LOW : HIGH)
@@ -3021,6 +3029,10 @@ void Temperature::isr() {
30213029
static SoftPWM soft_pwm_cooler;
30223030
#endif
30233031

3032+
#if BOTH(FAN_SOFT_PWM, USE_CONTROLLER_FAN)
3033+
static SoftPWM soft_pwm_controller;
3034+
#endif
3035+
30243036
#define WRITE_FAN(n, v) WRITE(FAN##n##_PIN, (v) ^ FAN_INVERTING)
30253037

30263038
#if DISABLED(SLOW_PWM_HEATERS)
@@ -3056,6 +3068,10 @@ void Temperature::isr() {
30563068
_PWM_MOD(COOLER, soft_pwm_cooler, temp_cooler);
30573069
#endif
30583070

3071+
#if BOTH(USE_CONTROLLER_FAN, FAN_SOFT_PWM)
3072+
WRITE(CONTROLLER_FAN_PIN, soft_pwm_controller.add(pwm_mask, soft_pwm_controller_speed));
3073+
#endif
3074+
30593075
#if ENABLED(FAN_SOFT_PWM)
30603076
#define _FAN_PWM(N) do{ \
30613077
uint8_t &spcf = soft_pwm_count_fan[N]; \
@@ -3132,6 +3148,9 @@ void Temperature::isr() {
31323148
#if HAS_FAN7
31333149
if (soft_pwm_count_fan[7] <= pwm_count_tmp) WRITE_FAN(7, LOW);
31343150
#endif
3151+
#if ENABLED(USE_CONTROLLER_FAN)
3152+
if (soft_pwm_controller.count <= pwm_count_tmp) WRITE(CONTROLLER_FAN_PIN, LOW);
3153+
#endif
31353154
#endif
31363155
}
31373156

0 commit comments

Comments
 (0)