drv8301-dd

Crates.iodrv8301-dd
lib.rsdrv8301-dd
version0.2.0
created_at2025-11-30 22:23:57.574439+00
updated_at2025-11-30 22:47:57.363968+00
descriptionA driver for the DRV8301 gate driver IC (uses device-driver crate)
homepage
repositoryhttps://github.com/okhsunrog/drv8301-dd
max_upload_size
id1958919
size2,868,660
Danila Gornushko (okhsunrog)

documentation

https://docs.rs/drv8301-dd

README

DRV8301 Gate Driver IC Driver (drv8301-dd)

Crates.io Docs.rs License: MIT OR Apache-2.0

This crate provides a no_std driver for the DRV8301 three-phase gate driver IC, a highly integrated motor driver from Texas Instruments. The project aims to support the full functionality of the DRV8301, leveraging the device-driver crate with a declarative YAML manifest (device.yaml) for a robust, type-safe register map definition. The low-level API covers 100% of the DRV8301's registers, with device.yaml providing a comprehensive and accurate description of all registers and their fields.

Overview

The drv8301-dd driver offers:

  • Declarative Configuration: The DRV8301 register map is defined in device.yaml, enabling device-driver to generate a type-safe, low-level register access API. This approach enhances maintainability and extensibility.
  • Unified Async/Blocking API: Uses the bisync crate to provide both asynchronous (Drv8301Async) and blocking (Drv8301) drivers from the same codebase, with no feature flags required.
  • High-Level and Low-Level APIs:
    • High-level methods simplify tasks like configuring overcurrent protection, PWM modes, and shunt amplifier gains.
    • Low-level API (via the ll field of the Drv8301/Drv8301Async struct) offers direct, type-safe access to all registers defined in device.yaml.
  • Motor Control Features: Manages gate driver outputs, overcurrent protection, temperature monitoring, and current sensing.
  • no_std and no-alloc: Optimized for bare-metal and RTOS environments.
  • Optional Logging: Supports defmt and the log facade for debugging.

Features

  • Declarative Register Map: Defined in device.yaml.
  • Unified Async/Blocking API: Both async and blocking drivers are always available; no feature flags required.
  • Type-Safe Register Access: Generated by device-driver.
  • Comprehensive Control: (See device.yaml for details)
    • Three-phase half-bridge gate driver outputs
    • Configurable overcurrent protection (VDS thresholds, OCP modes)
    • Current shunt amplifiers with selectable gain (10/20/40/80 V/V)
    • PWM mode selection (6-PWM or 3-PWM)
    • Status monitoring (faults, temperature, voltage)
    • DC calibration modes
  • no_std and no-alloc.
  • Optional Logging: Supports defmt and log facade.

Getting Started

  1. Add drv8301-dd to Cargo.toml:

    [dependencies]
    drv8301-dd = "0.2.0"
    # For blocking usage (Drv8301):
    embedded-hal = "1.0.0"
    # For async usage (Drv8301Async):
    embedded-hal-async = "1.0.0"
    

    Note: Add the relevant embedded-hal crate for your use case, no need for both

    • Use embedded-hal for blocking drivers (Drv8301)
    • Use embedded-hal-async for async drivers (Drv8301Async)
  2. Instantiate the driver with your SPI device:

    • Blocking:

      use drv8301_dd::{Drv8301, OcAdjSet, OcpMode, ShuntAmplifierGain};
      use embedded_hal::spi::SpiDevice;
      
      let spi_device = /* your SPI device */;
      let mut drv = Drv8301::new(spi_device);
      
      // Configure overcurrent protection
      drv.set_oc_threshold(OcAdjSet::Vds250mV)?;
      drv.set_ocp_mode(OcpMode::CurrentLimit)?;
      
      // Set PWM mode and amplifier gain
      drv.set_pwm_mode(false)?;  // 6-PWM mode
      drv.set_shunt_amplifier_gain(ShuntAmplifierGain::Gain20)?;
      
      // Read device status
      let device_id = drv.get_device_id()?;
      let has_fault = drv.has_fault()?;
      
      // Get comprehensive fault status
      let status = drv.get_fault_status()?;
      if status.has_overcurrent() {
          // Handle overcurrent on any phase
      }
      if status.phase_a_overcurrent() {
          // Phase A specific fault
      }
      
    • Async:

      use drv8301_dd::{Drv8301Async, OcAdjSet, OcpMode, ShuntAmplifierGain};
      use embedded_hal_async::spi::SpiDevice;
      
      let spi_device = /* your SPI device */;
      let mut drv = Drv8301Async::new(spi_device);
      
      // Configure overcurrent protection
      drv.set_oc_threshold(OcAdjSet::Vds250mV).await?;
      drv.set_ocp_mode(OcpMode::CurrentLimit).await?;
      
      // Set PWM mode and amplifier gain
      drv.set_pwm_mode(false).await?;  // 6-PWM mode
      drv.set_shunt_amplifier_gain(ShuntAmplifierGain::Gain20).await?;
      
      // Read device status
      let device_id = drv.get_device_id().await?;
      let has_fault = drv.has_fault().await?;
      
      // Get comprehensive fault status
      let status = drv.get_fault_status().await?;
      if status.has_overcurrent() {
          // Handle overcurrent on any phase
      }
      if status.has_thermal() {
          // Handle overtemperature warning or shutdown
      }
      

