trackedbot

L293D Motor Driver Shield

Technical hardware documentation and register mapping for the L293D Motor Driver Shield (compatible with Arduino Uno R3 / Mega 2560, based on the Adafruit Motor Shield v1 architecture) used on the tracked_bot platform.

Reference Documentation:

Datasheet References:

Hardware Images:


📋 Table of Contents

  1. Hardware Overview & Architecture
  2. Electrical & Functional Specifications
  3. Power Supply Configuration & PWR Jumper
  4. Complete Arduino Pin Allocation Matrix
  5. 74HC595 Shift Register Mapping & Protocol
  6. Speed Control via Hardware PWM (Timer0 & Timer2)
  7. Tracked Bot Motor Mapping (M3 & M1)
  8. Servo and Stepper Motor Interfaces
  9. Hardware Protection, Noise Filtering & Troubleshooting

🔧 Hardware Overview & Architecture

The L293D Motor Driver Shield stacks directly onto an Arduino Uno R3 form-factor board. It integrates two dual H-bridge motor driver ICs and an 8-bit serial-in/parallel-out shift register to drive multiple motors while minimizing the required microcontroller GPIO count:

L293D Motor Driver Shield

  1. IC1 (L293D): Quadruple high-current half-H driver. Drives Motor 1 (M1) and Motor 2 (M2). M1 is dedicated to the Right Track on tracked_bot.
  2. IC2 (L293D): Quadruple high-current half-H driver. Drives Motor 3 (M3) and Motor 4 (M4). M3 is dedicated to the Left Track on tracked_bot. By splitting Left and Right tracks onto separate physical L293D ICs (M3 on IC2, M1 on IC1), each motor utilizes an independent thermal package and power stage, eliminating thermal choking and maximizing available motor torque.
  3. IC3 (SN74HC595N): 8-bit serial-in, parallel-out shift register with output latches. Expands 4 microcontroller control lines into 8 direction signals feeding the H-bridges of IC1 and IC2.
  4. Pull-Down Resistor Network: A 10 kΩ resistor array grounds the L293D logic inputs during microcontroller power-up and reset cycles, preventing motors from running unpredictably.
  5. Reset Button: Duplicates the Arduino Uno reset switch to the top of the shield for convenient physical access.
  6. Power Indicator LED: Illuminates when power is supplied to the motor supply rail.

⚡ Electrical & Functional Specifications

Parameter Specification Notes
Motor Supply Voltage ($V_{motor}$) 4.5 V to 24 V DC Absolute maximum rating up to 36 V per L293D datasheet
Logic Supply Voltage ($V_{logic}$) 5.0 V DC Supplied directly from Arduino 5 V rail
Continuous Output Current 600 mA (0.6 A) per channel Depends on ambient temperature and heat dissipation
Peak Output Current 1.2 A per channel Non-repetitive transient / stall current
DC Motor Capacity Up to 4 bidirectional DC motors Individual 8-bit speed selection via PWM
Stepper Motor Capacity Up to 2 stepper motors Unipolar or bipolar (connected to M1–M2 and M3–M4)
Servo Motor Capacity Up to 2 hobby RC servos (5 V) Dedicated headers with a 100 µF filter capacitor
Over-Temperature Protection Internal thermal shutdown Disables output stages under excessive junction heat
Internal Clamping Diodes Built-in flyback suppression diodes Protects against inductive back-EMF spikes

🔋 Power Supply Configuration & PWR Jumper

The shield features a 2-pin screw terminal block labeled EXT_PWR and an adjacent 2-pin jumper header labeled PWR (or PWR_JMP).

[!WARNING] Short-Circuit Danger: Never connect an external power source to the EXT_PWR terminals while the PWR jumper is installed and the Arduino is connected to a computer USB port or DC power jack. Leaving the jumper installed bridges the external motor supply directly to the Arduino’s 5V/VIN rail, which can permanently destroy the Arduino board, the shield, and the host computer’s USB port!

Operating Modes:

Configuration PWR Jumper State Motor Supply Source Arduino Logic Supply Recommended Use Case
Mode 1: Single Supply INSTALLED (Closed) Powered via Arduino DC barrel jack or VIN Same as motor supply Prototyping with low-power motors (<9–12 V) where motor noise does not brown out the MCU.
Mode 2: Dual / Separate Supplies (Recommended) REMOVED (Open) External battery or power supply connected to EXT_PWR (4.5 V – 24 V) USB cable or independent battery/power bank Standard for tracked_bot: Isolates MCU logic from motor current surges, voltage dips, and inductive brush noise.

