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

Ensure that PWM frequency is not changed by AUTO_FAN #23048

Merged
merged 11 commits into from
Nov 2, 2021
2 changes: 1 addition & 1 deletion Marlin/src/HAL/AVR/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ void set_pwm_frequency(const pin_t pin, int f_desired);

/**
* set_pwm_duty
* Sets the PWM duty cycle of the provided pin to the provided value
* Set the PWM duty cycle of the provided pin to the provided value
* Optionally allows inverting the duty cycle [default = false]
* Optionally allows changing the maximum size of the provided value to enable finer PWM duty control [default = 255]
*/
Expand Down
62 changes: 30 additions & 32 deletions Marlin/src/HAL/AVR/fast_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@
#ifdef __AVR__

#include "../../inc/MarlinConfigPre.h"
#include "HAL.h"

#if NEEDS_HARDWARE_PWM // Specific meta-flag for features that mandate PWM

#include "HAL.h"

struct Timer {
volatile uint8_t* TCCRnQ[3]; // max 3 TCCR registers per timer
volatile uint16_t* OCRnQ[3]; // max 3 OCR registers per timer
Expand Down Expand Up @@ -153,7 +152,7 @@ Timer get_pwm_timer(const pin_t pin) {

void set_pwm_frequency(const pin_t pin, int f_desired) {
Timer timer = get_pwm_timer(pin);
if (timer.n == 0) return; // Don't proceed if protected timer or not recognised
if (timer.n == 0) return; // Don't proceed if protected timer or not recognized
uint16_t size;
if (timer.n == 2) size = 255; else size = 65535;

Expand Down Expand Up @@ -243,40 +242,39 @@ void set_pwm_frequency(const pin_t pin, int f_desired) {
_SET_ICRn(timer.ICRn, res); // Set ICRn value (TOP) = res
}

#endif // NEEDS_HARDWARE_PWM

void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
// If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
// Note that digitalWrite also disables pwm output for us (sets COM bit to 0)
if (v == 0)
digitalWrite(pin, invert);
else if (v == v_size)
digitalWrite(pin, !invert);
else {
Timer timer = get_pwm_timer(pin);
if (timer.n == 0) return; // Don't proceed if protected timer or not recognised
// 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
);
#if NEEDS_HARDWARE_PWM

uint16_t top;
if (timer.n == 2) { // if TIMER2
top = (
#if ENABLED(USE_OCR2A_AS_TOP)
*timer.OCRnQ[0] // top = OCR2A
#else
255 // top = 0xFF (max)
#endif
// If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
// Note that digitalWrite also disables pwm output for us (sets COM bit to 0)
if (v == 0)
digitalWrite(pin, invert);
else if (v == v_size)
digitalWrite(pin, !invert);
else {
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
}
else
top = *timer.ICRn; // top = ICRn

_SET_OCRnQ(timer.OCRnQ, timer.q, v * float(top) / float(v_size)); // Scale 8/16-bit v to top value
}
#else

analogWrite(pin, v);
UNUSED(v_size);
UNUSED(invert);

#endif
}

#endif // NEEDS_HARDWARE_PWM
#endif // __AVR__
5 changes: 5 additions & 0 deletions Marlin/src/HAL/DUE/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ inline void HAL_adc_init() {}//todo
void HAL_adc_start_conversion(const uint8_t ch);
uint16_t HAL_adc_get_result();

//
// PWM
//
inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

//
// Pin Map
//
Expand Down
4 changes: 4 additions & 0 deletions Marlin/src/HAL/ESP32/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ void HAL_adc_init();

void HAL_adc_start_conversion(const uint8_t adc_pin);

// PWM
inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

// Pin Map
#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
Expand Down
3 changes: 3 additions & 0 deletions Marlin/src/HAL/LINUX/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ void HAL_adc_enable_channel(const uint8_t ch);
void HAL_adc_start_conversion(const uint8_t ch);
uint16_t HAL_adc_get_result();

// PWM
inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

// Reset source
inline void HAL_clear_reset_source(void) {}
inline uint8_t HAL_get_reset_source(void) { return RST_POWER_ON; }
Expand Down
16 changes: 8 additions & 8 deletions Marlin/src/HAL/LPC1768/fast_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@
#ifdef TARGET_LPC1768

#include "../../inc/MarlinConfigPre.h"

#if NEEDS_HARDWARE_PWM // Specific meta-flag for features that mandate PWM

#include <pwm.h>

void set_pwm_frequency(const pin_t pin, int f_desired) {
LPC176x::pwm_set_frequency(pin, f_desired);
}

void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
LPC176x::pwm_write_ratio(pin, invert ? 1.0f - (float)v / v_size : (float)v / v_size);
}

#endif // NEEDS_HARDWARE_PWM
#if NEEDS_HARDWARE_PWM // Specific meta-flag for features that mandate PWM

void set_pwm_frequency(const pin_t pin, int f_desired) {
LPC176x::pwm_set_frequency(pin, f_desired);
}

#endif

#endif // TARGET_LPC1768
3 changes: 3 additions & 0 deletions Marlin/src/HAL/NATIVE_SIM/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ void HAL_adc_enable_channel(const uint8_t ch);
void HAL_adc_start_conversion(const uint8_t ch);
uint16_t HAL_adc_get_result();

// PWM
inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

// Reset source
inline void HAL_clear_reset_source(void) {}
inline uint8_t HAL_get_reset_source(void) { return RST_POWER_ON; }
Expand Down
5 changes: 5 additions & 0 deletions Marlin/src/HAL/SAMD51/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ void HAL_adc_init();

void HAL_adc_start_conversion(const uint8_t adc_pin);

//
// PWM
//
inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

//
// Pin Map
//
Expand Down
37 changes: 18 additions & 19 deletions Marlin/src/HAL/STM32/fast_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,9 @@

#ifdef HAL_STM32

#include "../../inc/MarlinConfigPre.h"

#if NEEDS_HARDWARE_PWM

#include "HAL.h"
#include "../../inc/MarlinConfig.h"
#include "timers.h"

void set_pwm_frequency(const pin_t pin, int f_desired) {
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer

PinName pin_name = digitalPinToPinName(pin);
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance

LOOP_S_L_N(i, 0, NUM_HARDWARE_TIMERS) // Protect used timers
if (timer_instance[i] && timer_instance[i]->getHandle()->Instance == Instance)
return;

pwm_start(pin_name, f_desired, 0, RESOLUTION_8B_COMPARE_FORMAT);
}

void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
PinName pin_name = digitalPinToPinName(pin);
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM);
Expand All @@ -58,5 +41,21 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255
}
}

