EVerest / EVerest/EVerest

[Bug] DC charging power limited by BSP AC PP ampacity (hw_caps.max_current_A_import) instead of fuse_limit_A

Open
#2,291 0 comments 0 reactions 1 assignee Claimed by @SebaLukas View on GitHub
EvseManager
Dominant language
C++
Stars
262
Forks
195
Avg merge
4d 19h
Merged PRs (30d)
49

Description

### Describe the bug

Description:

When using EVerest for DC fast charging, the maximum charging power is incorrectly limited to ~21kW (32A × 220V × 3-phase) regardless of fuse_limit_A configuration. This occurs because the BSP's AC hardware capability (hw_caps.max_current_A_import), which is derived from the DC CCS cable's PP (Proximity Pilot) pin resistance, is incorrectly applied as the grid-side AC current limit for DC charging.

Environment:
- everest-core: 2025.12.1
- everest-framework: 0.25.0
- Hardware: Phyverso-EVCS (AM62), PhyVersoBSP, InfyPower REG1K0100 DC PSU (×9, 270kW total)
- Protocol: DIN70121 DC charging

Steps to Reproduce:

1. Configure EVerest for DC charging with PhyVersoBSP and a DC PSU module
2. Set fuse_limit_A: 500 in grid_connection_point config
3. Set conn1_max_current_A_import: 500 in phyverso_mcu (PhyVersoBSP) config
4. Connect a DC CCS Type 2 cable and initiate charging
5. Observe EVSE ISO Change HLC Limits in logs and ChargeParameterDiscovery vs CurrentDemand via pcap

Observed Behavior:

- ChargeParameterDiscovery: Correctly advertises PSU hardware capability (270kW / 918A)
- CurrentDemand EVSE Maximum Power Limit: 21,120W (= 32A × 220V × 3ph)
- Energy manager debug log confirms:
"ac_max_current_A": {
"source": "evse_manager_port1/evse_board_support_caps",
"value": 32.0
}
- Despite fuse_limit_A: 500, grid power budget is capped at 21kW

Expected Behavior:

- CurrentDemand EVSE limits should be derived from fuse_limit_A and PSU capabilities, not from the BSP's AC PP ampacity
- Grid-side AC current limit should be: fuse_limit_A × nominal_voltage × phase_count

Root Cause Analysis:

1. DC CCS cable PP resistance → 32A:

The DC CCS cable has a PP pin resistance of ~1500Ω. PhyVersoBSP/board_support_common.cpp maps this to Ampacity::A_32 → published via publish_ac_pp_ampacity(). The EvseManager receives this and sets IECStateMachine.pp_ampacity = 32.

2. hw_caps.max_current_A_import becomes 32A:

The PP ampacity (32A) propagates into hw_caps.max_current_A_import, which the energyImpl uses when building energy requests.

3. Bug in energyImpl.cpp::clear_import_request_schedule() (line 64):

// modules/EVSE/EvseManager/energy_grid/energyImpl.cpp
entry_import.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import}; // = 32A from PP

This sets the EVSE's AC current request to 32A for ALL charge modes including DC. The energy manager then allocates exactly 32A (the minimum of grid fuse 500A and EVSE request 32A).

4. Same issue in request_energy_from_energy_manager() (line 212):

if (!e.limits_to_root.ac_max_current_A.has_value() ||
e.limits_to_root.ac_max_current_A.value().value > hw_caps.max_current_A_import) {
e.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import, source_bsp_caps};

No DC mode guard — caps AC current to 32A even for DC charging.

Note: The ChargeParameterDiscovery correctly uses PSU hardware capabilities (separate path), which is why ChargeParameterDiscovery shows 270kW but CurrentDemand shows 21kW.

Proposed Fix:

In modules/EVSE/EvseManager/energy_grid/energyImpl.cpp:

Fix 1 - clear_import_request_schedule(): Do not set ac_max_current_A from BSP hw_caps for DC mode. For DC charging, the AC grid current constraint should be determined solely by the upstream EnergyNode (via fuse_limit_A).

// Remove or guard these lines for DC mode:
- entry_import.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import};
- entry_import.limits_to_root.ac_min_current_A = {hw_caps.min_current_A_import};

Fix 2 - request_energy_from_energy_manager(): Add DC mode guard around the hw_caps AC current capping:

