Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows user to set (almost) any PWM frequency #12638

Merged
merged 3 commits into from
Mar 8, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,33 @@
//#define FAN_MIN_PWM 50
//#define FAN_MAX_PWM 128

/**
* FAST PWM FAN Settings
*
* Use to change the FAST FAN PWM frequency (if enabled in Configuration.h)
* Combinations of PWM Modes, prescale values and TOP resolutions are used internally to produce a
* frequency as close as possible to the desired frequency.
*
* FAST_PWM_FAN_FREQUENCY [undefined by default]
* Set this to your desired frequency.
* If left undefined this defaults to F = F_CPU/(2*255*1)
* ie F = 31.4 Khz on 16 MHz microcontrollers or F = 39.2 KHz on 20 MHz microcontrollers
* These defaults are the same as with the old FAST_PWM_FAN implementation - no migration is required
* NOTE: Setting very low frequencies (< 10 Hz) may result in unexpected timer behaviour.
*
* USE_OCR2A_AS_TOP [undefined by default]
* Boards that use TIMER2 for PWM have limitations resulting in only a few possible frequencies on TIMER2:
* 16MHz MCUs: [62.5KHz, 31.4KHz (default), 7.8KHz, 3.92KHz, 1.95KHz, 977Hz, 488Hz, 244Hz, 60Hz, 122Hz, 30Hz]
* 20MHz MCUs: [78.1KHz, 39.2KHz (default), 9.77KHz, 4.9KHz, 2.44KHz, 1.22KHz, 610Hz, 305Hz, 153Hz, 76Hz, 38Hz]
* A greater range can be achieved by enabling USE_OCR2A_AS_TOP. But note that this option blocks the use of
* PWM on pin OC2A. Only use this option if you don't need PWM on 0C2A. (Check your schematic.)
* USE_OCR2A_AS_TOP sacrifices duty cycle control resolution to achieve this broader range of frequencies.
*/
#if ENABLED(FAST_PWM_FAN)
//#define FAST_PWM_FAN_FREQUENCY 31400
//#define USE_OCR2A_AS_TOP
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not in favor if this USE_OCR2A_AS_TOP setting. For one thing, it only applies to AVR. This option should be replaced by some kind of automated method to detect whether this would be the best thing to do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it isn't ideal, but think it would be difficult for the software to make this choice for the user. Because TIMER2 is an 8-bit timer, the user will start to see significant drops in PWM control resolution (below the standard 0-255) to achieve their desired frequency. The user also loses timing capabilities on one of the TIMER2 outputs. Since this is a significant trade-off, I made it a user decision. Also, about it only applying to AVR - i'm not sure why you mention that when the majority of this feature would have to change to work with other micros.

#endif

// @section extruder

/**
Expand Down
7 changes: 7 additions & 0 deletions Marlin/src/HAL/HAL_AVR/SanityCheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@
#endif
#endif

/**
* Checks for FAST PWM
*/
#if ENABLED(FAST_PWM_FAN) && (ENABLED(USE_OCR2A_AS_TOP) && defined(TCCR2))
#error "USE_OCR2A_AS_TOP does not apply to devices with a single output TIMER2"
#endif

/**
* Sanity checks for Spindle / Laser
*/
Expand Down
37 changes: 37 additions & 0 deletions Marlin/src/HAL/HAL_AVR/fastio_AVR.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ enum WaveGenMode : char {
WGM_FAST_PWM_OCRnA // 15 COM OCnA
};

// Wavefore Generation Modes (Timer 2 only)
enum WaveGenMode2 : char {
WGM2_NORMAL, // 0
WGM2_PWM_PC, // 1
WGM2_CTC_OCR2A, // 2
WGM2_FAST_PWM, // 3
WGM2_reserved_1, // 4
WGM2_PWM_PC_OCR2A, // 5
WGM2_reserved_2, // 6
WGM2_FAST_PWM_OCR2A, // 7
};

// Compare Modes
enum CompareMode : char {
COM_NORMAL, // 0
Expand Down Expand Up @@ -186,6 +198,11 @@ enum ClockSource2 : char {
TCCR##T##B = (TCCR##T##B & ~(0x3 << WGM##T##2)) | (((int(V) >> 2) & 0x3) << WGM##T##2); \
}while(0)
#define SET_WGM(T,V) _SET_WGM(T,WGM_##V)
// Runtime (see Temperature::set_pwm_frequency):
#define _SET_WGMnQ(TCCRnQ, V) do{ \
*(TCCRnQ)[0] = (*(TCCRnQ)[0] & ~(0x3 << 0)) | (( int(V) & 0x3) << 0); \
*(TCCRnQ)[1] = (*(TCCRnQ)[1] & ~(0x3 << 3)) | (((int(V) >> 2) & 0x3) << 3); \
}while(0)

// Set Clock Select bits
// Ex: SET_CS3(PRESCALER_64);
Expand All @@ -211,6 +228,10 @@ enum ClockSource2 : char {
#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 Temperature::set_pwm_frequency)
#define _SET_CSn(TCCRnQ, V) do{ \
(*(TCCRnQ)[1] = (*(TCCRnQ[1]) & ~(0x7 << 0)) | ((int(V) & 0x7) << 0)); \
}while(0)

// Set Compare Mode bits
// Ex: SET_COMS(4,CLEAR_SET,CLEAR_SET,CLEAR_SET);
Expand All @@ -220,6 +241,22 @@ enum ClockSource2 : char {
#define SET_COMB(T,V) SET_COM(T,B,V)
#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 Temperature::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)

// Set OCRnQ register
// Runtime (see Temperature::set_pwm_duty):
#define _SET_OCRnQ(OCRnQ, Q, V) do{ \
(*(OCRnQ)[(Q)] = (0x0000) | (int(V) & 0xFFFF)); \
}while(0)

// Set ICRn register (one per timer)
// Runtime (see Temperature::set_pwm_frequency)
#define _SET_ICRn(ICRn, V) do{ \
(*(ICRn) = (0x0000) | (int(V) & 0xFFFF)); \
}while(0)

// Set Noise Canceler bit
// Ex: SET_ICNC(2,1)
Expand Down
7 changes: 7 additions & 0 deletions Marlin/src/inc/Conditionals_post.h
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,13 @@
#error "FAN_MIN_PWM must be less than or equal to FAN_MAX_PWM."
#endif

/**
* FAST PWM FAN Settings
*/
#if ENABLED(FAST_PWM_FAN) && !defined(FAST_PWM_FAN_FREQUENCY)
#define FAST_PWM_FAN_FREQUENCY ((F_CPU) / (2 * 255 * 1)) // Fan frequency default
#endif

/**
* Bed Probe dependencies
*/
Expand Down
12 changes: 12 additions & 0 deletions Marlin/src/module/planner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,18 @@ void Planner::check_axes_activity() {
#if HAS_FAN2
thermalManager.soft_pwm_amount_fan[2] = CALC_FAN_SPEED(2);
#endif

#elif ENABLED(FAST_PWM_FAN)
#if HAS_FAN0
thermalManager.set_pwm_duty(FAN_PIN, CALC_FAN_SPEED(0));
#endif
#if HAS_FAN1
thermalManager.set_pwm_duty(FAN1_PIN, CALC_FAN_SPEED(1));
#endif
#if HAS_FAN2
thermalManager.set_pwm_duty(FAN2_PIN, CALC_FAN_SPEED(2));
#endif

#else
#if HAS_FAN0
analogWrite(FAN_PIN, CALC_FAN_SPEED(0));
Expand Down
Loading