📌 Complete Arduino Pin Allocation Matrix

The shield occupies digital pins D3 through D12. Digital pins D0, D1, D2, D13 and all analog pins A0 through A5 remain completely untouched by the shield and are exposed for user hardware:

L293D Motor Driver Shield Pinout

Arduino Pin AVR Pin Shield Net / Function Dedicated Usage on Shield tracked_bot Status / Usage
D0 (RX) PD0 Unused by shield None USART0 RX – Serial UART reception from Host (115200 8-N-1)
D1 (TX) PD1 Unused by shield None USART0 TX – Serial UART telemetry transmission to Host (115200 8-N-1)
D2 PD2 Unused by shield None FREE GPIO – External Interrupt 0 (INT0), sensors, encoders
D3 PD3 PWM2B (OC2B) Motor 2 Speed / Enable (IC1 3,4EN) Reserved (unused on tracked platform)
D4 PD4 DIR_CLK 74HC595 Shift Clock 74HC595 Clock Line
D5 PD5 PWM0B (OC0B) Motor 4 Speed / Enable (IC2 3,4EN) Reserved (formerly Right Track)
D6 PD6 PWM0A (OC0A) Motor 3 Speed / Enable (IC2 1,2EN) Left Track PWM Speed (Timer0 Fast PWM)
D7 PD7 DIR_EN 74HC595 Output Enable (active LOW) 74HC595 Output Enable (~OE)
D8 PB0 DIR_SER 74HC595 Serial Data Input 74HC595 Serial Data (SER)
D9 PB1 PWM1A (OC1A) Servo 2 PWM Control (SERVO_2) Reserved / Free for pan-tilt servo
D10 PB2 PWM1B (OC1B) Servo 1 PWM Control (SER1) Reserved / Free for pan-tilt servo
D11 PB3 PWM2A (OC2A) Motor 1 Speed / Enable (IC1 1,2EN) Right Track PWM Speed (Timer2 Fast PWM)
D12 PB4 DIR_LATCH 74HC595 Storage Latch Clock 74HC595 Latch Line (RCLK)
D13 PB5 Unused by shield Arduino Uno onboard LED FREE GPIO / SPI SCK / Built-in LED
A0 PC0 Analog Breakout None Battery Voltage Sense (resistive voltage divider)
A1 PC1 Analog Breakout None HC-SR04 Ultrasonic Trigger / Analog Sensor
A2 PC2 Analog Breakout None HC-SR04 Ultrasonic Echo / Analog Sensor
A3 PC3 Analog Breakout None FREE GPIO / Analog Input
A4 (SDA) PC4 Analog Breakout None I2C SDA – IMU/Gyro (MPU-6050) or OLED display
A5 (SCL) PC5 Analog Breakout None I2C SCL – IMU/Gyro (MPU-6050) or OLED display

🔄 74HC595 Shift Register Mapping & Protocol

The 74HC595 shift register deserializes an 8-bit word clocked in from the microcontroller into the 8 direction control signals feeding the L293D H-bridges.

Subsystem Topology:

