Chat


How can I help you?

Explain project
Write a project description
Find schematic issues

Firmware Starter
Redesign status
The previous MAX17320 example is obsolete. U2 is now BQ76907RGRR on the existing BMS_SCL, BMS_SDA, and active-low BMS_ALERT_N nets. BQ76907 balancing is host-controlled and must be periodically renewed; it is not a charger.
Until the BQ76907 Technical Reference Manual register map is implemented and verified, firmware must keep the actuator disabled. The buildable scaffold below deliberately fails the BMS interlock rather than guessing register addresses or threshold encodings.
Pin mapping

Table


ESP32-S3 pinNetFunction
GPIO4MOTOR_ENABLEDRV8701 nSLEEP; starts LOW
GPIO5MOTOR_IN1Bridge direction input 1
GPIO6MOTOR_IN2Bridge direction input 2
GPIO7MOTOR_FAULT_NActive-low DRV8701 fault
GPIO8MOTOR_CURRENT_MONRaw current-monitor ADC
GPIO9BMS_SCLBQ76907 I²C clock
GPIO10BMS_SDABQ76907 I²C data
GPIO11BMS_ALERT_NActive-low BQ76907 alert
GPIO12/13GPS_TX / GPS_RXGPS UART
GPIO14GPS_PPSGPS pulse-per-second
GPIO17/18LIDAR_RX / LIDAR_TXTF-Luna UART
GPIO19/20USB D− / D+Native USB
GPIO21USB_VBUS_SENSEUSB VBUS divider ADC
Required BQ76907 production configuration
Implement and read back all settings before allowing motor operation:
  1. Two-cell mapping: VC7–VC6 and VC1–VC0, with VC6 through VC1 shorted.
  2. Cell UV target: 3.20 V/cell, with autonomous DSG control.
  3. Cell OV and temperature limits suitable for the selected 18650 chemistry.
  4. RS1 = 1 mΩ.
  5. OCD1 = −16 mV, nominally 16 A. OCD1 supports 2 mV steps.
  6. SCD = −40 mV, nominally 40 A.
  7. TS thermistor mode for the installed 10 kΩ NTC. BQ76907 supplies its own internal 20 kΩ thermistor bias.
  8. Autonomous OV/UV/OCD/SCD FET-control masks, wake/sleep behavior, fault recovery, and ALERT behavior.
  9. Host balancing policy with cell/temperature limits and periodic renewal.
PlatformIO configuration

Ini


[env:esp32-s3-mini-1-n8]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
board_upload.flash_size = 8MB
board_build.flash_size = 8MB
board_build.partitions = default_8MB.csv
build_flags =
    -D ARDUINO_USB_MODE=1
    -D ARDUINO_USB_CDC_ON_BOOT=1
monitor_speed = 115200
Safe buildable scaffold

Cpp


#include <Arduino.h>
#include <Wire.h>

static constexpr uint8_t PIN_MOTOR_ENABLE  = 4;
static constexpr uint8_t PIN_MOTOR_IN1     = 5;
static constexpr uint8_t PIN_MOTOR_IN2     = 6;
static constexpr uint8_t PIN_MOTOR_FAULT_N = 7;
static constexpr uint8_t PIN_BMS_SCL       = 9;
static constexpr uint8_t PIN_BMS_SDA       = 10;
static constexpr uint8_t PIN_BMS_ALERT_N   = 11;

static constexpr uint32_t HARD_MAX_PULSE_MS = 500;
static constexpr float MOTOR_INHIBIT_VOLTAGE_V = 6.6f;

struct BmsState {
  bool driverImplemented = false;
  bool communicationValid = false;
  bool configurationVerified = false;
  bool protectionFault = true;
  float packVoltageV = NAN;
  float cell1VoltageV = NAN;
  float cell2VoltageV = NAN;
  float temperatureC = NAN;
};

BmsState bms;

