23
23
24
24
#include " ../../inc/MarlinConfig.h"
25
25
26
+ // #define DEBUG_AVR_FAST_PWM
27
+ #define DEBUG_OUT ENABLED (DEBUG_AVR_FAST_PWM)
28
+ #include " ../../core/debug_out.h"
29
+
26
30
struct Timer {
27
31
volatile uint8_t * TCCRnQ[3 ]; // max 3 TCCR registers per timer
28
32
volatile uint16_t * OCRnQ[3 ]; // max 3 OCR registers per timer
@@ -108,36 +112,45 @@ const Timer get_pwm_timer(const pin_t pin) {
108
112
}
109
113
110
114
void MarlinHAL::set_pwm_frequency (const pin_t pin, const uint16_t f_desired) {
115
+ DEBUG_ECHOLNPGM (" set_pwm_frequency(pin=" , pin, " , freq=" , f_desired, " )" );
111
116
const Timer timer = get_pwm_timer (pin);
112
117
if (timer.isProtected || !timer.isPWM ) return ; // Don't proceed if protected timer or not recognized
113
118
114
119
const bool is_timer2 = timer.n == 2 ;
115
120
const uint16_t maxtop = is_timer2 ? 0xFF : 0xFFFF ;
116
121
122
+ DEBUG_ECHOLNPGM (" maxtop=" , maxtop);
123
+
117
124
uint16_t res = 0xFF ; // resolution (TOP value)
118
125
uint8_t j = CS_NONE; // prescaler index
119
126
uint8_t wgm = WGM_PWM_PC_8; // waveform generation mode
120
127
121
128
// Calculating the prescaler and resolution to use to achieve closest frequency
122
129
if (f_desired != 0 ) {
123
130
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)
125
132
133
+ DEBUG_ECHOLNPGM (" f=" , f);
134
+ DEBUG_ECHOLNPGM (" (prescaler loop)" );
126
135
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);
128
138
uint16_t res_fast_temp, res_pc_temp;
129
139
if (is_timer2) {
130
140
#if ENABLED(USE_OCR2A_AS_TOP) // No resolution calculation for TIMER2 unless enabled USE_OCR2A_AS_TOP
131
141
const uint16_t rft = (F_CPU) / (p * f_desired);
132
142
res_fast_temp = rft - 1 ;
133
143
res_pc_temp = rft / 2 ;
144
+ DEBUG_ECHOLNPGM (" (Timer2) res_fast_temp=" , res_fast_temp, " res_pc_temp=" , res_pc_temp);
134
145
#else
135
146
res_fast_temp = res_pc_temp = maxtop;
147
+ DEBUG_ECHOLNPGM (" (Timer2) res_fast_temp=" , maxtop, " res_pc_temp=" , maxtop);
136
148
#endif
137
149
}
138
150
else {
139
151
if (p == 32 || p == 128 ) continue ; // Skip TIMER2 specific prescalers when not TIMER2
140
152
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);
141
154
res_fast_temp = rft - 1 ;
142
155
res_pc_temp = rft / 2 ;
143
156
}
@@ -147,23 +160,27 @@ void MarlinHAL::set_pwm_frequency(const pin_t pin, const uint16_t f_desired) {
147
160
148
161
// Calculate frequencies of test prescaler and resolution values
149
162
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),
152
165
f_fast_diff = _MAX (f_fast_temp, f_desired) - _MIN (f_fast_temp, f_desired),
153
166
f_pc_diff = _MAX (f_pc_temp, f_desired) - _MIN (f_pc_temp, f_desired);
154
167
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
+
155
170
if (f_fast_diff < f_diff && f_fast_diff <= f_pc_diff) { // FAST values are closest to desired f
156
171
// Set the Wave Generation Mode to FAST PWM
157
172
wgm = is_timer2 ? uint8_t (TERN (USE_OCR2A_AS_TOP, WGM2_FAST_PWM_OCR2A, WGM2_FAST_PWM)) : uint8_t (WGM_FAST_PWM_ICRn);
158
173
// Remember this combination
159
174
f = f_fast_temp; res = res_fast_temp; j = i + 1 ;
175
+ DEBUG_ECHOLNPGM (" (FAST) updated f=" , f);
160
176
}
161
177
else if (f_pc_diff < f_diff) { // PHASE CORRECT values are closes to desired f
162
178
// Set the Wave Generation Mode to PWM PHASE CORRECT
163
179
wgm = is_timer2 ? uint8_t (TERN (USE_OCR2A_AS_TOP, WGM2_PWM_PC_OCR2A, WGM2_PWM_PC)) : uint8_t (WGM_PWM_PC_ICRn);
164
180
f = f_pc_temp; res = res_pc_temp; j = i + 1 ;
181
+ DEBUG_ECHOLNPGM (" (PHASE) updated f=" , f);
165
182
}
166
- }
183
+ } // prescaler loop
167
184
}
168
185
169
186
_SET_WGMnQ (timer, wgm);
0 commit comments