Skip to content

fix(ARK_G431_CAN): do not latch nFAULT OTW as stuck-rotor - #104

Open
AlexKlimaj wants to merge 5 commits into
feat/embed-g431-can-bootloaderfrom
fix/nfault-classify-otw
Open

fix(ARK_G431_CAN): do not latch nFAULT OTW as stuck-rotor#104
AlexKlimaj wants to merge 5 commits into
feat/embed-g431-can-bootloaderfrom
fix/nfault-classify-otw

Conversation

@AlexKlimaj

Copy link
Copy Markdown
Member

Stacked on #79.

Summary

A customer hit ERROR nFAULT OTW and the ESC shut down. DRV8350H nFAULT is a single open-drain OR of VDS OCP, UVLO, OTW, OTSD, and GDF (no SPI status). OTW is a warning — the chip keeps driving. Firmware treated every trusted pin assert as ESC_FAULT_STUCK, so a hot MCU (classifier used die ≥ 100 °C) dropped a motor.

DRV8350H (ARK 12S CAN)

Classify from pin duration and whether the bridge is still conducting. Do not cut PWM on the falling edge:

  • Pulse ~8 ms: VDS auto-retry — keep PWM, count pulses (8 in 100 ms latches)
  • Held + current still up: OTW warning — keep PWM, thermal derate continues; NodeStatus WARNING; log nFAULT OTW at WARNING, debug UART warn: (HWCI does not abort)
  • Held + dead, bus < 8 V: UVLO — PWM off, resume when the pin releases
  • Held + dead, MCU ≥ 100 °C: OTSD class — PWM off, resume when cool
  • Held + dead, otherwise: GDF — latch until zero throttle + ENABLE tRST

DRV8328 (ARK 4IN1)

Separate, simple path. That chip has no OTW-only report and no 8 ms VDS retry — every nFAULT already Hi-Z's the FETs. Cut PWM, latch stuck until zero throttle; nSLEEP sleep is the DRV reset.

Test plan

  • make ARK_G431_CAN builds
  • make ARK_4IN1_F051 builds (flash 27000 / 27424)
  • hwci/tests/test_debug_uart.pywarn: nFAULT OTW / retry are not abort faults
  • Bench 12S CAN: OTW (hot, motor still spinning) logs WARNING and keeps driving
  • Bench 12S CAN: VDS pulse does not latch stuck; persistent short still latches
  • Bench 4IN1: nFAULT still cuts and clears at zero throttle

DRV8350H nFAULT is an OR of VDS OCP, UVLO, OTW, OTSD, and GDF with no
SPI status. OTW is a warning (drivers stay active); VDS auto-retries
in ~8 ms. Treating every pin assert as ESC_FAULT_STUCK dropped a motor
on a hot MCU (logged ERROR nFAULT OTW).

Classify from pin duration and whether the bridge is still conducting:
OTW and short VDS pulses keep PWM; UVLO/OTSD auto-resume; GDF and a
retry budget still latch until zero throttle.

DRV8328 (ARK 4IN1) keeps a simple latched cut — that chip has no
OTW-only report and no 8 ms VDS retry.
WARN→dead used shunt current collapse alone, so OTW plus a pilot idle
re-entered the reported drop (Hi-Z → latch). Gate that test on commanded
drive, use smoothed centiamps, and treat every held+dead as Hi-Z: MCU die
temp is a log label, not HIZ vs latch. Stay Hi-Z while nFAULT is held so
zero throttle / prop-brake cannot re-queue ERROR every classify window.

VDS retry budget is opportunistic (a poll can miss µs-scale releases);
the held path is the backstop. ENABLE tRST is from HIZ at zero throttle,
not the unreachable LATCH pulse. Host twin: hwci/hwci/gd_nfault_model.py
gd_enter_warn(now, 0) asserted FAULT_GD_OTW and NodeStatus WARNING with
no LogMessage — including the two commanded-and-conducting fallthroughs
(snap below 0.5 A, or current halved but still live). Always log WARN;
the 200 ms rate limit is enough.

A single sample ≥ GD_LIVE_CA_MIN reset the 80 ms dead dwell, so
intermittent shunt current could sit in WARN with PWM allowed until the
stall rail misdiagnosed it. Confirm OTW after 40 ms of consecutive live
current under drive; otherwise Hi-Z after 250 ms commanded-held. Idle
pauses that ceiling so OTW + throttle-cut is not a delayed drop.

tRST budget is now lifetime (sleep-idle / pin-high do not refill it), so
a dead DRV cannot pulse ENABLE for the whole flight. gd_ms uses >= the
1 kHz divider. FaultResetPulse is ENABLE-only.
gd_enter_dead() no longer short-circuits to LATCH when the tRST budget
is spent — that removed the HIZ auto-resume window for a later OTSD.
Only the HIZ pulse path consumes the budget, and pin-high recovery
resets it (consecutive failed attempts). Sleep-idle still does not,
because it never observes the pin high.

The unconfirmed WARN ceiling now accumulates commanded-held time across
idle blips instead of restarting gd_cmd_t0. gd_otw_confirmed clears on
WARN→IDLE. Comment the CLASSIFY 12 ms fast-confirm and that LIVE_CA_MIN
needs a low-throttle spinning datapoint, not just warm idle.
IDLE→CLASSIFY zeroes gd_cmd_held_ms, so commanded-held accumulation
survives throttle blips only below the DRV sleep threshold. Comment that
boundary. Add profile g431_current_floor so the GD_LIVE_CA_MIN idle vs
lowest-commanded-throttle measurement is a real HWCI run, not only a
source comment.
@AlexKlimaj
AlexKlimaj force-pushed the fix/nfault-classify-otw branch from dc563d4 to eabdc27 Compare August 28, 2026 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant