UUtzinger_DRV8704  0.1.1
Arduino library for the DRV8704 dual H-bridge gate driver
UUtzinger_DRV8704

Arduino library for the Texas Instruments DRV8704 dual H-bridge gate driver.

Generated API docs are available at: https://uutzinger.github.io/Arduino_DRV8704/

Purpose

This library exposes the DRV8704 through one consistent control model:

  • set bridge direction explicitly
  • choose a bridge runtime state:
    • Coast
    • Brake
    • CurrentDrive
    • PwmDriveWithCurrentLimit
  • configure current limit once at the chip level
  • use presets to choose reasonable decay and timing behavior

It also provides:

  • SPI register access
  • fault and status helpers
  • platform PWM backends

Hardware Model

The DRV8704 is not a pure SPI motor controller.

It has two separate control surfaces:

  • SPI:
    • configuration
    • diagnostics
    • fault/status
    • current-limit related registers
  • bridge inputs AIN1/AIN2/BIN1/BIN2:
    • forward/reverse/brake/coast behavior
    • external or library-generated PWM

Important hardware constraint:

  • ISGAIN and TORQUE are chip-global
  • therefore the high-level current-limit API is chip-global too

Required Wiring

Minimum useful connections:

  • SCS to a GPIO used as chip select
  • SCLK, SDATI, SDATO to the MCU SPI bus
  • AIN1, AIN2, BIN1, BIN2 to GPIO or PWM-capable pins

Recommended optional connections:

  • SLEEPn
  • RESET
  • FAULTn with pull-up

Board-level requirements still come from the DRV8704 datasheet:

  • external N-channel MOSFET H-bridges
  • current shunts at the ISEN inputs
  • proper VM/VCP/VINT/V5 bypassing
  • pull-ups for FAULTn and SDATO

Quick Start

#include <drv8704.h>
DRV8704* driver = nullptr;
void setup() {
pins.csPin = 10;
pins.sleepPin = 9;
pins.resetPin = 8;
pins.faultPin = 7;
pins.ain1Pin = 5;
pins.ain2Pin = 6;
pins.bin1Pin = 3;
pins.bin2Pin = 4;
static DRV8704 drv(pins);
driver = &drv;
if (!driver->begin()) {
return;
}
}
void loop() {
}
Arduino-facing DRV8704 device driver class.
Definition: drv8704.h:21
bool begin()
Initialize GPIO and SPI state for the device.
Definition: drv8704.cpp:35
Public Arduino API for the DRV8704 dual H-bridge gate driver.
Pin assignment bundle for a DRV8704 instance.
Definition: drv8704_types.h:181
int8_t ain2Pin
Definition: drv8704_types.h:187
int8_t bin1Pin
Definition: drv8704_types.h:188
int8_t faultPin
Definition: drv8704_types.h:185
int8_t resetPin
Definition: drv8704_types.h:184
int8_t sleepPin
Definition: drv8704_types.h:183
int8_t bin2Pin
Definition: drv8704_types.h:189
uint8_t csPin
Definition: drv8704_types.h:182
int8_t ain1Pin
Definition: drv8704_types.h:186

Control Model

Direction

Direction is separate from magnitude control:

  • setDirection(BridgeId bridge, Direction direction)

This direction is then used by both:

  • setCurrent(...)
  • setSpeed(...)

Static Bridge States

Use explicit static bridge commands when you want an immediate override:

  • coast(BridgeId bridge)
  • brake(BridgeId bridge)

These states override active current-drive or PWM-drive behavior on that bridge immediately.

Current Drive

Use current drive when you want the DRV8704 internal current chopper to regulate a bridge in the currently selected direction.

Current drive is intended for inductive loads. Do not present it as a primary control method for resistive heaters.

Primary API:

  • setShuntResistance(float ohms) depends on your hardware design
  • setShuntResistance(BridgeId bridge, float ohms)
  • setCurrentModePreset(CurrentModePreset preset) timing baseline for heater, TEC, or motor loads
  • setCurrentLimit(float amps)
  • setCurrent(BridgeId bridge, float amps)
  • disableCurrentLimit()
  • currentLimitResult()

Control flow:

  1. set shunt value
  2. choose preset
  3. set direction
  4. call setCurrent(...)

Current-limit equation used by the driver:

ICHOP = 2.75 * TORQUE / (256 * ISGAIN * RISENSE)

The implementation chooses the highest usable gain first because that gives the finest current resolution for a given shunt.

Important limitation:

  • the DRV8704 shunt path is used for internal current chopping and comparator behavior
  • the chip does not provide direct current telemetry over SPI
  • currentLimitResult() reports the programmed current-trip settings, not measured load current
  • on mostly resistive heaters, bench results may not track requested current linearly even after timing optimization
  • for heaters, use PWM mode for control and treat current limit as protection

PWM With Current Limit

Use PWM mode when you want open-loop duty control while keeping the DRV8704 current limit active during PWM on-time. This is the recommended control path for resistive heaters.

Primary API:

  • beginPwmMode(const DRV8704PwmConfig& config)
  • setPwmFrequency(uint32_t hz)
  • setCurrentLimit(float amps)
  • setDirection(BridgeId bridge, Direction direction)
  • setSpeed(BridgeId bridge, float percent)
  • pwmCapability()

Behavior:

  • setSpeed(..., 0): behaves like coast(...)
  • setSpeed(..., 100): constant-on directional input, no PWM toggling
  • 0 < speed < 100: one bridge input is PWM, the complementary input is held low

High-level PWM control is intentionally framed as PWM with current limit. If you want effectively unbounded drive, deliberately program a very high current limit instead of using a separate unsafe mode.

Default library PWM settings now start from:

  • 5 kHz
  • 10-bit preferred resolution

The interactive examples follow that model by default:

  • pwm ... commands apply PWM with the stored current limit active
  • full ... is the explicit no-current-limit comparison mode
  • DRV8704_Test is the main engineering console for bring-up and bench tuning

Presets

The presets are starting points for current-limit timing, not guaranteed final answers.

  • Heater
    • resistive heater-oriented timing baseline
    • bench-tuned default uses TOFF=0x40, TBLANK=0x00, AutoMixed decay on the reference heater-pad setup
    • use this preset with PWM mode for heater control
  • ThermoelectricCooler
    • mixed-decay starting point for weakly inductive bipolar loads
  • MotorSmallInductance
    • shorter timing, more aggressive correction
  • MotorMediumInductance
    • general motor default
  • MotorLargeInductance
    • longer timing for slower current change

The implementation also adjusts preset timing when PWM mode is active at higher frequency. Validate the preset on real hardware and retune as needed.

Mode Transitions

The bridge follows the most recent command on that bridge.

Examples:

  • current drive to coast:
    • coast(bridge)
  • current drive to brake:
    • brake(bridge)
  • current drive to PWM with current limit:
    • beginPwmMode(...)
    • setCurrentLimit(...)
    • setDirection(...)
    • setSpeed(...)
  • PWM with current limit to current drive:
    • setDirection(...)
    • setCurrent(...)

The current-limit configuration remains programmed until you change it or call disableCurrentLimit().

Examples

The example set is organized by workflow:

  • BasicBringup
  • RegisterHealthCheck
  • DRV8704_Test
  • BridgeControlDemo
  • CurrentModeDemo
  • CurrentPresetDemo
  • Current_Test
  • PwmModeDemo
  • PWM_Test

Example Snippets

Current Drive

driver.setShuntResistance(0.0005f);
driver.setCurrent(BridgeId::A, 4.0f);
bool setCurrent(BridgeId bridge, float amps)
Program the chip for current drive on one bridge using the stored direction.
Definition: drv8704_current.cpp:263
bool setShuntResistance(float ohms)
Set one shunt resistance value for both bridges in current mode.
Definition: drv8704_current.cpp:108
bool setCurrentModePreset(CurrentModePreset preset)
Select the predefined timing and decay preset used by current mode.
Definition: drv8704_current.cpp:122
bool setDirection(BridgeId bridge, Direction direction)
Set the direction used by high-level current-drive and PWM-drive commands.
Definition: drv8704_current.cpp:148

Interactive Engineering Test

Use examples/DRV8704_Test when you need one serial console for:

  • bring-up checks after BasicBringup and RegisterHealthCheck
  • current-mode testing and timing sweeps
  • PWM duty, frequency, and resolution testing
  • comparing current-limited drive, PWM drive, and full drive on hardware

PWM With Current Limit

pwm.frequencyHz = 5000;
driver.setCurrentLimit(4.0f);
driver.beginPwmMode(pwm);
driver.setSpeed(BridgeId::A, 35.0f);
bool beginPwmMode(const DRV8704PwmConfig &config=DRV8704PwmConfig())
Enable board-specific PWM generation for the DRV8704 input pins.
Definition: drv8704_bridge.cpp:190
bool setCurrentLimit(float amps)
Program the chip-global current limit in amperes without changing bridge state.
Definition: drv8704_current.cpp:248
bool setSpeed(BridgeId bridge, float speedPercent)
Apply an open-loop speed command to one bridge using hardware PWM.
Definition: drv8704_bridge.cpp:292
Requested PWM generator settings.
Definition: drv8704_types.h:322
uint32_t frequencyHz
Definition: drv8704_types.h:323
uint8_t preferredResolutionBits
Definition: drv8704_types.h:324

Coast And Brake

void brake(BridgeId bridge)
Drive one bridge to brake.
Definition: drv8704_bridge.cpp:155
void coast(BridgeId bridge)
Drive one bridge to coast.
Definition: drv8704_bridge.cpp:145

PWM Backends

Supported PWM backends:

  • generic Arduino fallback using analogWrite()
  • ESP32 LEDC backend
  • Teensy hardware PWM backend
  • STM hardware PWM backend

The generic Arduino backend does not control PWM frequency directly. Hardware-specific backends report achieved frequency and duty resolution through pwmCapability().

Faults And Diagnostics

Fault handling is available through:

  • the STATUS register
  • the optional hardware FAULTn pin
  • healthCheck() for startup plausibility and fault reporting

Useful low-level helpers:

  • readRegister()
  • writeRegister()
  • updateRegister()
  • applyConfig()
  • readStatus()
  • hasFault()
  • clearFaults()

Limitations

  • current-limit settings are chip-global, not per bridge
  • if bridge A and bridge B use different shunts, the same chip-global current-limit setting produces different actual limits on the two bridges
  • PWM mode is open-loop duty control, not closed-loop speed control
  • the DRV8704 does not report measured current over SPI
  • preset tuning is only an initial heuristic and still needs hardware validation

Documentation

  • README.md provides the top-level usage model
  • docs/ contains generated Doxygen output when documentation has been built