Low-Level API Usage

The driver provides direct access to all DRV8301 registers through the low-level API via drv.ll. This API is automatically generated from device.yaml and provides type-safe access to all register fields.

Reading Registers

Use .read() to read a register and access its fields:

// Read status register 1
let status1 = drv.ll.status_register_1().read()?;
let has_fault = status1.fault();
let gvdd_uv = status1.gvdd_uv();
let otw = status1.otw();

// Read status register 2
let status2 = drv.ll.status_register_2().read()?;
let device_id = status2.device_id();

// Read control register 1
let ctrl1 = drv.ll.control_register_1().read()?;
let gate_current = ctrl1.gate_current();
let gate_reset = ctrl1.gate_reset();

Writing Registers

Use .write() with a closure to modify register fields. The closure receives a mutable reference to the register structure:

// Configure control register 1
drv.ll.control_register_1().write(|w| {
    w.set_gate_current(GateCurrent::Ma1700);
    w.set_gate_reset(false);
    w.set_pwm_mode(PwmMode::SixPwm);
    w.set_oc_adj_set(OcAdjSet::Vds250mV);
})?;

// Configure control register 2
drv.ll.control_register_2().write(|w| {
    w.set_octw_set(OctwSet::Both);
    w.set_gain(ShuntAmplifierGain::Gain20);
    w.set_dc_cal_ch1(false);
    w.set_dc_cal_ch2(false);
    w.set_ocp_mode(OcpMode::CurrentLimit);
})?;

Modifying Registers

Use .modify() to read-modify-write, preserving other fields:

// Enable DC calibration for channel 1 without affecting other settings
// modify() reads the register, applies your changes, then writes it back
drv.ll.control_register_2().modify(|w| {
    w.set_dc_cal_ch1(true);  // Only modify this field, others preserved
})?;

Async Low-Level API

The low-level API has async versions for use with Drv8301Async. Simply append _async to the method name:

// Async read
let status1 = drv.ll.status_register_1().read_async().await?;
let status2 = drv.ll.status_register_2().read_async().await?;

// Async write
drv.ll.control_register_1().write_async(|w| {
    w.set_gate_current(GateCurrent::Ma1700);
    w.set_pwm_mode(PwmMode::SixPwm);
}).await?;

// Async modify
drv.ll.control_register_2().modify_async(|w| {
    w.set_gain(ShuntAmplifierGain::Gain40);
}).await?;

Field Naming Convention

Register and field names in the LL API follow snake_case and are derived from the names in device.yaml:

  • Register: StatusRegister1status_register_1()
  • Field: gate_currentset_gate_current() / gate_current()
  • Register: ControlRegister2control_register_2()
  • Field: dc_cal_ch1set_dc_cal_ch1() / dc_cal_ch1()

Finding Register/Field Names

  1. Check device.yaml - All registers and fields are documented there
  2. Use IDE autocomplete - Type drv.ll. to see all available registers
  3. Read a register - Use .read() then autocomplete to see available field getters
  4. Write a register - The closure parameter has autocomplete for all setters

Examples

Examples for ESP32-C3 using esp-hal are included. Setup is required (see esp-hal docs). Both examples demonstrate high-level convenience methods and low-level register API usage.

Register Map

The DRV8301 register map is defined in device.yaml, which device-driver uses to generate Rust code. This file specifies:

  • Register names, addresses, and sizes.
  • Field names, bit positions, and access modes (Read-Only, Read-Write).
  • Enumerations for field values (e.g., gate currents, OCP modes, amplifier gains).
  • Reset values and descriptions based on the datasheet.

Hardware Setup

The DRV8301 requires SPI communication with specific characteristics:

  • SPI Mode: CPOL=0, CPHA=1 (Mode 1)
  • Clock Frequency: Up to 10 MHz
  • Frame Format: 16-bit MSB first
  • Voltage Levels: 3.3V or 5V logic compatible
  • Connections: SCLK, MISO, MOSI, CS (chip select)

Datasheet

Feature Flags

  • default = []: No default features; async and blocking drivers are always available.
  • std: Enables std features for thiserror.
  • log: Enables log facade logging. Requires log = { version = "0.4", optional = true }.
  • defmt: Enables defmt logging. Requires defmt = { version = "1.0", optional = true }.

Contributions

Contributions are welcome! While the register map in device.yaml is complete, you can contribute by:

  • Adding high-level convenience methods to simplify common operations (e.g., motor control sequences, calibration routines).
  • Enhancing documentation with additional examples or clarifications.
  • Reporting issues or suggesting improvements.
  • Suggesting code refactoring.

Please submit issues, fork the repository, and create pull requests.

License

This project is dual-licensed under the MIT License or Apache License 2.0, at your option.

Commit count: 0

cargo fmt