# DRV8301 Gate Driver IC Driver (drv8301-dd)
[](https://crates.io/crates/drv8301-dd)
[](https://docs.rs/drv8301-dd)
[](https://opensource.org/licenses)
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`](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`](https://github.com/JM4ier/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`:**
```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:**
```rust
use drv8301_dd::{Drv8301, OcAdjSet, OcpMode, ShuntAmplifierGain};
use embedded_hal::spi::SpiDevice;
let spi_device = ;
let mut drv = Drv8301::new(spi_device);
drv.set_oc_threshold(OcAdjSet::Vds250mV)?;
drv.set_ocp_mode(OcpMode::CurrentLimit)?;
drv.set_pwm_mode(false)?; drv.set_shunt_amplifier_gain(ShuntAmplifierGain::Gain20)?;
let device_id = drv.get_device_id()?;
let has_fault = drv.has_fault()?;
let status = drv.get_fault_status()?;
if status.has_overcurrent() {
}
if status.phase_a_overcurrent() {
}
```
- **Async:**
```rust
use drv8301_dd::{Drv8301Async, OcAdjSet, OcpMode, ShuntAmplifierGain};
use embedded_hal_async::spi::SpiDevice;
let spi_device = ;
let mut drv = Drv8301Async::new(spi_device);
drv.set_oc_threshold(OcAdjSet::Vds250mV).await?;
drv.set_ocp_mode(OcpMode::CurrentLimit).await?;
drv.set_pwm_mode(false).await?; drv.set_shunt_amplifier_gain(ShuntAmplifierGain::Gain20).await?;
let device_id = drv.get_device_id().await?;
let has_fault = drv.has_fault().await?;
let status = drv.get_fault_status().await?;
if status.has_overcurrent() {
}
if status.has_thermal() {
}
```
## 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`](device.yaml) and provides type-safe access to all register fields.
### Reading Registers
Use `.read()` to read a register and access its fields:
```rust
// 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:
```rust
// Configure control register 1
w.set_gate_reset(false);
w.set_pwm_mode(PwmMode::SixPwm);
w.set_oc_adj_set(OcAdjSet::Vds250mV);
})?;
// Configure control register 2
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:
```rust
// Enable DC calibration for channel 1 without affecting other settings
// modify() reads the register, applies your changes, then writes it back
})?;
```
### Async Low-Level API
The low-level API has async versions for use with `Drv8301Async`. Simply append `_async` to the method name:
```rust
// 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`](device.yaml):
- Register: `StatusRegister1` → `status_register_1()`
- Field: `gate_current` → `set_gate_current()` / `gate_current()`
- Register: `ControlRegister2` → `control_register_2()`
- Field: `dc_cal_ch1` → `set_dc_cal_ch1()` / `dc_cal_ch1()`
### Finding Register/Field Names
1. **Check [`device.yaml`](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](https://esp-rs.github.io/book/installation/)). Both examples demonstrate high-level convenience methods and low-level register API usage.
- **Async Example:** [`examples/test_drv_async.rs`](examples/test_drv_async.rs)
```bash
cargo run --release --example test_drv_async --features defmt
```
- **Blocking Example:** [`examples/test_drv_blocking.rs`](examples/test_drv_blocking.rs)
```bash
cargo run --release --example test_drv_blocking --features defmt
```
## Register Map
The DRV8301 register map is defined in [`device.yaml`](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
- [DRV8301 Datasheet - PDF](docs/drv8301.pdf)
- [DRV8301 Datasheet - Markdown](docs/drv8301.md) (OCR-converted for easier reference)
## 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](LICENSE-MIT) or [Apache License 2.0](LICENSE-APACHE), at your option.