flowchart LR
    subgraph MCU ["<b>ATmega328P (Control Pins)</b>"]
        D4["<b>D4 (PD4)</b><br/>Shift Clock"]
        D7["<b>D7 (PD7)</b><br/>Output Enable"]
        D8["<b>D8 (PB0)</b><br/>Serial Data"]
        D12["<b>D12 (PB4)</b><br/>Storage Latch"]
    end

    subgraph ShiftReg ["<b>74HC595 (8-Bit Shift Register)</b>"]
        SH_CP["<b>SH_CP</b><br/>Shift Clock"]
        OE["<b>~OE</b><br/>Output Enable"]
        DS["<b>DS</b><br/>Serial Data In"]
        ST_CP["<b>ST_CP</b><br/>Storage Latch"]
        OUTPUTS["<b>Outputs Q0..Q7</b><br/>Direction Demux Bus"]
    end

    subgraph HBridge ["<b>Dual L293D H-Bridges</b>"]
        M1_DIR["<b>Motor 1 Direction</b><br/>Right Track"]
        M2_DIR["<b>Motor 2 Direction</b><br/>Auxiliary"]
        M3_DIR["<b>Motor 3 Direction</b><br/>Left Track"]
        M4_DIR["<b>Motor 4 Direction</b><br/>Auxiliary"]
    end

    D4 -->|"CLK"| SH_CP
    D7 -->|"EN (~OE)"| OE
    D8 -->|"SER"| DS
    D12 -->|"LATCH"| ST_CP

    SH_CP & OE & DS & ST_CP --> OUTPUTS
    OUTPUTS -->|"Q2, Q3"| M1_DIR
    OUTPUTS -->|"Q1, Q4"| M2_DIR
    OUTPUTS -->|"Q5, Q7"| M3_DIR
    OUTPUTS -->|"Q0, Q6"| M4_DIR

    classDef mcuPin fill:#0c4a6e,stroke:#38bdf8,stroke-width:2px,color:#ffffff;
    classDef regPin fill:#4338ca,stroke:#818cf8,stroke-width:2px,color:#ffffff;
    classDef hBridge fill:#831843,stroke:#f472b6,stroke-width:2px,color:#ffffff;

    class D4,D7,D8,D12 mcuPin;
    class SH_CP,OE,DS,ST_CP,OUTPUTS regPin;
    class M1_DIR,M2_DIR,M3_DIR,M4_DIR hBridge;

    style MCU fill:none,stroke:#38bdf8,stroke-width:2px,stroke-dasharray: 4 4
    style ShiftReg fill:none,stroke:#818cf8,stroke-width:2px,stroke-dasharray: 4 4
    style HBridge fill:none,stroke:#f472b6,stroke-width:2px,stroke-dasharray: 4 4

Output Bit Mapping (Q0 – Q7):

Shift Register Bit Constant Identifier L293D IC & Pin Target Channel Function
Bit 0 SHIFT_BIT_MOTOR4_A IC2 Pin 10 (3A) Motor 4 Direction A
Bit 1 SHIFT_BIT_MOTOR2_A IC1 Pin 2 (1A) Motor 2 Direction A
Bit 2 SHIFT_BIT_MOTOR1_A IC1 Pin 10 (3A) Motor 1 Direction A (Right Track)
Bit 3 SHIFT_BIT_MOTOR1_B IC1 Pin 15 (4A) Motor 1 Direction B (Right Track)
Bit 4 SHIFT_BIT_MOTOR2_B IC1 Pin 7 (2A) Motor 2 Direction B
Bit 5 SHIFT_BIT_MOTOR3_A IC2 Pin 2 (1A) Motor 3 Direction A (Left Track)
Bit 6 SHIFT_BIT_MOTOR4_B IC2 Pin 15 (4A) Motor 4 Direction B
Bit 7 SHIFT_BIT_MOTOR3_B IC2 Pin 7 (2A) Motor 3 Direction B (Left Track)

Shift Register Control Protocol:

Transmission of an 8-bit direction byte from ATmega328P follows this sequence:

  1. Pull DIR_LATCH (PB4 / D12) LOW to prepare the storage register.
  2. For each bit (from MSB Bit 7 down to LSB Bit 0):
    • Set DIR_CLK (PD4 / D4) LOW.
    • Output the data bit value on DIR_SER (PB0 / D8).
    • Set DIR_CLK HIGH (data is shifted into the 74HC595 on the rising clock edge).
  3. Pull DIR_LATCH HIGH (latches the internal 8-bit shift buffer onto output pins Q0–Q7).
  4. Maintain DIR_EN (PD7 / D7) LOW to keep the outputs enabled (active LOW).
sequenceDiagram
    autonumber
    participant MCU as ATmega328P (Firmware)
    participant LATCH as DIR_LATCH (PB4 / D12)
    participant CLK as DIR_CLK (PD4 / D4)
    participant SER as DIR_SER (PB0 / D8)
    participant REG as 74HC595 (Shift Register)
    participant OUT as L293D Inputs (Q0..Q7)

    Note over MCU,LATCH: Step 1: Open Storage Register
    MCU->>LATCH: Pull LOW (ST_CP)
    loop Step 2: Shift 8 Bits (MSB Bit 7 down to LSB Bit 0)
        MCU->>CLK: Pull LOW (SH_CP)
        MCU->>SER: Set Bit Data Level (DS)
        MCU->>CLK: Pull HIGH (Rising Edge)
        REG->>REG: Shift bit into internal stage
    end
    Note over MCU,LATCH: Step 3: Latch Parallel Outputs
    MCU->>LATCH: Pull HIGH (ST_CP)
    REG->>OUT: Update outputs Q0..Q7 simultaneously

