🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    H-Bridge Unit v1.1 + M5Dial: possible library bug, HPWR issues & safety note — test report (please correct me if I'm wrong)

    Scheduled Pinned Locked Moved Units
    1 Posts 1 Posters 16 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      HarzDevel
      last edited by

      H-Bridge Unit v1.1 + M5Dial: possible library bug, HPWR issues & safety note — test report (please correct me if I'm wrong)

      Hardware: M5Stack Dial v1 (ESP32-S3) + M5Stack H-Bridge Unit v1.1 (STM32F030 + RZ7899, FW v2)
      Arduino Core: ESP32 3.3.7 | M5Unified: 0.2.15 | M5GFX: 0.2.21 | M5UnitHbridge: 1.0.0


      Overview

      We spent several sessions trying to get the H-Bridge Unit v1.1 working reliably with the M5Stack Dial v1. What started as a simple "connect and drive a motor" task turned into a systematic investigation of all possible port, voltage, and I2C combinations.

      This post documents the full test matrix with serial output and current measurements. We observed three things that surprised us — please read carefully and let us know if we misunderstood something or if there is a known solution we missed:

      1. The official M5UnitHbridge library does not seem to work with this hardware — we believe it is due to a missing Repeated Start condition in its I2C read implementation, but we may be wrong.
      2. Wire.begin() must be called after M5Dial.begin() — contrary to what you might expect, this re-configures the hardware I2C peripheral to Port A and works correctly. Is this intended behavior?
      3. HPWR mode does not behave as expected — forward direction produces no output, backward direction appears limited to ~9% effective duty cycle regardless of speed value. We tried PWM frequency changes, common GND, different ports and I2C methods — all without improvement. Could this be a firmware issue, or are we missing a required initialization step?

      We hope this is useful to others, and we very much welcome corrections or explanations from M5Stack or the community.


      TL;DR

      Getting the H-Bridge Unit v1.1 working with M5Dial is not straightforward. This post documents a complete test matrix covering all port/voltage/I2C combinations. The short version:

      • 5V mode + Hardware I2C (Wire) + correct registers = works, but USB power limits motor load to ~500mA
      • M5UnitHbridge library = broken for this hardware (wrong I2C read protocol, motor does not respond)
      • HPWR mode appears non-functional in FW v2: forward channel dead, backward works at fixed ~9% duty cycle regardless of speed value — firmware bug suspected

      Hardware Setup

      Item Detail
      Controller M5Stack Dial v1 (ESP32-S3)
      Driver M5Stack H-Bridge Unit v1.1 (STM32F030 + RZ7899, FW v2)
      Grove Port A SDA=G13, SCL=G15
      Grove Port B SDA=G2, SCL=G1
      HPWR supply 13.5V @ external terminals, 470µF cap across VIN+/GND

      Key Discovery 1: Wire.begin() After M5Dial.begin()

      M5Dial.begin() initializes the internal I2C bus (touch controller) on G11/G12.

      • Wire after M5Dial.begin() → internal bus, not Port A
      • Wire1.begin(13, 15) → G15 held LOW by touch controller → SCL blocked
      • ✅ Solution: Call Wire.begin(13, 15) after M5Dial.begin() — this re-configures the hardware I2C peripheral to Port A pins and works correctly
      auto cfg = M5.config();
      M5Dial.begin(cfg, false, false);
      // ...
      Wire.begin(13, 15);
      Wire.setClock(100000);
      

      Key Discovery 2: Correct Register Map

      The H-Bridge register layout differs from various online sources. Verified by M5UnitHbridge library source:

      Register Address Description
      REG_DIR 0x00 Direction: 0=STOP, 1=FORWARD, 2=BACKWARD
      REG_SPEED8 0x01 Speed 8-bit (0–255)
      REG_SPEED16 0x02 Speed 16-bit little-endian
      REG_PWM_FREQ 0x04 PWM frequency little-endian
      REG_CURRENT 0x30 Motor current IEEE-754 float, 4 bytes (v1.1 only)
      REG_FW 0xFE Firmware version (uint8)

      Key Discovery 3: M5UnitHbridge Library Broken for This Hardware

      The official M5UnitHbridge library uses endTransmission() (with STOP condition) before requestFrom():

      // Library readBytes() — BROKEN for H-Bridge v1.1
      _wire->beginTransmission(addr);
      _wire->write(reg);
      _wire->endTransmission();        // ← sends STOP
      _wire->requestFrom(addr, length); // ← new START (not Repeated Start)
      

      The STM32F030 in the H-Bridge requires Repeated Start between write and read. Without it:

      • getFirmwareVersion() returns 255 instead of 2
      • Write operations appear to succeed but the motor does not respond

      ✅ Solution: Use Wire directly with endTransmission(false) for reads:

      Wire.beginTransmission(HBRIDGE_ADDR);
      Wire.write(reg);
      Wire.endTransmission(false);  // Repeated Start — NO stop condition
      Wire.requestFrom(HBRIDGE_ADDR, len);
      

      Complete Test Matrix

      # Port Pins Power I2C Result Notes
      1a COM A G13/G15 5V Hardware Wire ✅ Motor runs Brownout at ~78% load — USB 5V insufficient for full load
      1b COM A G13/G15 5V M5UnitHbridge lib ❌ No movement FW=255, writes silent. Library incompatible.
      2a COM A G13/G15 5V Bit-Banging ✅ Motor runs Brownout at ~24% — GPIO switching adds extra current spikes
      2b COM B G2/G1 5V Bit-Banging ✅ Motor twitches Brownout at ~25%, same as 2a. Port makes no difference.
      3a COM A G13/G15 HPWR Hardware Wire ❌ Forward only ~4mV FW=2 ✓, writes accepted (readback confirmed), forward channel inactive
      3b COM A G13/G15 HPWR Bit-Banging ⚡ Asymmetric Forward ❌ (4mV, inactive). Backward ✅ (-1.2V, 128mA, clean ramp to 255 and back)
      4 COM B G2/G1 HPWR Bit-Banging ❌ No movement Same HPWR issue, FW=2 ✓, readback correct, 79mA draw, 4mV output

      Serial Console Excerpts

      Test 1a — 5V, Hardware Wire, correct registers (motor runs, brownout at ~78%)

      FW-Version: 2
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        write reg=0x00 val=1 ... err=0
        write reg=0x01 val=0 ... err=0
        spd=  0
        ...
        write reg=0x01 val=198 ... err=0
        spd=198
      E BOD: Brownout detector was triggered
      

      Test 1b — 5V, M5UnitHbridge library (motor does not respond)

      begin: OK
      FW-Version: 255   ← should be 2 — Repeated Start missing in library
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        spd=  0 ... spd=255
      [2] Vorwaerts: halte 100% fuer 3s
      ...
      === Fertig ===
      ← no brownout, no motor current, motor never moved
      

      Test 4 — HPWR, Bit-Banging, with register readback (motor does not respond)

      FW-Version: 2  (read OK)
      [1] Readback-Test: dir=1 spd=128
        Readback: dir=1 (soll=1)  spd=128 (soll=128)   ← registers confirmed correct
      [2] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        spd=0 ... spd=255
      [3] Vorwaerts: halte 100% fuer 3s
      Motor dreht nicht
      Messungen: 13.5V confirmed, 79mA from supply, 4mV at motor terminals
      

      Test 3b — HPWR, Bit-Banging, COM A (asymmetric: forward dead, backward works)

      FW-Version: 2
      [1] Vorwaerts: Rampe 0->255    → Motor does NOT turn, ~4mV at terminals
      [5] Rueckwaerts: Rampe 0->255  → Motor RUNS, -1.2V at terminals, 128mA from supply
                                        (~9% duty cycle at 13.5V, regardless of speed value)
      [7] Rueckwaerts: Rampe 255->0  → Motor slows cleanly and stops at spd=0
      

      Test 5 — HPWR, register snapshot (default PWM frequency)

      [R] Register-Snapshot (Firmware-Defaults):
        0x00 DIR   = 0  (0=STOP,1=FWD,2=BWD)
        0x01 SPD8  = 0
        0x02 SPD16 = 0
        0x04 FREQ  = 1000 Hz    ← default is audible range — explains motor beeping
      

      HPWR Mode — Appears Non-Functional in Firmware v2

      After extensive testing across all port/I2C combinations, our conclusion is that HPWR mode is functionally broken in firmware v2.

      Additional tests (Tests 5 & 6)

      • Default PWM frequency: 1000 Hz (register 0x04) — audible range, explains the motor "beeping"
      • Setting frequency to 10000 Hz: no improvement, forward direction still inactive
      • Connecting external supply GND to Grove GND: no improvement

      HPWR test results across all combinations

      Test Port I2C Forward Backward Notes
      3a COM A Hardware Wire ✗ 4mV n/a Writes confirmed OK via err=0
      3b COM A Bit-Banging ✗ 4mV ✓ -1.2V / 128mA Asymmetric — only backward works
      4 COM B Bit-Banging ✗ 4mV n/a Readback confirmed dir/spd correct

      Asymmetric behavior detail (Test 3b)

      Forward (dir=1):

      • ~4mV at motor terminals regardless of speed value
      • Brief 120mA spike from supply at spd=0–10, drops to 80µA by spd=40
      • Motor does not turn

      Backward (dir=2):

      • -1.2V at motor terminals — only ≈9% effective duty cycle at 13.5V supply, regardless of speed value (0–255)
      • 128mA from external supply
      • Motor runs through full ramp 0→255→0 and stops correctly
      • Requires a manual push past static friction at low speeds

      Evidence pointing to firmware bug

      1. I2C communication confirmed working (FW=2 readable, register readback correct)
      2. Speed value has no effect on output voltage in HPWR mode (9% fixed regardless of spd=1 or spd=255)
      3. PWM frequency change has no effect
      4. GND connection has no effect
      5. Issue present on both COM A and COM B
      6. Issue present with both Hardware I2C and Bit-Banging
      7. 5V mode works correctly on the same hardware

      Our interpretation: The STM32F030 firmware v2 may not properly implement HPWR mode — the DIP switch position appears to be detected but the RZ7899 drive logic may not be correctly configured for external supply operation. However, we acknowledge we could be missing a required initialization step or configuration. We would greatly appreciate clarification from M5Stack or anyone who has successfully used HPWR mode.


      Working Configuration (Minimal Code)

      #include <M5Dial.h>
      
      #define HBRIDGE_ADDR  0x20
      #define REG_DIR       0x00
      #define REG_SPEED8    0x01
      
      bool hb_write(uint8_t reg, uint8_t val) {
          Wire.beginTransmission(HBRIDGE_ADDR);
          Wire.write(reg);
          Wire.write(val);
          return Wire.endTransmission() == 0;
      }
      
      bool hb_read(uint8_t reg, uint8_t* out) {
          Wire.beginTransmission(HBRIDGE_ADDR);
          Wire.write(reg);
          Wire.endTransmission(false);  // Repeated Start
          return Wire.requestFrom((uint8_t)HBRIDGE_ADDR, (uint8_t)1) == 1
              && (*out = Wire.read(), true);
      }
      
      void setup() {
          auto cfg = M5.config();
          M5Dial.begin(cfg, false, false);
          Wire.begin(13, 15);           // COM A, after M5Dial.begin()
          Wire.setClock(100000);
          // DIP switch: 5V mode — HPWR forward channel does not work
          hb_write(REG_DIR, 1);         // FORWARD
          hb_write(REG_SPEED8, 128);    // 50%
      }
      

      ⚠️ Safety Note: H-Bridge Runs Independently After ESP32 Reset

      The STM32F030 inside the H-Bridge has a lower minimum operating voltage than the ESP32-S3. This means:

      Scenario 1 — Brownout:
      The ESP32-S3 crashes (brownout at ~700mA from Grove 5V). The STM32F030 keeps running and holds the last direction + speed. The motor continues turning until power is physically removed.

      Scenario 2 — Reset button:
      Pressing the M5Dial reset button resets the ESP32-S3, but the STM32F030 is unaffected. Motor keeps running.

      Scenario 3 — Software crash:
      Any ESP32-S3 crash leaves the H-Bridge in its last state.

      Safe practice — always send STOP as the first action in setup():

      Wire.begin(13, 15);
      Wire.setClock(100000);
      Wire.beginTransmission(HBRIDGE_ADDR);
      Wire.write(0x00); Wire.write(0);   // DIR = STOP
      Wire.endTransmission();
      Wire.beginTransmission(HBRIDGE_ADDR);
      Wire.write(0x01); Wire.write(0);   // SPEED = 0
      Wire.endTransmission();
      // ... rest of setup
      

      Current Measurements (5V Mode, Grove Side)

      State Motor Voltage Grove 5V Current
      Idle (M5Dial + H-Bridge logic) — ~300mA
      Motor running (after manual push) 3.3V ~700mA
      Brownout threshold (USB) — ~500mA

      Note: USB 2.0 limit is 500mA — sustained motor load exceeds this. Use a powered USB hub or a 5V supply with higher current rating. Do not rely on HPWR mode — it is non-functional in FW v2.


      Summary

      Issue Root Cause Fix
      Wire on Port A silent M5Dial.begin() uses Wire on G11/G12 Call Wire.begin(13,15) after M5Dial.begin()
      Wire1 SCL blocked Touch controller holds G15 LOW Don't use Wire1
      M5UnitHbridge FW=255 Library uses STOP instead of Repeated Start Use Wire directly with endTransmission(false)
      5V mode brownout USB 5V insufficient for motor load >~500mA Use powered USB hub or higher-current 5V supply
      HPWR mode non-functional STM32F030 FW v2 bug — forward dead, backward fixed at ~9% duty cycle regardless of speed No workaround — requires firmware fix from M5Stack

      Tested May 2026 on M5Stack Dial v1 (ESP32-S3) + H-Bridge Unit v1.1 (STM32F030 + RZ7899, FW v2) / Arduino IDE 2.3.8 / ESP32 Core 3.3.7 / M5Unified 0.2.15


      Appendix: Full Serial Output per Test

      Test 1a — COM A | 5V | Hardware Wire | correct registers

      === Test 1a: Wire direkt, korrekte Register ===
      FW-Version: 2
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        write reg=0x00 val=1 ... err=0
        write reg=0x01 val=0 ... err=0
        spd=  0
        
        write reg=0x01 val=198 ... err=0
        spd=198
      E BOD: Brownout detector was triggered
      
      Lauf mit Ammeter (Grove-Seite):
        write reg=0x01 val=52 ... err=0
        spd= 52
      E BOD: Brownout detector was triggered
      Strom: ~300mA Ruhestrom, ~700mA beim Laufen (nach Anschieben), 3.3V an Motor
      

      Test 1b — COM A | 5V | M5UnitHbridge Library

      === Test 1b: M5UnitHbridge Library ===
      begin: OK
      FW-Version: 255   ← should be 2
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        spd=  0 ... spd=255
      [2] Vorwaerts: halte 100% fuer 3s
      [3] Vorwaerts: Rampe 255->0
      [4] STOP ... [8] STOP
      === Fertig ===
      ← no brownout, no motor current, motor never moved
      

      Test 2a — COM A | 5V | Bit-Banging

      === Test 2a: COM A | 5V | Bit-Banging ===
      [0] I2C Scan...  Gefunden: 0x20 <- H-Bridge
      FW-Version: 2
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        spd=  0 ... spd= 62
      E BOD: Brownout detector was triggered
      ← Motor dreht. Brownout bei spd=62 (~24%). GPIO-Umschalten erhoht Strombedarf.
      

      Test 2b — COM B | 5V | Bit-Banging

      === Test 2b: COM B | 5V | Bit-Banging ===
          SDA=G2 (gelb), SCL=G1 (weiss)
      [0] I2C Scan...  Gefunden: 0x20 <- H-Bridge
      FW-Version: 2  (read OK)
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        spd=  0 ... spd= 63
      E BOD: Brownout detector was triggered
      ← Motor hat gezuckt, Spannung messbar. Brownout bei spd=63, identisch mit 2a.
      

      Test 3a — COM A | HPWR | Hardware Wire

      === Test 3a: COM A | HPWR | Wire direkt ===
          SDA=G13, SCL=G15
      FW-Version: 2
      [1] Vorwaerts: Rampe 0->255 (100ms/Schritt)
        write reg=0x00 val=1 ... err=0
        write reg=0x01 val=0 ... err=0
        spd=  0 ... spd=255
      [2] Vorwaerts: halte 100% fuer 3s
      [3] Vorwaerts: Rampe 255->0
      === Fertig ===
      Messungen: 13.5V OK, 0.083mA aus Netzteil, Motor dreht nicht.
      

      Test 3b — COM A | HPWR | Bit-Banging

      === Test 3b: COM A | HPWR | Bit-Banging ===
          SDA=G13, SCL=G15
      [0] I2C Scan...  Gefunden: 0x20 <- H-Bridge
      FW-Version: 2
      [1] Vorwaerts: Rampe 0->255   → Motor dreht NICHT, ~4mV, 120mA-Spike bei spd=0..10
      [5] Rueckwaerts: Rampe 0->255 → Motor dreht ✓, -1.2V, 128mA aus Netzteil
      [7] Rueckwaerts: Rampe 255->0 → Motor haelt sauber bei spd=0
      === Fertig ===
      Asymmetrie: Vorwaerts tot, Rueckwaerts ~9% eff. Duty Cycle bei 13.5V
      

      Test 4 — COM B | HPWR | Bit-Banging

      === Test 4: COM B | HPWR | Bit-Banging ===
          SDA=G2 (gelb), SCL=G1 (weiss)
      [0] I2C Scan...  Gefunden: 0x20 <- H-Bridge
      FW-Version: 2  (read OK)
      [1] Readback-Test: dir=1 spd=128
        Readback: dir=1 (soll=1)  spd=128 (soll=128)   ← Register korrekt geschrieben
      [2] Vorwaerts: Rampe 0->255 ... Motor dreht nicht
      Messungen: 13.5V OK, 79mA aus Netzteil, 4mV an Motor.
      

      Test 5 — COM A | HPWR | Bit-Banging | PWM-Frequenz auslesen

      === Test 5: COM A | HPWR | Bit-Banging | FreqRead ===
          SDA=G13, SCL=G15
      [0] I2C Scan...  Gefunden: 0x20 <- H-Bridge
      FW-Version: 2
      [R] Register-Snapshot (Firmware-Defaults):
        0x00 DIR   = 0  (0=STOP,1=FWD,2=BWD)
        0x01 SPD8  = 0
        0x02 SPD16 = 0
        0x04 FREQ  = 1000 Hz   ← default PWM frequency
      Motor dreht nicht.
      

      Test 6 — COM A | HPWR | Bit-Banging | PWM-Frequenz auf 10kHz gesetzt

      === Test 6: COM A | HPWR | Bit-Banging | FreqSet 10kHz ===
          SDA=G13, SCL=G15
      [F] Setze PWM-Frequenz auf 10000 Hz...
          FREQ nach Set = 10000 Hz   ← write accepted
      [R] Register-Snapshot:
        0x04 FREQ  = 10000 Hz
      [1] Vorwaerts: Rampe 0->255   → Motor dreht nicht. Frequenz hat keinen Einfluss.
      
      1 Reply Last reply Reply Quote 0

      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

      With your input, this post could be even better 💗

      Register Login
      • First post
        Last post