feat: ramp DC current to zero over 3 ticks before RUN → STOP
When vcucmd transitions to COMPLETE while in EVSEACTIVATE the previous behavior was to clear acpres_out / evseact_out and transition to STOP in a single 100 ms tick — cutting the OBC AC enable immediately. The VCU's HV contactor opens at roughly the same moment; under active 9 kW charging (~23 A) this hard disconnect transient floods the Tesla BMS state-change CAN path and starves the VCU's task scheduler past the IWDG window. Bench-confirmed 2026-05-21 as the trigger for the iteration N limit-lower 0x002A reset loop. Add a 3-tick (300 ms) ramp inside EVSEACTIVATE before the STOP transition: stash the original DC-current reference, scale it 2/3 → 1/3 → 0 across the remaining ticks, and only then clear the AC enable GPIOs and go STOP. The PI controller's natural response walks the AC current limit down so output current decays smoothly rather than hard-stopping. If vcucmd reverts to Charging mid-ramp (user raised limit again), restore the original reference cleanly before the existing branches take over. The VCU also defers its own HV-contactor open by 1500 ms (see VCU iteration O commit 5781f47). Belt-and-suspenders: either fix alone substantially reduces the disconnect transient; together they make RUN → STOP graceful on any controller that interoperates with this charger. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+49
-4
@@ -383,13 +383,58 @@ void ChargerStateMachine()
|
|||||||
// VCU command is the primary exit. CheckUnplugged + CheckChargerFaults
|
// VCU command is the primary exit. CheckUnplugged + CheckChargerFaults
|
||||||
// remain for hardware safety; the self-decided CheckVoltage/CheckTimeout
|
// remain for hardware safety; the self-decided CheckVoltage/CheckTimeout
|
||||||
// exits are gone (S12 — VCU is authoritative).
|
// exits are gone (S12 — VCU is authoritative).
|
||||||
|
//
|
||||||
|
// SKUDAK: ramp the DC-current reference toward zero across 3 ticks
|
||||||
|
// (300 ms) before transitioning to STOP. Without this, the VCU
|
||||||
|
// opening its HV contactor at the moment we go STOP triggers a hard
|
||||||
|
// 23 A → 0 disconnect transient that floods the Tesla BMS state-
|
||||||
|
// change CAN path and starves the VCU's task scheduler past its
|
||||||
|
// IWDG window (bench-confirmed 2026-05-21 limit-lower 0x002A loop).
|
||||||
|
// The VCU also defers its contactor open by ~1500 ms; together
|
||||||
|
// they make the disconnect graceful even on a hard limit-lower
|
||||||
|
// mid-RUN. completeRampTicks counts DOWN from 3 → 0; the original
|
||||||
|
// reference is stashed so if vcucmd reverts to Charging mid-ramp
|
||||||
|
// we restore cleanly.
|
||||||
|
static uint8_t completeRampTicks = 0;
|
||||||
|
static s32fp completeRampOriginalRef = 0;
|
||||||
if (vcucmd == VCUCMD_COMPLETE)
|
if (vcucmd == VCUCMD_COMPLETE)
|
||||||
{
|
{
|
||||||
DigIo::acpres_out.Clear();
|
if (completeRampTicks == 0)
|
||||||
DigIo::evseact_out.Clear();
|
{
|
||||||
state = STOP;
|
completeRampOriginalRef = MIN(Param::Get(Param::idcspnt), Param::Get(Param::idclim));
|
||||||
|
completeRampTicks = 3;
|
||||||
|
}
|
||||||
|
if (completeRampTicks > 1)
|
||||||
|
{
|
||||||
|
// Scale 2/3 → 1/3 → 0 across remaining ticks.
|
||||||
|
s32fp scaled = (completeRampOriginalRef * (completeRampTicks - 1)) / 3;
|
||||||
|
dcCurController.SetRef(scaled);
|
||||||
|
completeRampTicks--;
|
||||||
|
// Stay in EVSEACTIVATE this tick; current is decaying.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dcCurController.SetRef(0);
|
||||||
|
DigIo::acpres_out.Clear();
|
||||||
|
DigIo::evseact_out.Clear();
|
||||||
|
completeRampTicks = 0;
|
||||||
|
completeRampOriginalRef = 0;
|
||||||
|
state = STOP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (vcucmd == VCUCMD_STOPPED)
|
|
||||||
|
// vcucmd not Complete — if we were mid-ramp the user reversed
|
||||||
|
// (raised limit again); restore reference before the existing
|
||||||
|
// branches take over.
|
||||||
|
if (completeRampTicks != 0)
|
||||||
|
{
|
||||||
|
dcCurController.SetRef(completeRampOriginalRef);
|
||||||
|
completeRampTicks = 0;
|
||||||
|
completeRampOriginalRef = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vcucmd == VCUCMD_STOPPED)
|
||||||
{
|
{
|
||||||
// VCU revoked the charge command (e.g. user lowered limit below
|
// VCU revoked the charge command (e.g. user lowered limit below
|
||||||
// current SOC but BMS isn't full yet). Park HV-armed in ENABLE
|
// current SOC but BMS isn't full yet). Park HV-armed in ENABLE
|
||||||
|
|||||||
Reference in New Issue
Block a user