Signal Waveform Timing:

Serial Shift Timing Diagram:

 DIR_LATCH (PB4) ---\___________________________________________/--- (ST_CP)
                     Bit 7       Bit 6               Bit 0
 DIR_CLK   (PD4) ___/---\___/---\___/---\___ ... _____/---\________ (SH_CP)
 DIR_SER   (PB0) ===< D7  >===< D6  >=================< D0  >====== (DS)
 Outputs (Q0..Q7):  [Previous Latch State Held]        [New State Output]

See implementation in shift_reg.c and shift_reg.h.


⏱️ Speed Control via Hardware PWM (Timer0 & Timer2)

Speed regulation is performed by driving the L293D enable inputs (1,2EN) with hardware Pulse Width Modulation (PWM):

flowchart LR
    subgraph MCU_CTRL ["<b>Microcontroller & Shift Register</b>"]
        PWM_M3["<b>PD6 / OC0A</b><br/>Timer0 Fast PWM"]
        DIR_M3_A["<b>74HC595 Q5</b><br/>Dir A - M3_A"]
        DIR_M3_B["<b>74HC595 Q7</b><br/>Dir B - M3_B"]

        PWM_M1["<b>PB3 / OC2A</b><br/>Timer2 Fast PWM"]
        DIR_M1_A["<b>74HC595 Q2</b><br/>Dir A - M1_A"]
        DIR_M1_B["<b>74HC595 Q3</b><br/>Dir B - M1_B"]
    end

    subgraph IC2 ["<b>L293D IC2 (Left Track Actuation)</b>"]
        EN_IC2["<b>1,2EN (Pin 1)</b><br/>PWM Speed Enable"]
        A1_IC2["<b>1A (Pin 2)</b><br/>Half-Bridge 1"]
        A2_IC2["<b>2A (Pin 7)</b><br/>Half-Bridge 2"]
        OUT_M3["<b>M3 Channels</b><br/>Pins 3 & 6"]
        EN_IC2 & A1_IC2 & A2_IC2 --> OUT_M3
    end

    subgraph IC1 ["<b>L293D IC1 (Right Track Actuation)</b>"]
        EN_IC1["<b>1,2EN (Pin 1)</b><br/>PWM Speed Enable"]
        A1_IC1["<b>1A / 3A</b><br/>Half-Bridge 1"]
        A2_IC1["<b>2A / 4A</b><br/>Half-Bridge 2"]
        OUT_M1["<b>M1 Channels</b><br/>Pins 11 & 14"]
        EN_IC1 & A1_IC1 & A2_IC1 --> OUT_M1
    end

    subgraph Motors ["<b>Track Actuators</b>"]
        LEFT_TRACK["<b>Left Track Motor (M3)</b>"]
        RIGHT_TRACK["<b>Right Track Motor (M1)</b>"]
    end

    PWM_M3 -->|"PWM Duty Cycle"| EN_IC2
    DIR_M3_A -->|"Direction Bit"| A1_IC2
    DIR_M3_B -->|"Direction Bit"| A2_IC2
    OUT_M3 ==>|"Bidirectional Drive"| LEFT_TRACK

    PWM_M1 -->|"PWM Duty Cycle"| EN_IC1
    DIR_M1_A -->|"Direction Bit"| A1_IC1
    DIR_M1_B -->|"Direction Bit"| A2_IC1
    OUT_M1 ==>|"Bidirectional Drive"| RIGHT_TRACK

    classDef mcuStyle fill:#0c4a6e,stroke:#38bdf8,stroke-width:2px,color:#ffffff;
    classDef hBridge fill:#831843,stroke:#f472b6,stroke-width:2px,color:#ffffff;
    classDef motorStyle fill:#701a75,stroke:#e879f9,stroke-width:2px,color:#ffffff;

    class PWM_M3,DIR_M3_A,DIR_M3_B,PWM_M1,DIR_M1_A,DIR_M1_B mcuStyle;
    class EN_IC2,A1_IC2,A2_IC2,OUT_M3,EN_IC1,A1_IC1,A2_IC1,OUT_M1 hBridge;
    class LEFT_TRACK,RIGHT_TRACK motorStyle;

    style MCU_CTRL fill:none,stroke:#38bdf8,stroke-width:2px,stroke-dasharray: 4 4
    style IC2 fill:none,stroke:#f472b6,stroke-width:2px,stroke-dasharray: 4 4
    style IC1 fill:none,stroke:#f472b6,stroke-width:2px,stroke-dasharray: 4 4
    style Motors fill:none,stroke:#e879f9,stroke-width:2px,stroke-dasharray: 4 4