#endif // NEEDS_HARDWARE_PWM
#if NEEDS_HARDWARE_PWM

void set_pwm_frequency(const pin_t pin, int f_desired) {
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer

PinName pin_name = digitalPinToPinName(pin);
TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(pin_name, PinMap_PWM); // Get HAL timer instance

LOOP_S_L_N(i, 0, NUM_HARDWARE_TIMERS) // Protect used timers
if (timer_instance[i] && timer_instance[i]->getHandle()->Instance == Instance)
return;

pwm_start(pin_name, f_desired, 0, RESOLUTION_8B_COMPARE_FORMAT);
}

#endif

#endif // HAL_STM32
3 changes: 1 addition & 2 deletions Marlin/src/HAL/STM32F1/HAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,7 @@ uint16_t analogRead(pin_t pin) {

// Wrapper to maple unprotected analogWrite
void analogWrite(pin_t pin, int pwm_val8) {
if (PWM_PIN(pin))
analogWrite(uint8_t(pin), pwm_val8);
if (PWM_PIN(pin)) analogWrite(uint8_t(pin), pwm_val8);
}

void HAL_reboot() { nvic_sys_reset(); }
Expand Down
60 changes: 30 additions & 30 deletions Marlin/src/HAL/STM32F1/fast_pwm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,46 +23,46 @@

#include "../../inc/MarlinConfigPre.h"

#if NEEDS_HARDWARE_PWM

#include <pwm.h>
#include "HAL.h"
#include "timers.h"

void set_pwm_frequency(const pin_t pin, int f_desired) {
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer

timer_dev *timer = PIN_MAP[pin].timer_device;
uint8_t channel = PIN_MAP[pin].timer_channel;

// Protect used timers
if (timer == get_timer_dev(TEMP_TIMER_NUM)) return;
if (timer == get_timer_dev(STEP_TIMER_NUM)) return;
#if PULSE_TIMER_NUM != STEP_TIMER_NUM
if (timer == get_timer_dev(PULSE_TIMER_NUM)) return;
#endif

if (!(timer->regs.bas->SR & TIMER_CR1_CEN)) // Ensure the timer is enabled
timer_init(timer);

timer_set_mode(timer, channel, TIMER_PWM);
uint16_t preload = 255; // Lock 255 PWM resolution for high frequencies
int32_t prescaler = (HAL_TIMER_RATE) / (preload + 1) / f_desired - 1;
if (prescaler > 65535) { // For low frequencies increase prescaler
prescaler = 65535;
preload = (HAL_TIMER_RATE) / (prescaler + 1) / f_desired - 1;
}
if (prescaler < 0) return; // Too high frequency
timer_set_reload(timer, preload);
timer_set_prescaler(timer, prescaler);
}

void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
timer_dev *timer = PIN_MAP[pin].timer_device;
thinkyhead marked this conversation as resolved.
Show resolved Hide resolved
uint16_t max_val = timer->regs.bas->ARR * v / v_size;
if (invert) max_val = v_size - max_val;
pwmWrite(pin, max_val);
}