void bridgeOff() {
  digitalWrite(PIN_MOTOR_IN1, LOW);
  digitalWrite(PIN_MOTOR_IN2, LOW);
  digitalWrite(PIN_MOTOR_ENABLE, LOW);
}

bool hardwareFaultActive() {
  return digitalRead(PIN_MOTOR_FAULT_N) == LOW ||
         digitalRead(PIN_BMS_ALERT_N) == LOW;
}

bool initializeBq76907() {
  // Intentionally fail closed until the BQ76907 Technical Reference Manual
  // commands, data-memory addresses, CRC policy, thresholds and readback tests
  // are implemented. Never guess these values.
  bms.driverImplemented = false;
  bms.communicationValid = false;
  bms.configurationVerified = false;
  bms.protectionFault = true;
  return false;
}

bool refreshBq76907() {
  if (!bms.driverImplemented) return false;
  // TODO: read cell voltages, stack voltage, TS temperature, safety status,
  // FET status, ALERT causes and configuration checksum/readback.
  return false;
}

bool actuatorInterlockOk() {
  return bms.driverImplemented && bms.communicationValid &&
         bms.configurationVerified && !bms.protectionFault &&
         isfinite(bms.packVoltageV) &&
         bms.packVoltageV >= MOTOR_INHIBIT_VOLTAGE_V &&
         !hardwareFaultActive();
}

bool pulseMotor(bool forward, uint32_t durationMs) {
  if (!actuatorInterlockOk()) return false;
  durationMs = constrain(durationMs, 1UL, HARD_MAX_PULSE_MS);

  digitalWrite(PIN_MOTOR_IN1, LOW);
  digitalWrite(PIN_MOTOR_IN2, LOW);
  digitalWrite(PIN_MOTOR_ENABLE, HIGH);
  delay(5); // bounded direction dead-time

  digitalWrite(PIN_MOTOR_IN1, forward ? HIGH : LOW);
  digitalWrite(PIN_MOTOR_IN2, forward ? LOW : HIGH);

  const uint32_t started = millis();
  while (millis() - started < durationMs) {
    if (hardwareFaultActive() || !refreshBq76907()) {
      bridgeOff();
      return false;
    }
    delay(1);
  }

  bridgeOff();
  return true;
}

void setup() {
  pinMode(PIN_MOTOR_ENABLE, OUTPUT);
  pinMode(PIN_MOTOR_IN1, OUTPUT);
  pinMode(PIN_MOTOR_IN2, OUTPUT);
  bridgeOff();

  pinMode(PIN_MOTOR_FAULT_N, INPUT_PULLUP);
  pinMode(PIN_BMS_ALERT_N, INPUT_PULLUP);

  Serial.begin(115200);
  Wire.begin(PIN_BMS_SDA, PIN_BMS_SCL, 100000);
  Wire.setTimeOut(50);

  if (!initializeBq76907()) {
    Serial.println("BQ76907 driver/configuration not implemented: actuator locked out.");
  }
}

void loop() {
  refreshBq76907();
  if (hardwareFaultActive()) bridgeOff();
  delay(10);
}
Implementation acceptance criteria
Motor control may be enabled only after the completed driver:
  • positively identifies U2 and validates I²C/CRC behavior;
  • writes or loads the intended 2S protection configuration;
  • reads every safety-critical setting back and compares it with the expected value;
  • confirms both cells, temperature, FET state and safety status are valid;
  • treats ALERT, communication loss, stale data, undervoltage, overtemperature and DRV8701 nFAULT as immediate motor-off conditions;
  • uses a hard independent pulse timeout of 500 ms or less;
  • refuses direction reversal until the bridge has returned to neutral;
  • logs the exact configuration version/checksum used on each production board.
Use an external suitable 2S CC/CV charger. Firmware balancing is maintenance only and must never be treated as charge termination.
  • Redesign status

  • Pin mapping

  • Required BQ76907 production configuration

  • PlatformIO configuration

  • Safe buildable scaffold

  • Implementation acceptance criteria