State machine
The BMS has a state machine that defines the behavior of the BMS.
The state is available as a variable:
/driver/state- string variable, the state name is printed/driver/statemachine/state- integer variable, the state code is printed
| Value | Mode | Printed name | Description | DSC | CHG |
|---|---|---|---|---|---|
| 0 | ERR | ERROR | Permanent ERROR | OFF | OFF |
| 10 | FAIL | FAIL | Fail (temporary) state | OFF | OFF |
| 20 | INIT | INIT | BMS is not set, minimum parametrization required | OFF | OFF |
| 30 | PROTECT | PROT | Transient state, verifying that the error(s) has disappeared | OFF | OFF |
| 40 | UNDERVOLTAGE | UV | Undervoltage of some battery cell detected | OFF | OFF |
| 60 | STORAGE | STOR | Battery is being discharged to storage voltage | OFF | OFF |
| 70 | STANDBY | STBY | BMS switched OFF, no errors | OFF | OFF |
| 80 | PRECHARGING | PRE | Starting by precharging | PRE | OFF |
| 90 | OVERVOLTAGE | OV | Overvoltage of some battery cell detected | ON | OFF |
| 100 | IDLE | IDLE | Idle state - DSC port ON but no discharging or charging current | ON | OFF |
| 110 | DISCHARGING | DISCH | Discharging battery | ON | OFF |
| 120 | REGEN | REG | Charging battery by DSC from motor | ON | OFF |
| 124 | CHG_OVERTEMP | CHOT | Charger connected, but battery temperature is outside the charging limits | ON | OFF |
| 125 | CHG_IDLE | CH_ID | Charger connected but no charging | ON | OFF |
| 130 | CHARGING | CHAR | Charging battery by CHG from charger | ON | ON |
The "Printed name" column shows the short state name printed by /driver/state and in the diagnostic logs.
How the state is evaluated
The state machine evaluates the conditions in a fixed priority order. The first matching condition wins:
- INIT — the cell count parameter
/driver/balancing/Scountis 0 (the BMS is not configured yet) - ERROR — any permanent error condition is active
- FAIL — any temporary fail condition is active
- PROTECT — any protect event is active, or the protect timer is still running
- UNDERVOLTAGE / OVERVOLTAGE — a cell voltage is out of the configured limits
- Runtime states — decided by the port command, current direction and charger detection:
- Ports commanded OFF → STANDBY
- DSC port is precharging → PRECHARGING (see precharging)
- Current flowing from the battery → DISCHARGING
- Current flowing into the battery → CHARGING (charger detected) or REGEN (no charger)
- No significant current → CHG_IDLE (charger detected) or IDLE
- Charger detected, but the battery temperature is outside the
minChg/maxChgcharging temperature limits → CHG_OVERTEMP (charging blocked, discharge stays available)
The current direction is detected with a time filter using the idle configuration (idle_current magnitude threshold and idle_timeout).
PROTECT state
The PROTECT state is entered when the BMS detects a condition that endangers the battery pack and the ports must be turned OFF. It is a transient state - the BMS stays in it for at least protect_timeout and until all protect conditions disappear. After that, the BMS returns to STANDBY, and the user must turn the ports back ON (using the sw command or over CAN).
If the BMS enters PROTECT state, the BMS will log the reason for entering the PROTECT state. The reason is available as a permanent variable protectLog. The permanent is an array of 20 logs. With a new log, the values are shifted to the right, and the oldest log is deleted. The newest log is always on the first position (most left). Use the wtf command to decode the log to human readable form - see diagnostic.
protectLog is a bitwise value - multiple reasons can be active at the same time (the values are OR-ed together).
| Value | Reason | Condition to enter |
|---|---|---|
| 0x0000 | None | No protect reason active |
| 0x0001 | Leave error state | Logged when the BMS is recovering from the FAIL state. The FAIL cause disappeared and the BMS passes through PROTECT back to normal operation. |
| 0x0002 | Shortcut | Short circuit detected on the DSC port - the current exceeded the short circuit threshold (idscShort for longer than idscDelay on BMS3, ishrt on BMS1). Increments the shortcut_counter permanent. |
| 0x0004 | Shortcut on CHG | Short circuit on the CHG port - current from the battery exceeded ichgshrt. Increments shortcut_counter. (BMS1 only) |
| 0x0008 | Shortcut on CHG to battery | Short circuit on the CHG port - current into the battery exceeded ichgshrtp. Increments shortcut_counter. (BMS1 only) |
| 0x0010 | DSC switch power overload | The power dissipated in the DSC switch transistors was too high - the switch did not close properly, or it is heavily overloaded. |
| 0x0020 | Shortcut of DSC transistor | Hardware failure of the DSC switch transistor. (legacy) |
| 0x0040 | Current overload on DSC | Overcurrent disconnect - the DSC current exceeded ocd_treshold for longer than ocd_delay. See pack current limiter. |
| 0x0080 | Connected load on CHG | A load was detected on the CHG port. (legacy) |
| 0x0100 | Charger on DSC port | A charger was detected on the DSC port. (legacy) |
| 0x0200 | Overtemp of the switch | A BMS internal temperature sensor of the switch (switchptc, mcu) exceeded its max threshold. See temperature limitation. |
| 0x0400 | Overtemp on TS inputs | A battery temperature sensor (TS input) reading is above max or below min (including the margin). See temperature limitation. |
| 0x0800 | Bat voltage measurement error | The battery voltage measurement does not match. (legacy) |
| 0x1000 | Load on DSC during charging | A load current on the DSC port was detected while charging. (legacy) |
| 0x2000 | Precharge failed | The DSC port voltage did not drop below prch_volt within precharge_time - the load capacitance is too big, or there is a short circuit on the output. See precharging. |
| 0x4000 | Cell undervoltage | The lowest cell voltage was below cellMinVoltage for more than 1 s. See cell voltage limitation. |
| 0x8000 | Cell overvoltage | The highest cell voltage was above cellMaxVoltage for more than 2 s. See cell voltage limitation. |
Cell undervoltage (0x4000) and overvoltage (0x8000) alone do not hold the BMS in the PROTECT state - the BMS transitions to the dedicated UNDERVOLTAGE / OVERVOLTAGE states, where charging (UV) or discharging (OV) is still allowed.
Difference between PROTECT and FAIL/ERROR state:
- PROTECT - protecting the battery pack
- FAIL/ERROR - protecting the BMS (and pack)
FAIL/ERROR state
If the BMS enters FAIL/ERROR state, the BMS will log the reason for entering the FAIL/ERROR state in /permanents/errorLog. The permanent is an array of 20 logs. With a new log, the values are shifted to the right, and the oldest log is deleted. The newest log is always in the first position (most left). Use the wtf command to decode the log to human readable form - see diagnostic.
The only difference between FAIL and ERROR state is that the ERROR state is permanent, and the FAIL state is temporary. If you are in FAIL and the reason for entering the FAIL state is resolved, the BMS will automatically leave the FAIL state. If the BMS is in the FAIL for a longer time than the fail_timeout, the BMS will enter the ERROR state.
Values 100 and above are FAIL (recoverable) reasons, values below 100 are ERROR (permanent) reasons.
If the BMS is in the ERROR state, the BMS will disable wake from the CAN bus. Before communicating with the BMS, it is necessary to wake up the BMS by pressing the button.
ERROR reasons (permanent)
| Value | Reason | Condition to enter |
|---|---|---|
| 0 | None | No error active |
| 5 | Max fails reached | The permanent fail_counter exceeded the max_fails parameter. The counter is incremented on every entry into the FAIL state. |
| 6 | Max shortcuts reached | The permanent shortcut_counter exceeded the max_shortcuts parameter. The counter is incremented on every short circuit event (any of the shortcut PROTECT reasons). |
| 7 | Fail timer | The BMS stayed in the FAIL state for longer than the fail_timeout parameter without the fail reason disappearing. |
| 10 | Panic | The battery was overcharged over the DSC port - cell overvoltage was active while charging current kept flowing into the battery for more than 20 s. The BMS cannot stop current flowing into the DSC port (it flows through the MOSFET body diodes), so it enters the permanent error as a last resort. |
| 10 | Hardware error | The hw_error state is non-zero - a hardware problem was detected during initialization or at runtime. See hardware status. |
Panic and hardware error share the same log value 10.
FAIL reasons (temporary)
| Value | Reason | Condition to enter |
|---|---|---|
| 101 | Heatsink isolation | The heatsink isolation voltage heatsink_isol left the allowed window - the heatsink is no longer isolated from the battery potential (e.g. moisture, mechanical damage). The behavior is configured by the htsIsolCfg parameter. |
| 102 | Balancer error | The balancer IC reports an error - the BMS cannot communicate with the balancer chip (communication problem), a parameter could not be written to the chip, or the chip reports an internal fault. |
| 103 | Balancer fail | The balancer IC stopped responding at runtime. The BMS retries the communication every 5 s. If the balancer does not recover within fail_timeout, the BMS enters the permanent ERROR state. |
| 104 | Critical undervoltage | A cell voltage was below the /driver/balancing/limiter/CritUnderVoltage parameter for more than 10 minutes. The battery is deeply discharged, and the BMS goes to sleep to prevent further discharge. |
| 105 | Battery disbalanced | Cell undervoltage and overvoltage detected at the same time - the battery is heavily disbalanced. |
| 106 | Cell check fail | The cell connection check failed - some cells report an unexpected voltage (see badCells in balancing states), or the sum of all cell voltages differs from the measured pack voltage by more than 1 V. Typical cause: wrong Scount setting or a broken cell sense wire. |
Recovering from the ERROR state
The ERROR state is permanent - the BMS will not leave it automatically. To recover:
- Wake the BMS by pressing the button (CAN wake is disabled in ERROR).
- Resolve the cause of the error (check
errorLogwith thewtfcommand). - Use the
clr_errshell command - it clears the error state and resets thefail_counterandshortcut_counterpermanents.
State machine configuration
The state machine is configured in the /driver/stateMachine folder.
| Parameter | Unit | Description |
|---|---|---|
fail_timeout | s | If the state is FAIL for longer time than the timeout, the BMS enter ERROR state |
max_fails | - | Maximum number of fails before entering ERROR state |
max_shortcuts | - | Maximum number of shortcuts before entering ERROR state |
protect_timeout | s | Minimum time in PROTECT state before recovering |
State machine states
These read-only states are available in the /driver/stateMachine folder.
| State | Description |
|---|---|
state | Internal state machine state code (see the state table above) |
cmd_drv | Pending command for the ports: 0 = OFF, 1 = DSC on, 2 = CHG on, 3 = DSC+CHG on |
fail_timer | Remaining time in ms before the FAIL state becomes a permanent ERROR |
protect_timer | Remaining minimum time in ms in the PROTECT state |
State machine permanents
| Permanent | Description |
|---|---|
fail_counter | Count of FAIL state entries. When it exceeds max_fails, the BMS enters the ERROR state. Cleared by clr_err. |
shortcut_counter | Count of short circuit events. When it exceeds max_shortcuts, the BMS enters the ERROR state. Cleared by clr_err. |