diff --git a/Marlin/src/HAL/STM32F1/HAL.h b/Marlin/src/HAL/STM32F1/HAL.h
index eaf6494dfa..b77539d7b6 100644
--- a/Marlin/src/HAL/STM32F1/HAL.h
+++ b/Marlin/src/HAL/STM32F1/HAL.h
@@ -244,3 +244,20 @@ void analogWrite(pin_t pin, int pwm_val8); // PWM only! mul by 257 in maple!?
#define PLATFORM_M997_SUPPORT
void flashFirmware(const int16_t);
+
+#define HAL_CAN_SET_PWM_FREQ // This HAL supports PWM Frequency adjustment
+
+/**
+ * set_pwm_frequency
+ * Set the frequency of the timer corresponding to the provided pin
+ * All Timer PWM pins run at the same frequency
+ */
+void set_pwm_frequency(const pin_t pin, int f_desired);
+
+/**
+ * set_pwm_duty
+ * 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]
+ */
+void set_pwm_duty(const pin_t pin, const uint16_t v, const uint16_t v_size=255, const bool invert=false);
diff --git a/Marlin/src/HAL/STM32F1/fast_pwm.cpp b/Marlin/src/HAL/STM32F1/fast_pwm.cpp
new file mode 100644
index 0000000000..884d482af5
--- /dev/null
+++ b/Marlin/src/HAL/STM32F1/fast_pwm.cpp
@@ -0,0 +1,68 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+#ifdef __STM32F1__
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if NEEDS_HARDWARE_PWM
+
+#include
+#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;
+ uint16_t max_val = timer->regs.bas->ARR * v / v_size;
+ if (invert) max_val = v_size - max_val;
+ pwmWrite(pin, max_val);
+}
+
+#endif // NEEDS_HARDWARE_PWM
+#endif // __STM32F1__
diff --git a/Marlin/src/HAL/STM32F1/inc/SanityCheck.h b/Marlin/src/HAL/STM32F1/inc/SanityCheck.h
index a0381ea8c8..937bef8803 100644
--- a/Marlin/src/HAL/STM32F1/inc/SanityCheck.h
+++ b/Marlin/src/HAL/STM32F1/inc/SanityCheck.h
@@ -25,10 +25,6 @@
* Test STM32F1-specific configuration values for errors at compile-time.
*/
-#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY
- #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on STM32F1."
-#endif
-
#if !defined(HAVE_SW_SERIAL) && HAS_TMC_SW_SERIAL
#warning "With TMC2208/9 consider using SoftwareSerialM with HAVE_SW_SERIAL and appropriate SS_TIMER."
#error "Missing SoftwareSerial implementation."
diff --git a/Marlin/src/lcd/menu/menu_spindle_laser.cpp b/Marlin/src/lcd/menu/menu_spindle_laser.cpp
index 04b999eaf6..f1bf433c21 100644
--- a/Marlin/src/lcd/menu/menu_spindle_laser.cpp
+++ b/Marlin/src/lcd/menu/menu_spindle_laser.cpp
@@ -55,10 +55,8 @@
#endif
}
- #if ENABLED(MARLIN_DEV_MODE)
- #if ENABLED(HAL_CAN_SET_PWM_FREQ) && defined(SPINDLE_LASER_FREQUENCY)
- EDIT_ITEM_FAST(CUTTER_MENU_FREQUENCY_TYPE, MSG_CUTTER_FREQUENCY, &cutter.frequency, 2000, 50000, cutter.refresh_frequency);
- #endif
+ #if BOTH(MARLIN_DEV_MODE, HAL_CAN_SET_PWM_FREQ) && defined(SPINDLE_LASER_FREQUENCY)
+ EDIT_ITEM_FAST(CUTTER_MENU_FREQUENCY_TYPE, MSG_CUTTER_FREQUENCY, &cutter.frequency, 2000, 50000, cutter.refresh_frequency);
#endif
END_MENU();
}