2323
2424#include " ../../inc/MarlinConfig.h"
2525
26+ // #define DEBUG_AVR_FAST_PWM
27+ #define DEBUG_OUT ENABLED (DEBUG_AVR_FAST_PWM)
28+ #include " ../../core/debug_out.h"
29+
2630struct Timer {
2731 volatile uint8_t * TCCRnQ[3 ]; // max 3 TCCR registers per timer
2832 volatile uint16_t * OCRnQ[3 ]; // max 3 OCR registers per timer
@@ -108,36 +112,45 @@ const Timer get_pwm_timer(const pin_t pin) {
108112}
109113
110114void MarlinHAL::set_pwm_frequency (const pin_t pin, const uint16_t f_desired) {
115+ DEBUG_ECHOLNPGM (" set_pwm_frequency(pin=" , pin, " , freq=" , f_desired, " )" );
111116 const Timer timer = get_pwm_timer (pin);
112117 if (timer.isProtected || !timer.isPWM ) return ; // Don't proceed if protected timer or not recognized
113118
114119 const bool is_timer2 = timer.n == 2 ;
115120 const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF ;
116121
122+ DEBUG_ECHOLNPGM (" maxtop=" , maxtop);
123+
117124 uint16_t res = 0xFF ; // resolution (TOP value)
118125 uint8_t j = CS_NONE; // prescaler index
119126 uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode
120127
121128 // Calculating the prescaler and resolution to use to achieve closest frequency
122129 if (f_desired != 0 ) {
123130 constexpr uint16_t prescaler[] = { 1 , 8 , (32 ), 64 , (128 ), 256 , 1024 }; // (*) are Timer 2 only
124- uint16_t f = (F_CPU) / (2 * 1024 * maxtop ) + 1 ; // Start with the lowest non-zero frequency achievable (1 or 31)
131+ uint16_t f = (F_CPU) / (uint32_t (maxtop) << 11 ) + 1 ; // Start with the lowest non-zero frequency achievable (for 16MHz, 1 or 31)
125132
133+ DEBUG_ECHOLNPGM (" f=" , f);
134+ DEBUG_ECHOLNPGM (" (prescaler loop)" );
126135 LOOP_L_N (i, COUNT (prescaler)) { // Loop through all prescaler values
127- const uint16_t p = prescaler[i];
136+ const uint32_t p = prescaler[i]; // Extend to 32 bits for calculations
137+ DEBUG_ECHOLNPGM (" prescaler[" , i, " ]=" , p);
128138 uint16_t res_fast_temp, res_pc_temp;
129139 if (is_timer2) {
130140 #if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP
131141 const uint16_t rft = (F_CPU) / (p * f_desired);
132142 res_fast_temp = rft - 1 ;
133143 res_pc_temp = rft / 2 ;
144+ DEBUG_ECHOLNPGM (" (Timer2) res_fast_temp=" , res_fast_temp, " res_pc_temp=" , res_pc_temp);
134145 #else
135146 res_fast_temp = res_pc_temp = maxtop;
147+ DEBUG_ECHOLNPGM (" (Timer2) res_fast_temp=" , maxtop, " res_pc_temp=" , maxtop);
136148 #endif
137149 }
138150 else {
139151 if (p == 32 || p == 128 ) continue ; // Skip TIMER2 specific prescalers when not TIMER2
140152 const uint16_t rft = (F_CPU) / (p * f_desired);
153+ DEBUG_ECHOLNPGM (" (Not Timer 2) F_CPU=" STRINGIFY (F_CPU), " prescaler=" , p, " f_desired=" , f_desired);
141154 res_fast_temp = rft - 1 ;
142155 res_pc_temp = rft / 2 ;
143156 }
@@ -147,23 +160,27 @@ void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
147160
148161 // Calculate frequencies of test prescaler and resolution values
149162 const uint16_t f_fast_temp = (F_CPU) / (p * (1 + res_fast_temp)),
150- f_pc_temp = (F_CPU) / (2 * p * res_pc_temp);
151- const int f_diff = _MAX (f, f_desired) - _MIN (f, f_desired),
163+ f_pc_temp = (F_CPU) / (( p * res_pc_temp) << 1 ),
164+ f_diff = _MAX (f, f_desired) - _MIN (f, f_desired),
152165 f_fast_diff = _MAX (f_fast_temp, f_desired) - _MIN (f_fast_temp, f_desired),
153166 f_pc_diff = _MAX (f_pc_temp, f_desired) - _MIN (f_pc_temp, f_desired);
154167
168+ DEBUG_ECHOLNPGM (" f_fast_temp=" , f_fast_temp, " f_pc_temp=" , f_pc_temp, " f_diff=" , f_diff, " f_fast_diff=" , f_fast_diff, " f_pc_diff=" , f_pc_diff);
169+
155170 if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f
156171 // Set the Wave Generation Mode to FAST PWM
157172 wgm = is_timer2 ? uint8_t (TERN (USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t (WGM_FAST_PWM_ICRn);
158173 // Remember this combination
159174 f = f_fast_temp; res = res_fast_temp; j = i + 1 ;
175+ DEBUG_ECHOLNPGM (" (FAST) updated f=" , f);
160176 }
161177 else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f
162178 // Set the Wave Generation Mode to PWM PHASE CORRECT
163179 wgm = is_timer2 ? uint8_t (TERN (USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t (WGM_PWM_PC_ICRn);
164180 f = f_pc_temp; res = res_pc_temp; j = i + 1 ;
181+ DEBUG_ECHOLNPGM (" (PHASE) updated f=" , f);
165182 }
166- }
183+ } // prescaler loop
167184 }
168185
169186 _SET_WGMnQ (timer, wgm);
0 commit comments