diff --git a/Marlin/src/HAL/HAL_ESP32/HAL.h b/Marlin/src/HAL/HAL_ESP32/HAL.h
index 4c831edf4f..9e4ab78a9a 100644
--- a/Marlin/src/HAL/HAL_ESP32/HAL.h
+++ b/Marlin/src/HAL/HAL_ESP32/HAL.h
@@ -75,6 +75,8 @@ extern portMUX_TYPE spinlock;
typedef int16_t pin_t;
+#define HAL_SERVO_LIB Servo
+
// --------------------------------------------------------------------------
// Public Variables
// --------------------------------------------------------------------------
diff --git a/Marlin/src/HAL/HAL_ESP32/HAL_Servo_ESP32.cpp b/Marlin/src/HAL/HAL_ESP32/HAL_Servo_ESP32.cpp
new file mode 100644
index 0000000000..bf3d228a6a
--- /dev/null
+++ b/Marlin/src/HAL/HAL_ESP32/HAL_Servo_ESP32.cpp
@@ -0,0 +1,69 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2019 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 ARDUINO_ARCH_ESP32
+
+#include "../../inc/MarlinConfig.h"
+
+#if HAS_SERVOS
+
+#include "HAL_Servo_ESP32.h"
+
+int Servo::channel_next_free = 0;
+
+Servo::Servo() {
+ this->channel = channel_next_free++;
+}
+
+int8_t Servo::attach(const int pin) {
+ if (this->channel >= CHANNEL_MAX_NUM) return -1;
+ if (pin > 0) this->pin = pin;
+
+ ledcSetup(this->channel, 50, 16); // channel X, 50 Hz, 16-bit depth
+ ledcAttachPin(this->pin, this->channel);
+ return true;
+}
+
+void Servo::detach() { ledcDetachPin(this->pin) }
+
+int Servo::read() { return this->degrees; }
+
+void Servo::write(int degrees) {
+ this->degrees = constrain(degrees, MIN_ANGLE, MAX_ANGLE);
+ int us = map(this->degrees, MIN_ANGLE, MAX_ANGLE, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
+ int duty = map(us, 0, TAU_USEC, 0, MAX_COMPARE);
+ ledcWrite(channel, duty);
+}
+
+void Servo::move(const int value) {
+ constexpr uint16_t servo_delay[] = SERVO_DELAY;
+ static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
+ if (this->attach(0) >= 0) {
+ this->write(value);
+ safe_delay(servo_delay[this->channel]);
+ #if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE)
+ this->detach();
+ #endif
+ }
+}
+#endif // HAS_SERVOS
+
+#endif // ARDUINO_ARCH_ESP32
diff --git a/Marlin/src/HAL/HAL_ESP32/HAL_Servo_ESP32.h b/Marlin/src/HAL/HAL_ESP32/HAL_Servo_ESP32.h
new file mode 100644
index 0000000000..b6c250038e
--- /dev/null
+++ b/Marlin/src/HAL/HAL_ESP32/HAL_Servo_ESP32.h
@@ -0,0 +1,49 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (C) 2019 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 .
+ *
+ */
+#pragma once
+
+#include
+
+class Servo {
+ static const int MIN_ANGLE = 0,
+ MAX_ANGLE = 180,
+ MIN_PULSE_WIDTH = 544, // Shortest pulse sent to a servo
+ MAX_PULSE_WIDTH = 2400, // Longest pulse sent to a servo
+ TAU_MSEC = 20,
+ TAU_USEC = (TAU_MSEC * 1000),
+ MAX_COMPARE = ((1 << 16) - 1), // 65535
+ CHANNEL_MAX_NUM = 16;
+
+public:
+ Servo();
+ int8_t attach(const int pin); // attach the given pin to the next free channel, set pinMode, return channel number (-1 on fail)
+ void detach();
+ void write(int degrees); // set angle
+ void move(const int degrees); // attach the servo, then move to value
+ int read(); // returns current pulse width as an angle between 0 and 180 degrees
+
+private:
+ static int channel_next_free;
+ int channel;
+ int pin;
+ int degrees;
+};
diff --git a/Marlin/src/HAL/shared/servo.cpp b/Marlin/src/HAL/shared/servo.cpp
index ec25569f9d..684fc320a8 100644
--- a/Marlin/src/HAL/shared/servo.cpp
+++ b/Marlin/src/HAL/shared/servo.cpp
@@ -53,7 +53,7 @@
#include "../../inc/MarlinConfig.h"
-#if HAS_SERVOS && !(IS_32BIT_TEENSY || defined(TARGET_LPC1768) || defined(STM32F1) || defined(STM32F1xx) || defined(STM32F4) || defined(STM32F4xx) || defined(STM32F7xx))
+#if HAS_SERVOS && !(IS_32BIT_TEENSY || defined(TARGET_LPC1768) || defined(STM32F1) || defined(STM32F1xx) || defined(STM32F4) || defined(STM32F4xx) || defined(STM32F7xx) || defined(ARDUINO_ARCH_ESP32))
#include "servo.h"
#include "servo_private.h"
diff --git a/Marlin/src/HAL/shared/servo.h b/Marlin/src/HAL/shared/servo.h
index 1bcc200a54..dea3e20d51 100644
--- a/Marlin/src/HAL/shared/servo.h
+++ b/Marlin/src/HAL/shared/servo.h
@@ -80,6 +80,8 @@
#include "../HAL_STM32F4/HAL_Servo_STM32F4.h"
#elif defined(ARDUINO_ARCH_STM32)
#include "../HAL_STM32/HAL_Servo_STM32.h"
+#elif defined(ARDUINO_ARCH_ESP32)
+ #include "../HAL_ESP32/HAL_Servo_ESP32.h"
#else
#include