if (mod->config.charge_mode != "DC") {
if (!e.limits_to_root.ac_max_current_A.has_value() ||
e.limits_to_root.ac_max_current_A.value().value > hw_caps.max_current_A_import) {
e.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import, source_bsp_caps};
...
}
}

Rationale: For DC charging, hw_caps.max_current_A_import represents the AC cable ampacity from the PP proximity pilot (a DC cable connector property, not the charger's AC input capacity). This value must not constrain the DC charger's grid-side AC current, which is correctly controlled by fuse_limit_A in the upstream EnergyNode.

### Expected behavior

_No response_

### EVerest Domain

Energy Management

### Affected Component
```diff
diff --git a/modules/EVSE/EvseManager/energy_grid/energyImpl.cpp b/modules/EVSE/EvseManager/energy_grid/energyImpl.cpp
index 7a5ec5b1..0fd0c489 100644
--- a/modules/EVSE/EvseManager/energy_grid/energyImpl.cpp
+++ b/modules/EVSE/EvseManager/energy_grid/energyImpl.cpp
@@ -61,13 +61,14 @@ void energyImpl::clear_import_request_schedule() {
entry_import.timestamp = tp;
entry_import.limits_to_root.ac_max_phase_count = {hw_caps.max_phase_count_import};
entry_import.limits_to_root.ac_min_phase_count = {hw_caps.min_phase_count_import};
- entry_import.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import};
- entry_import.limits_to_root.ac_min_current_A = {hw_caps.min_current_A_import};
entry_import.limits_to_root.ac_supports_changing_phases_during_charging =
hw_caps.supports_changing_phases_during_charging;
entry_import.limits_to_root.ac_number_of_active_phases = mod->ac_nr_phases_active;

if (mod->config.charge_mode == "DC") {
+ // For DC charging, BSP hw_caps AC current (from PP cable rating) must not limit
+ // the grid-side AC current. Grid limit is set by fuse_limit_A in grid_connection_point.
+ // ac_max_current_A and ac_min_current_A are intentionally not set for DC mode.
// For DC, apply our power supply capabilities as limit on leaves side
const auto caps = mod->get_powersupply_capabilities();
entry_import.limits_to_leaves.total_power_W = {caps.max_export_power_W,
@@ -206,17 +207,21 @@ void energyImpl::request_energy_from_energy_manager(bool priority_request) {
}
}

- // apply our local hardware limits on root side
+ // apply our local hardware limits on root side (AC mode only)
+ // For DC mode, BSP hw_caps AC current limit comes from PP cable rating and must not
+ // restrict grid-side current. Grid limit is controlled by fuse_limit_A in grid_connection_point.
for (auto& e : energy_flow_request.schedule_import) {
- if (!e.limits_to_root.ac_max_current_A.has_value() ||
- e.limits_to_root.ac_max_current_A.value().value > hw_caps.max_current_A_import) {
- e.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import, source_bsp_caps};
-
- // are we in EV pause mode? -> Reduce requested current to minimum just to see when car
- // wants to start charging again. The energy manager may pause us externally to reduce to
- // zero
- if (charger_state == Charger::EvseState::ChargingPausedEV && mod->config.request_zero_power_in_idle) {
- e.limits_to_root.ac_max_current_A = {hw_caps.min_current_A_import, source_bsp_caps};
+ if (mod->config.charge_mode != "DC") {
+ if (!e.limits_to_root.ac_max_current_A.has_value() ||
+ e.limits_to_root.ac_max_current_A.value().value > hw_caps.max_current_A_import) {
+ e.limits_to_root.ac_max_current_A = {hw_caps.max_current_A_import, source_bsp_caps};
+
+ // are we in EV pause mode? -> Reduce requested current to minimum just to see when car
+ // wants to start charging again. The energy manager may pause us externally to reduce to
+ // zero
+ if (charger_state == Charger::EvseState::ChargingPausedEV && mod->config.request_zero_power_in_idle) {
+ e.limits_to_root.ac_max_current_A = {hw_caps.min_current_A_import, source_bsp_caps};
+ }
}
}
```

### EVerest Version

_No response_

### To Reproduce

_No response_

### Anything else?

- everest-core: 2025.12.1 (confirmed in 2026.02.0-rc3-158-g2adf92e7 as well)
- Commit: 2adf92e7
- everest-framework: 0.25.0
- Hardware: Phyverso-EVCS (AM62x), PhyVersoBSP, DC PSU
- Charge mode: DC (DIN70121)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.