Fast PWM Waveform Timing Diagram:

TCNT0 / TCNT2 (Counters)
    ^
255 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TOP
    |            /|            /|            /|            /|
OCR | - - - - - / | - - - - - / | - - - - - / | - - - - - / | - - - - - OCR0A / OCR2A
    |          /  |          /  |          /  |          /  |
  0 +---------+---+---------+---+---------+---+---------+---+---------> Time
Output Pins: PD6 (OC0A, M3 Left) / PB3 (OC2A, M1 Right)
  1 |=========|   |=========|   |=========|   |=========|   |
  0 +---------+---+---------+---+---------+---+---------+---+--------->
    |<--Duty->|   |<--Duty->|   |<--Duty->|   |<--Duty->|   |
    |<------ Period ~1.024ms (976 Hz) ------->|

Fast PWM Configuration on ATmega328P:

A frequency of ~976 Hz balances low acoustic motor whine with minimal switching losses in the bipolar L293D output transistors.


🏎️ Tracked Bot Motor Mapping (M3 & M1)

The tracked platform utilizes Motor 3 on IC2 for the left track drive and Motor 1 on IC1 for the right track drive:

H-Bridge Control Truth Table:

Channel Desired Motion PWM Duty (OCRxx) Dir A (74HC595) Dir B (74HC595) Output Terminals Resulting State
M3 (Left Track, IC2) Forward 1 .. 255 MOTOR3_A (bit 5) = 1 MOTOR3_B (bit 7) = 0 Out 1 = HIGH, Out 2 = LOW Track drives forward
  Reverse 1 .. 255 MOTOR3_A (bit 5) = 0 MOTOR3_B (bit 7) = 1 Out 1 = LOW, Out 2 = HIGH Track drives reverse
  Dynamic Brake 1 .. 255 MOTOR3_A (bit 5) = 0 MOTOR3_B (bit 7) = 0 Out 1 = LOW, Out 2 = LOW Active dynamic braking
  Coast / Off 0 Don’t care (X) Don’t care (X) High-Z floating Track coasts freely
M1 (Right Track, IC1) Forward 1 .. 255 MOTOR1_A (bit 2) = 1 MOTOR1_B (bit 3) = 0 Out 1 = HIGH, Out 2 = LOW Track drives forward
  Reverse 1 .. 255 MOTOR1_A (bit 2) = 0 MOTOR1_B (bit 3) = 1 Out 1 = LOW, Out 2 = HIGH Track drives reverse
  Dynamic Brake 1 .. 255 MOTOR1_A (bit 2) = 0 MOTOR1_B (bit 3) = 0 Out 1 = LOW, Out 2 = LOW Active dynamic braking
  Coast / Off 0 Don’t care (X) Don’t care (X) High-Z floating Track coasts freely

Firmware driver references:


🤖 Servo and Stepper Motor Interfaces

While tracked_bot primarily uses DC gearmotors on M3 and M4, the shield natively supports other actuator types:

1. Hobby RC Servo Motors (SER1 & SERVO_2):

2. Stepper Motors:


🛡️ Hardware Protection, Noise Filtering & Troubleshooting

1. Inrush Current & Motor Stall:

2. EMI Suppression (Brush Noise):

3. Thermal Considerations:

4. Common Troubleshooting Checklist:

Symptom Probable Cause Corrective Action
Motors do not rotate Power jumper missing or no voltage on EXT_PWR Check LED indicator. Verify external battery voltage and connection polarity on EXT_PWR.
MCU reboots on motor startup Voltage sag / brownout on shared power rail Remove PWR jumper and power Arduino via dedicated USB supply.
One track rotates backwards Inverted motor polarity or shift register bit order Swap the motor wires on the M3/M4 screw terminal, or invert direction flags in l293d_shield.c.
Motor hums but cannot move PWM duty cycle is below the motor deadband Increase OCR0x starting threshold (typically duty cycle > 25–30% is needed to overcome gearbox friction).
Servo twitches / jitters Insufficient 5 V current or supply ripple Use an external 5 V BEC/regulator for servos or avoid powering heavy servos from the Arduino 5 V pin.