Skip to main content

omnitiles/drivers/
tb6612.rs

1// SPDX-License-Identifier: MIT
2// © 2025–2026 Christopher Liu
3
4//! Single-channel driver for the TB6612FNG H-bridge (used on DFRobot DRI0040).
5//!
6//! Each TB6612 channel controls one DC motor via:
7//! - One PWM pin for speed (duty cycle)
8//! - Two GPIO pins (IN1/IN2) for direction
9
10use stm32f7xx_hal::{
11    gpio::{self, Output, PushPull},
12    prelude::*,
13};
14
15pub struct Tb6612<const IN1_P: char, const IN1_N: u8, const IN2_P: char, const IN2_N: u8, Pwm> {
16    in1: gpio::Pin<IN1_P, IN1_N, Output<PushPull>>,
17    in2: gpio::Pin<IN2_P, IN2_N, Output<PushPull>>,
18    pwm: Pwm,
19}
20
21impl<const IN1_P: char, const IN1_N: u8, const IN2_P: char, const IN2_N: u8, Pwm>
22    Tb6612<IN1_P, IN1_N, IN2_P, IN2_N, Pwm>
23where
24    Pwm: _embedded_hal_PwmPin<Duty = u16>,
25{
26    pub fn new(
27        in1: gpio::Pin<IN1_P, IN1_N, Output<PushPull>>,
28        in2: gpio::Pin<IN2_P, IN2_N, Output<PushPull>>,
29        mut pwm: Pwm,
30    ) -> Self {
31        pwm.set_duty(0);
32        pwm.enable();
33        Self { in1, in2, pwm }
34    }
35
36    /// Set motor speed from -1.0 (full reverse) to 1.0 (full forward).
37    /// Values near zero (|speed| < 0.001) engage the brake.
38    pub fn set_speed(&mut self, speed: f32) {
39        let speed = speed.clamp(-1.0, 1.0);
40
41        if speed > 0.001 {
42            self.in1.set_high();
43            self.in2.set_low();
44            let duty = (speed * self.pwm.get_max_duty() as f32) as u16;
45            self.pwm.set_duty(duty);
46        } else if speed < -0.001 {
47            self.in1.set_low();
48            self.in2.set_high();
49            let duty = (speed.abs() * self.pwm.get_max_duty() as f32) as u16;
50            self.pwm.set_duty(duty);
51        } else {
52            self.brake();
53        }
54    }
55
56    /// Short-brake: both inputs high, full duty.
57    pub fn brake(&mut self) {
58        self.in1.set_high();
59        self.in2.set_high();
60        self.pwm.set_duty(self.pwm.get_max_duty());
61    }
62
63    /// Coast: both inputs low, zero duty.
64    pub fn coast(&mut self) {
65        self.in1.set_low();
66        self.in2.set_low();
67        self.pwm.set_duty(0);
68    }
69}