|
|
@ -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
|
|
|
@ -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; |
|
|
|
|
|
|
@ -243,7 +242,11 @@ 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 NEEDS_HARDWARE_PWM |
|
|
|
|
|
|
|
// 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) |
|
|
@ -252,7 +255,7 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255 |
|
|
|
digitalWrite(pin, !invert); |
|
|
|
else { |
|
|
|
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
|
|
|
|
// Set compare output mode to CLEAR -> SET or SET -> CLEAR (if inverted)
|
|
|
|
_SET_COMnQ(timer.TCCRnQ, (timer.q |
|
|
|
#ifdef TCCR2 |
|
|
@ -261,22 +264,17 @@ void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255 |
|
|
|
), COM_CLEAR_SET + invert |
|
|
|
); |
|
|
|
|
|
|
|
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 |
|
|
|
); |
|
|
|
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__
|
|
|
|