#if NEEDS_HARDWARE_PWM

void set_pwm_frequency(const pin_t pin, int f_desired) {
if (!PWM_PIN(pin)) return; // Don't proceed if no hardware timer

timer_dev *timer = PIN_MAP[pin].timer_device;
uint8_t channel = PIN_MAP[pin].timer_channel;

// Protect used timers
if (timer == get_timer_dev(TEMP_TIMER_NUM)) return;
if (timer == get_timer_dev(STEP_TIMER_NUM)) return;
#if PULSE_TIMER_NUM != STEP_TIMER_NUM
if (timer == get_timer_dev(PULSE_TIMER_NUM)) return;
#endif

if (!(timer->regs.bas->SR & TIMER_CR1_CEN)) // Ensure the timer is enabled
timer_init(timer);

timer_set_mode(timer, channel, TIMER_PWM);
uint16_t preload = 255; // Lock 255 PWM resolution for high frequencies
int32_t prescaler = (HAL_TIMER_RATE) / (preload + 1) / f_desired - 1;
if (prescaler > 65535) { // For low frequencies increase prescaler
prescaler = 65535;
preload = (HAL_TIMER_RATE) / (prescaler + 1) / f_desired - 1;
}
if (prescaler < 0) return; // Too high frequency
timer_set_reload(timer, preload);
timer_set_prescaler(timer, prescaler);
}

#endif // NEEDS_HARDWARE_PWM
#endif // __STM32F1__
6 changes: 6 additions & 0 deletions Marlin/src/HAL/TEENSY31_32/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ void HAL_adc_init();
void HAL_adc_start_conversion(const uint8_t adc_pin);
uint16_t HAL_adc_get_result();

// PWM

inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

// Pin Map

#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
6 changes: 6 additions & 0 deletions Marlin/src/HAL/TEENSY35_36/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@ void HAL_adc_init();
void HAL_adc_start_conversion(const uint8_t adc_pin);
uint16_t HAL_adc_get_result();

// PWM

inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

// Pin Map

#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
10 changes: 5 additions & 5 deletions Marlin/src/HAL/TEENSY40_41/HAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,17 @@ void HAL_adc_init() {
void HAL_clear_reset_source() {
uint32_t reset_source = SRC_SRSR;
SRC_SRSR = reset_source;
}
}

uint8_t HAL_get_reset_source() {
switch (SRC_SRSR & 0xFF) {
case 1: return RST_POWER_ON; break;
case 2: return RST_SOFTWARE; break;
case 4: return RST_EXTERNAL; break;
// case 8: return RST_BROWN_OUT; break;
//case 8: return RST_BROWN_OUT; break;
case 16: return RST_WATCHDOG; break;
case 64: return RST_JTAG; break;
// case 128: return RST_OVERTEMP; break;
case 64: return RST_JTAG; break;
//case 128: return RST_OVERTEMP; break;
}
return 0;
}
Expand Down Expand Up @@ -168,7 +168,7 @@ uint16_t HAL_adc_get_result() {
return 0;
}

bool is_output(uint8_t pin) {
bool is_output(pin_t pin) {
const struct digital_pin_bitband_and_config_table_struct *p;
p = digital_pin_to_info_PGM + pin;
return (*(p->reg + 1) & p->mask);
Expand Down
8 changes: 7 additions & 1 deletion Marlin/src/HAL/TEENSY40_41/HAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,14 @@ void HAL_adc_init();
void HAL_adc_start_conversion(const uint8_t adc_pin);
uint16_t HAL_adc_get_result();

// PWM

inline void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t=255, const bool=false) { analogWrite(pin, v); }

// Pin Map

#define GET_PIN_MAP_PIN(index) index
#define GET_PIN_MAP_INDEX(pin) pin
#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)

bool is_output(uint8_t pin);
bool is_output(pin_t pin);
Loading