To achieve reliable PWM motor control with an ESP32 or Arduino, you must match the motor's stall current to a driver rated for at least 1.5x that continuous load, while selecting the motor type based on whether your application demands positional accuracy or raw continuous torque. There is no universal motor; a 3D printer extruder demands completely different drive logic than a robotic rover chassis.
Matching Motor Types to Your Load Profile
Before writing a single line of PWM code, you must select the correct electromechanical actuator for your physical load. The most common mistake in embedded projects is treating stepper motors and RC servos as interchangeable. They are not. Steppers hold position via open-loop magnetic detents and require continuous coil energization to maintain holding torque. Servos use a closed-loop internal potentiometer or encoder and only draw significant current while actively moving against a load.
| Motor Type | Torque Curve | Control Needs | Typical Cost (2026) | Best Application |
|---|---|---|---|---|
| Brushed DC | High starting torque, drops linearly with speed | Simple PWM + H-Bridge for direction | $5 - $20 | Drive wheels, conveyors, pumps |
| Brushless DC (BLDC) | Flat torque curve, high efficiency at high RPM | ESC or 3-phase FOC driver (complex PWM) | $25 - $80 | Drones, high-speed cooling, robotics |
| Stepper | High holding torque, drops sharply at speed | Step/Dir pulses (driver handles internal PWM chopping) | $15 - $40 | 3D printers, CNC routers, linear actuators |
| RC Servo | High torque at low speed, zero speed holding | 50Hz PWM positional signal (1000-2000µs) | $10 - $30 | Robot arms, pan/tilt cameras, RC steering |
If your load requires continuous rotation and variable speed without strict positional feedback, a Brushed DC gearmotor is your baseline choice. If you need precise angular movement without external limit switches, choose a Servo. For linear motion requiring high holding force without a mechanical brake, choose a Stepper.
Sizing Your PWM Motor Control Driver and Wiring
Microcontrollers cannot source the current required to drive motors directly. An ESP32 GPIO pin can safely source only about 40mA, while a small 12V gearmotor might pull 4,000mA (4A) at stall. You need a dedicated motor driver.
The 1.5x Sizing Rule of Thumb
Never size your motor driver based on the motor's free-run or nominal current. Always size it based on the stall current. The golden rule for PWM motor control sizing is:
Driver Continuous Current Rating ≥ 1.5 × Motor Stall Current
Worked Load Example
Suppose you are building an autonomous rover using a 12V brushed DC gearmotor. The datasheet lists a free-run current of 0.5A and a stall current of 4.0A.
- Required Driver Rating: 4.0A × 1.5 = 6.0A minimum continuous current.
- Bad Choice: The classic L298N H-Bridge. It is rated for only 2A continuous. It will overheat and trigger its internal thermal shutdown within seconds of a heavy load.
- Marginal Choice: TI DRV8871. Rated for 3.6A continuous. It will likely fail during a hard stall or rapid direction reversal.
- Correct Choice: BTS7960 High-Power Driver. Rated for 43A peak and roughly 20A continuous with basic heatsinking. It costs around $12 and handles the 4A stall effortlessly.
Wiring and Terminal Identification (BTS7960)
When wiring a high-power dual-H-bridge like the BTS7960 to an ESP32, terminal identification is critical to avoid frying your microcontroller's 3.3V logic pins.
| Terminal Label | Function | Connection Target |
|---|---|---|
| B+ / B- | High-current motor power input | 12V/24V Power Supply and Main GND |
| VCC / GND | Logic level power for optoisolators | ESP32 3V3 (or 5V if using Arduino Uno) |
| R_EN / L_EN | Enable pins for right/left channels | Tie to VCC (always enabled) or a separate GPIO |
| R_PWM / L_PWM | PWM signal inputs for speed control | ESP32 GPIO pins configured via LEDC API |
| M+ / M- | Motor output terminals | Brushed DC Motor wires |
Recognizing Failure Signatures: Hum, Overheat, and Stall
When your PWM motor control circuit fails, the physical symptoms will tell you exactly where the engineering breakdown occurred. Use this diagnostic path before swapping parts.
1. Audible Humming Without Rotation
The Symptom: The motor vibrates and emits a high-pitched whine or low hum, but the shaft does not turn.
The Cause: Either the PWM frequency is set too low (causing audible mechanical resonance), or the starting duty cycle is too low to overcome the load's static friction.
The Fix: If using an ESP32, configure the LEDC peripheral to a frequency between 1,000 Hz and 5,000 Hz. Next, implement a 'kickstart' routine in your code: apply 100% duty cycle for 50 milliseconds to break static friction, then drop to your desired PWM speed.
2. Driver Overheating and Thermal Shutdown
The Symptom: The motor runs fine for 30 seconds, then stops. The driver IC is too hot to touch. It resumes after cooling.
The Cause: You are operating near the driver's absolute maximum rating without adequate heatsinking, or your PWM frequency is so high that MOSFET gate-charge switching losses are generating excess heat.
The Fix: Measure the continuous current with a multimeter. If it exceeds 60% of the driver's rated continuous current, add an active cooling fan or upgrade to a driver with a lower R_DS(on) specification. Reduce PWM frequency if it is set above 20 kHz.
3. Microcontroller Brownout and Reset (Stall)
The Symptom: When the motor starts or hits a physical stall, the ESP32 or Arduino instantly reboots.
The Cause: Ground bounce and voltage sag. The motor's massive inrush current pulls the shared power rail voltage below the microcontroller's brownout threshold (typically 2.7V for ESP32).
The Fix: Never power the microcontroller from the same raw DC bus as a high-torque motor without isolation. Use a dedicated 5V buck converter for the ESP32. Crucially, solder a bulk electrolytic capacitor (e.g., 2200µF, 25V rated) directly across the motor driver's B+ and B- terminals to supply instantaneous inrush current. Ensure the ESP32 GND and Driver GND share a common reference point to prevent floating logic signals.
PWM Motor Control FAQ
What is the best PWM frequency for DC motor control?
The optimal range for brushed DC motor control is 1 kHz to 5 kHz. Frequencies below 500 Hz cause audible whine and can induce mechanical resonance in the motor housing and drivetrain. Frequencies above 20 kHz push the driver into the ultrasonic range, which is quiet but significantly increases MOSFET switching losses in the H-Bridge without providing any mechanical benefit to the motor. For most hobbyist and prosumer applications, 2 kHz is the sweet spot.
Can I use PWM to control a stepper motor directly from an ESP32?
No. You do not send PWM signals directly to stepper motor coils from a microcontroller. Instead, you send digital step and direction pulses to a dedicated chopper driver (like a TB6600 or TMC2209). The driver itself uses internal, high-frequency PWM (current chopping) to regulate the coil current and prevent overheating. Your ESP32 only needs to output clean, timed digital HIGH/LOW pulses to the driver's STEP pin.
Why does my ESP32 reset when I start the motor via PWM?
This is almost always caused by inrush current voltage sag or ground loop noise. When a DC motor starts, it briefly draws its full stall current. If your power supply cannot deliver this instantly, the voltage on the main rail drops. If the ESP32 shares this rail, it triggers a brownout reset. Fix this by separating the logic power supply from the motor power supply, tying their grounds together at a single star point, and adding a large bulk capacitor (2200µF or larger) across the motor driver's main power inputs.
How do I reverse a brushed DC motor using PWM?
You must use an H-Bridge driver (such as the BTS7960, DRV8871, or L298N). An H-Bridge has four internal switches that route current across the motor in either direction. To move forward, apply your PWM signal to the 'Forward' input pin while holding the 'Reverse' pin LOW. To reverse, apply PWM to the 'Reverse' pin and hold 'Forward' LOW. Never apply PWM to both pins simultaneously, as this will short-circuit the driver's internal MOSFETs and destroy the board.






