Browse Source

🐛 Fix, improve PWM on AVR (#23520)

Mike La Spina 3 years ago
parent
commit
09909512d7
No account linked to committer's email address
2 changed files with 25 additions and 14 deletions
  1. 16
    7
      Marlin/src/HAL/AVR/fast_pwm.cpp
  2. 9
    7
      Marlin/src/module/planner.cpp

+ 16
- 7
Marlin/src/HAL/AVR/fast_pwm.cpp View File

61
   switch (digitalPinToTimer(pin)) {
61
   switch (digitalPinToTimer(pin)) {
62
     #ifdef TCCR0A
62
     #ifdef TCCR0A
63
       IF_DISABLED(AVR_AT90USB1286_FAMILY, case TIMER0A:)
63
       IF_DISABLED(AVR_AT90USB1286_FAMILY, case TIMER0A:)
64
-      case TIMER0B:
65
     #endif
64
     #endif
66
     #ifdef TCCR1A
65
     #ifdef TCCR1A
67
       case TIMER1A: case TIMER1B:
66
       case TIMER1A: case TIMER1B:
69
 
68
 
70
     break;    // Protect reserved timers (TIMER0 & TIMER1)
69
     break;    // Protect reserved timers (TIMER0 & TIMER1)
71
 
70
 
71
+    #ifdef TCCR0A
72
+      case TIMER0B:   // Protected timer, but allow setting the duty cycle on OCR0B for pin D4 only
73
+        return Timer({ { &TCCR0A, nullptr, nullptr }, { (uint16_t*)&OCR0B, nullptr, nullptr }, nullptr, 0, 0, true, true });
74
+    #endif
75
+
72
     #if HAS_TCCR2
76
     #if HAS_TCCR2
73
       case TIMER2:
77
       case TIMER2:
74
         return Timer({ { &TCCR2, nullptr, nullptr }, { (uint16_t*)&OCR2, nullptr, nullptr }, nullptr, 2, 0, true, false });
78
         return Timer({ { &TCCR2, nullptr, nullptr }, { (uint16_t*)&OCR2, nullptr, nullptr }, nullptr, 2, 0, true, false });
75
     #elif ENABLED(USE_OCR2A_AS_TOP)
79
     #elif ENABLED(USE_OCR2A_AS_TOP)
76
-      case TIMER2A: break; // protect TIMER2A since its OCR is used by TIMER2B
80
+      case TIMER2A: break; // Protect TIMER2A since its OCR is used by TIMER2B
77
       case TIMER2B:
81
       case TIMER2B:
78
         return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, 1, true, false });
82
         return Timer({ { &TCCR2A, &TCCR2B, nullptr }, { (uint16_t*)&OCR2A, (uint16_t*)&OCR2B, nullptr }, nullptr, 2, 1, true, false });
79
     #elif defined(TCCR2A)
83
     #elif defined(TCCR2A)
174
 
178
 
175
 void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
179
 void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size/*=255*/, const bool invert/*=false*/) {
176
   // If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
180
   // If v is 0 or v_size (max), digitalWrite to LOW or HIGH.
177
-  // Note that digitalWrite also disables pwm output for us (sets COM bit to 0)
181
+  // Note that digitalWrite also disables PWM output for us (sets COM bit to 0)
178
   if (v == 0)
182
   if (v == 0)
179
     digitalWrite(pin, invert);
183
     digitalWrite(pin, invert);
180
   else if (v == v_size)
184
   else if (v == v_size)
181
     digitalWrite(pin, !invert);
185
     digitalWrite(pin, !invert);
182
   else {
186
   else {
183
     Timer timer = get_pwm_timer(pin);
187
     Timer timer = get_pwm_timer(pin);
184
-    if (timer.isProtected) return;                            // Leave protected timer unchanged
185
     if (timer.isPWM) {
188
     if (timer.isPWM) {
186
-      _SET_COMnQ(timer.TCCRnQ, SUM_TERN(HAS_TCCR2, timer.q, timer.q == 2), COM_CLEAR_SET + invert);   // COM20 is on bit 4 of TCCR2, so +1 for q==2
187
-      const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
188
-      _SET_OCRnQ(timer.OCRnQ, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value
189
+      if (timer.n == 0) {
190
+        TCCR0A |= _BV(COM0B1); // Only allow a TIMER0B select and OCR0B duty update for pin D4 outputs no frequency changes are permited.
191
+        OCR0B = v;
192
+      }
193
+      else if (!timer.isProtected) {
194
+        const uint16_t top = timer.n == 2 ? TERN(USE_OCR2A_AS_TOP, *timer.OCRnQ[0], 255) : *timer.ICRn;
195
+        _SET_COMnQ(timer.TCCRnQ, SUM_TERN(HAS_TCCR2, timer.q, timer.q == 2), COM_CLEAR_SET + invert);   // COM20 is on bit 4 of TCCR2, so +1 for q==2
196
+        _SET_OCRnQ(timer.OCRnQ, timer.q, uint16_t(uint32_t(v) * top / v_size)); // Scale 8/16-bit v to top value
197
+      }
189
     }
198
     }
190
     else
199
     else
191
       digitalWrite(pin, v < 128 ? LOW : HIGH);
200
       digitalWrite(pin, v < 128 ? LOW : HIGH);

+ 9
- 7
Marlin/src/module/planner.cpp View File

1244
   recalculate_trapezoids();
1244
   recalculate_trapezoids();
1245
 }
1245
 }
1246
 
1246
 
1247
-#if HAS_FAN && DISABLED(LASER_SYNCHRONOUS_M106_M107)
1248
-  #define HAS_TAIL_FAN_SPEED 1
1249
-#endif
1250
-
1251
 /**
1247
 /**
1252
  * Apply fan speeds
1248
  * Apply fan speeds
1253
  */
1249
  */
1308
     xyze_bool_t axis_active = { false };
1304
     xyze_bool_t axis_active = { false };
1309
   #endif
1305
   #endif
1310
 
1306
 
1311
-  #if HAS_TAIL_FAN_SPEED
1312
-    static uint8_t tail_fan_speed[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, 255);
1307
+  #if HAS_FAN && DISABLED(LASER_SYNCHRONOUS_M106_M107)
1308
+    #define HAS_TAIL_FAN_SPEED 1
1309
+    static uint8_t tail_fan_speed[FAN_COUNT] = ARRAY_N_1(FAN_COUNT, 128);
1313
     bool fans_need_update = false;
1310
     bool fans_need_update = false;
1314
   #endif
1311
   #endif
1315
 
1312
 
1395
   // Update Fan speeds
1392
   // Update Fan speeds
1396
   // Only if synchronous M106/M107 is disabled
1393
   // Only if synchronous M106/M107 is disabled
1397
   //
1394
   //
1398
-  TERN_(HAS_TAIL_FAN_SPEED, if (fans_need_update) sync_fan_speeds(tail_fan_speed));
1395
+  #if HAS_TAIL_FAN_SPEED
1396
+    if (fans_need_update) {
1397
+      sync_fan_speeds(tail_fan_speed);
1398
+      fans_need_update = false;
1399
+    }
1400
+  #endif
1399
 
1401
 
1400
   TERN_(AUTOTEMP, autotemp_task());
1402
   TERN_(AUTOTEMP, autotemp_task());
1401
 
1403
 

Loading…
Cancel
Save