The Arduino L298N motor driver is a dual full-bridge module used to control the speed and direction of two DC motors independently. To get it running, you need an Arduino Uno R3, a standard red L298N breakout board, and a power supply providing at least 7V to 12V (to overcome the IC's internal 2V to 3V voltage drop). Wire the ENA and ENB pins to Arduino PWM pins 5 and 6, route IN1 through IN4 to digital pins 7 through 10, and tie the grounds together. Below is the exact pinout, complete C++ code with bounds-checking, and the three hardware checks you must perform when the motors refuse to spin.

The Direct Answer: Parts and Pin Mapping

Difficulty: Beginner/Intermediate | Time: 45 Minutes | Cost: ~$20-$35

Exact Parts List

  • Microcontroller: Arduino Uno R3 (ATmega328P). Note: If using an Uno R4 Minima, be aware its logic is 5V tolerant but operates natively at 5V; the code remains identical.
  • Motor Driver: Standard red Dual H-Bridge L298N breakout board (STMicroelectronics L298N IC or standard clone). Expect to pay $3 to $6 for clones.
  • Motors: 2x TT Gear Motors (3-6V DC, 200 RPM, yellow plastic body) or 12V DC wheelchair/scooter motors. Do not exceed 2A continuous per channel.
  • Power Supply: 2S LiPo (7.4V) or 3S LiPo (11.1V) battery pack, or a 6x AA battery holder (9V). Do not power motors directly from the Arduino's USB 5V rail.
  • Wiring: 22 AWG stranded silicone jumper wires.

L298N to Arduino Pin Mapping

L298N Pin Arduino Uno R3 Pin Function & Notes
ENA Pin 5 (PWM) Motor A speed control. Remove physical jumper cap.
IN1 Pin 7 (Digital) Motor A direction logic 1.
IN2 Pin 8 (Digital) Motor A direction logic 2.
IN3 Pin 9 (Digital) Motor B direction logic 1.
IN4 Pin 10 (Digital) Motor B direction logic 2.
ENB Pin 6 (PWM) Motor B speed control. Remove physical jumper cap.
12V (VCC) Battery Positive (+) Main motor power input (7V to 12V nominal, 35V absolute max).
GND Battery Negative (-) & Arduino GND Critical: Must share a common ground with the Arduino.
5V None (or Arduino 5V) Output from onboard 7805 regulator if 12V jumper is ON. See debugging section.

Complete Compilable Code (Targeting Uno R3)

This sketch targets the Arduino Uno R3. It includes explicit pin definitions, a setup routine that ensures motors are braked on boot, and a custom setMotorSpeed() function that includes serial error handling to catch out-of-bounds PWM values before they cause erratic hardware behavior.

// Target Board: Arduino Uno R3 (ATmega328P)
// Module: Standard Red Dual H-Bridge L298N Breakout

// --- Pin Definitions ---
const int ENA = 5;   // PWM pin for Motor A speed
const int IN1 = 7;   // Digital pin for Motor A direction
const int IN2 = 8;   // Digital pin for Motor A direction
const int IN3 = 9;   // Digital pin for Motor B direction
const int IN4 = 10;  // Digital pin for Motor B direction
const int ENB = 6;   // PWM pin for Motor B speed

void setup() {
  Serial.begin(115200);
  
  // Configure pin modes
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  
  // Brake both motors on startup to prevent runaway
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
  
  Serial.println("[SYS] L298N Initialized. Motors braked.");
}

// Function with bounds checking and error handling
void setMotorSpeed(int motorID, int speed) {
  // Validate PWM bounds (0 to 255 for 8-bit Uno R3 PWM)
  if (speed < -255 || speed > 255) {
    Serial.print("[ERR] PWM value out of bounds (0-255): ");
    Serial.println(speed);
    return;
  }
  
  int dirPin1, dirPin2, pwmPin;
  if (motorID == 'A') {
    dirPin1 = IN1; dirPin2 = IN2; pwmPin = ENA;
  } else if (motorID == 'B') {
    dirPin1 = IN3; dirPin2 = IN4; pwmPin = ENB;
  } else {
    Serial.println("[ERR] Invalid Motor ID. Use 'A' or 'B'.");
    return;
  }
  
  if (speed > 0) {
    digitalWrite(dirPin1, HIGH);
    digitalWrite(dirPin2, LOW);
  } else if (speed < 0) {
    digitalWrite(dirPin1, LOW);
    digitalWrite(dirPin2, HIGH);
  } else {
    digitalWrite(dirPin1, LOW);
    digitalWrite(dirPin2, LOW); // Brake
  }
  
  analogWrite(pwmPin, abs(speed));
}

void loop() {
  // Demo sequence: Forward, Stop, Reverse
  Serial.println("[ACT] Moving Forward at 75% duty cycle");
  setMotorSpeed('A', 190); // ~75% of 255
  setMotorSpeed('B', 190);
  delay(2000);
  
  // Trigger intentional error to test serial handler
  setMotorSpeed('A', 300); 
  
  Serial.println("[ACT] Braking");
  setMotorSpeed('A', 0);
  setMotorSpeed('B', 0);
  delay(1000);
  
  Serial.println("[ACT] Reversing at 50% duty cycle");
  setMotorSpeed('A', -127);
  setMotorSpeed('B', -127);
  delay(2000);
  
  setMotorSpeed('A', 0);
  setMotorSpeed('B', 0);
  delay(3000);
}

Debugging: First Three Checks When Motors Won't Spin

When you upload the code and nothing happens, do not rewrite your software. 95% of L298N failures are hardware wiring traps. Check these three things first:

  1. Verify the Common Ground: The Arduino GND and the L298N GND must be connected. If they are not, the Arduino's 5V logic signals have no reference voltage, and the L298N opto-isolators/logic gates will ignore your HIGH/LOW commands. Use your multimeter in continuity mode to verify < 1 ohm between the Arduino GND pin and the L298N GND screw terminal.
  2. Check the Physical Enable Jumpers: Look at the ENA and ENB pins on the L298N board. By default, they have black plastic jumper caps connecting them to the 5V rail. This forces the motors to run at 100% speed and ignores your Arduino PWM pins. Remove both jumper caps and wire ENA and ENB to your Arduino PWM pins.
  3. Inspect the 12V/5V Regulator Jumper: Near the power terminals, there is a jumper cap next to the 5V output pin.
    • If your battery is > 7V: Leave the jumper ON. The onboard 78M05 regulator steps the voltage down to 5V for the logic chip.
    • If your battery is < 7V (e.g., 4x AA = 6V): Remove the jumper, or the regulator will brown out and kill the logic. You must then supply 5V to the 5V pin manually from the Arduino.
Bench Tip: The BJT Voltage Drop Trap
Unlike modern MOSFET-based drivers (like the DRV8833), the L298N uses older Bipolar Junction Transistors. According to the STMicroelectronics L298N datasheet, the IC drops roughly 2V to 3V across the H-bridge. If you power the module with a 5V USB power bank, your motors will only receive ~2.5V and will likely stall. Always supply at least 7V to the 12V terminal for reliable operation.

Resolving Common IDE and Runtime Errors

If you are using third-party libraries or copying code from forums, you may hit compiler or runtime errors. Here is how to fix the most frequent ones.

Error 1: fatal error: L298N.h: No such file or directory

Ranked Causes:

  1. Missing Library: You copied code that relies on a specific wrapper library (like Andrea Lombardo's L298N library) but haven't installed it. Fix: Go to Sketch > Include Library > Manage Libraries, search for "L298N", and install it.
  2. Typo in Include Statement: C++ is case-sensitive. #include <l298n.h> will fail on Linux/macOS file systems. Fix: Change it to #include <L298N.h>.

Error 2: [ERR] PWM value out of bounds (0-255) (Serial Monitor Output)

Ranked Causes:

  1. Math Overflow: You are calculating speed using mapping functions (e.g., map(joystick, 0, 1023, -300, 300)) without constraining the output. Fix: Wrap your speed variable in constrain(val, -255, 255) before passing it to analogWrite().
  2. Wrong Board Architecture: If you migrate this exact code to an Arduino Due or Portenta, PWM resolution might be 12-bit (0-4095). The code's bounds checker will flag 400 as an error. Fix: Adjust the bounds check in the setMotorSpeed function to match your target board's analogWrite resolution.

Simplifying and Extending Your Drivetrain

How to Simplify the Build

If writing raw digitalWrite and analogWrite sequences feels tedious, simplify your code by using the L298N library by Andrea Lombardo via the Arduino Library Manager. It abstracts the pin logic into simple commands like motor.forward(150) and handles the internal pin state tracking for you. This reduces a 100-line custom sketch to about 20 lines.

How to Extend the Build

  • Add Encoder Feedback: The L298N is "dumb"—it doesn't know if the motor is actually spinning or stalled. Extend the build by adding optical or magnetic quadrature encoders to the motor shafts and wiring them to the Arduino's hardware interrupt pins (Pins 2 and 3 on the Uno R3) to implement a PID speed controller.
  • Migrate to ESP32: If you need WiFi for a remote-control rover, swap the Uno R3 for an ESP32 DevKit V1. Warning: The ESP32 is a 3.3V logic device. While the L298N will usually recognize 3.3V as a valid HIGH signal, it is out of spec. For reliable operation, run the ESP32's 3.3V logic through a bidirectional logic level shifter (like the Texas Instruments TXS0108E) before hitting the L298N IN pins.

Frequently Asked Questions

Can I power the Arduino from the L298N 5V pin?

Yes, but with strict limits. If your motor supply is between 7V and 12V, and the 5V regulator jumper is ON, the L298N's onboard 78M05 linear regulator will output 5V. You can wire this to the Arduino's 5V pin (bypassing the Arduino's USB voltage regulator). However, the 78M05 can only supply about 500mA, and it must share that current with the L298N's internal logic. If you have sensors, servos, or an LCD screen attached to the Arduino, you will likely brown out the system. For complex builds, power the Arduino independently.

Why does my L298N get hot and shut down?

The L298N IC has a built-in thermal shutdown feature that triggers at roughly 150°C (302°F). Because it uses BJT technology, it dissipates a massive amount of heat as waste. If you are pulling 1.5A per channel, the IC is burning off 3 to 4 watts of heat. The small aluminum heatsink glued to the top of the chip is rarely sufficient for continuous high loads. If it shuts down, add active cooling (a 5V fan) or, better yet, replace the L298N with a modern MOSFET driver like the TB6612FNG or DRV8871, which run significantly cooler.

How do I control motor speed with the L298N?

Speed is controlled via Pulse Width Modulation (PWM) on the ENA and ENB pins. By sending a PWM signal (using analogWrite on the Arduino), you rapidly switch the motor power on and off. A value of 255 is 100% duty cycle (full speed), 127 is roughly 50% speed, and 0 is stopped. Note that DC motors have a "stall voltage"—a PWM value of 30 might not provide enough average voltage to overcome the motor's internal friction, resulting in a humming sound without rotation. You usually need to start at a PWM value of 80-100 to get the wheels moving.