To control a DC motor with an Arduino, you cannot wire the motor directly to the microcontroller's GPIO pins. An Arduino Uno or Nano pin can safely source only about 20mA, while even a small 12V DC gearmotor draws 500mA to 2A+ under load. Attempting to drive a motor directly will instantly fry the ATmega328P's internal traces. The direct answer: you must use a dedicated motor driver IC (like the TB6612FNG or DRV8871) that acts as a high-current switch, controlled by the Arduino's low-current logic signals.
Which Motor Type Fits Your Load Profile?
Before selecting a driver, you must match the motor to the mechanical load. Hobbyists often confuse motor types, leading to undersized components or overly complex control schemes. Here is how the four common embedded motor types compare in real-world applications.
| Motor Type | Torque Curve & Profile | Control Needs | Typical Cost |
|---|---|---|---|
| Brushed DC | High starting torque, drops as speed increases. Ideal for continuous rotation (wheels, conveyors). | Simple H-bridge driver for direction; PWM for speed. | $5 - $15 |
| Brushless DC (BLDC) | High efficiency, flat torque curve. Best for high-speed or battery-constrained drones/RC models. | 3-phase ESC (Electronic Speed Controller) or sensorless FOC driver. | $20 - $50 |
| Stepper | High holding torque at zero speed, drops sharply at high RPM. Used for open-loop precise positioning (3D printers). | Step/Dir driver (e.g., TMC2209); requires constant current chopping. | $15 - $40 |
| Servo | Massive torque via internal gearbox, limited to ~180° rotation. Used for closed-loop angular positioning (robot arms). | Direct 50Hz PWM signal from Arduino; internal potentiometer handles feedback. | $10 - $60 |
Note: Steppers and servos are fundamentally different. A stepper holds position via magnetic detents in an open loop, while a servo uses a DC motor with an internal gearbox and potentiometer for closed-loop feedback. Do not use a stepper driver to control a standard hobby servo.
Sizing Rule of Thumb and Worked Load Example
The most common mistake in motor control is sizing the driver for the motor's free-run (no-load) current. When a DC motor starts from a dead stop, or when it stalls against a heavy load, it acts essentially as a short circuit. It draws its maximum stall current. If your driver cannot handle this peak, it will trigger thermal shutdown or melt.
Worked Load Example: 12V Conveyor Belt
Imagine you are building a small conveyor belt to move 5kg of parts. You select a 12V, 100RPM brushed DC gearmotor.
- Motor Free-Run Current: 150mA (0.15A)
- Motor Stall Current: 1.8A (from datasheet)
- Required Driver Peak Rating: 1.8A × 2 = 3.6A minimum
If you choose the classic L298N dual H-bridge module, you will run into trouble. The L298N is rated for 2A continuous per channel. At a 1.8A stall, it is operating at 90% of its absolute maximum, and because it uses older BJT (Bipolar Junction Transistor) technology, it drops about 2.5V across the IC. That means it will dissipate roughly 4.5W of heat (1.8A × 2.5V) instantly, likely triggering its internal thermal shutdown within seconds.
Instead, choose a modern MOSFET-based driver like the Texas Instruments DRV8871 (rated for 3.6A peak) or the TB6612FNG (rated for 3.2A peak). MOSFET drivers have a low Rds(on) resistance, dropping only ~0.2V, meaning they run cool even near their limits.
Driver Selection and Terminal Wiring
Let's look at the wiring for the TB6612FNG, widely considered the best general-purpose dual motor driver for 5V and 3.3V Arduinos and ESP32s in 2026. It replaces the L298N in almost every hobbyist application due to its high efficiency and compact footprint.
TB6612FNG Terminal Identification
| Pin Name | Connection | Function & Notes |
|---|---|---|
| VM | Motor Power (+) | Connect to your main battery/power supply (e.g., 12V). Handles the heavy current. |
| VCC | Logic Power (+) | Connect to Arduino 5V (or ESP32 3.3V). Powers the internal logic gates. |
| GND | Common Ground | Must be shared between the motor power supply and the Arduino. Critical. |
| STBY | Arduino GPIO | Standby pin. Must be pulled HIGH (5V) to enable the driver. Tie to VCC if always on. |
| PWMA / PWMB | Arduino PWM Pin | Controls speed via Pulse Width Modulation (e.g., pins 5, 6, 9 on Uno). |
| AIN1 / AIN2 | Arduino GPIO | Direction control for Motor A. (HIGH/LOW = Forward, LOW/HIGH = Reverse). |
| AO1 / AO2 | Motor A Terminals | Connect directly to the two wires of your brushed DC motor. |
Failure Signatures: Hum, Overheat, and Stall
When a motor circuit fails, it rarely just 'stops working.' It gives you physical and electrical clues. Here is how to diagnose the three most common failure signatures on the bench.
1. The Audible Hum or Whine
Symptom: The motor vibrates and emits a high-pitched whine but doesn't spin, or it spins with a noticeable buzzing sound.
Cause: This is usually a PWM frequency issue or a stall condition. The default Arduino analogWrite() PWM frequency on pins 5 and 6 is ~980Hz, and on pins 3, 9, 10, 11 it is ~490Hz. These frequencies fall squarely in the human hearing range, causing the motor coils to physically vibrate. Alternatively, if the hum occurs at startup, your PWM duty cycle is too low to overcome the motor's static friction (stiction).
Fix: Increase the starting PWM value to 80-100 (out of 255) to break stiction, then drop to your target speed. For the whine, use Arduino timer registers to push the PWM frequency above 20kHz (ultrasonic), though this requires advanced timer configuration.
2. Driver Overheat and Thermal Shutdown
Symptom: The motor runs fine for 10 seconds, then stops. The driver IC is too hot to touch. After a minute, it starts again.
Cause: You are exceeding the continuous current rating of the driver, triggering its internal thermal protection. As noted, BJT drivers like the L298N waste massive amounts of power as heat.
Fix: Measure the actual current draw with a multimeter in series with the motor. If it exceeds the driver's continuous rating, upgrade to a MOSFET-based driver (TB6612FNG, DRV8871) or add active cooling. Ensure your power supply voltage isn't vastly exceeding the motor's nominal voltage, which forces the driver to dissipate the excess via PWM switching losses.
3. The Stall Brownout (Arduino Resetting)
Symptom: The moment the motor starts, the Arduino's onboard LED flickers, the serial monitor disconnects, and the sketch restarts from setup().
Cause: Voltage sag. When the motor hits peak stall current, it pulls the shared power rail down. If the voltage drops below the Arduino's brownout detection threshold (usually ~4.3V for a 5V board), the microcontroller resets to prevent memory corruption.
Fix: Never power high-torque motors from the Arduino's 5V pin. Use a separate power supply for the motor (connected to VM), and ensure the grounds are tied together. Add a bulk electrolytic capacitor (1000µF to 2200µF, rated for at least 25V) directly across the motor driver's VM and GND terminals to supply the instantaneous peak current.
Frequently Asked Questions
Can I control a DC motor with an Arduino without a driver?
No. An Arduino GPIO pin can supply a maximum of 20mA (absolute maximum 40mA, which risks silicon damage). A standard small DC motor requires at least 300mA to 1A to start. Connecting a motor directly to a pin will draw far more current than the ATmega328P can supply, permanently destroying the microcontroller's output transistor. You must use a transistor, MOSFET, or dedicated H-bridge driver IC to isolate the high-current motor load from the low-current logic.
Why does my Arduino reset when the DC motor starts?
This is caused by a brownout due to voltage sag. DC motors draw their highest current (stall current) at the exact moment they start from a dead stop. If your motor and Arduino share the same power supply, this sudden current spike pulls the system voltage down. If it drops below the Arduino's brownout threshold, the board resets. Fix this by using a dedicated power supply for the motor, tying the grounds together, and placing a 1000µF bulk capacitor across the motor's power rails to handle the transient spike.
How do I control the speed of a DC motor using Arduino PWM?
You control speed by sending a Pulse Width Modulation (PWM) signal to the enable or PWM pin on your motor driver using the analogWrite(pin, value) function. The value ranges from 0 (0% duty cycle, motor off) to 255 (100% duty cycle, full speed). Because DC motors have physical stiction, a value of 10 or 20 usually won't spin the motor; you typically need to send a value of at least 60-80 to overcome static friction, after which you can lower it to maintain a slower cruising speed. For a complete reference on PWM pins and frequencies, consult the official Arduino analogWrite documentation.






