16-cell BMS

From openinverter.org wiki
Jump to navigation Jump to search
16-cell BMS

The goal of this BMS is to use mostly decade old components to create a 16 channel cell voltage meter. It uses a very accurate sigma/delta ADC for superb resolution. It can drain about 100mA from a cell or charge it with 50 mA via the DC/DC converter. The ability to both charge and discharge cells speeds up balancing despite the low balancing current.

When turned off it drains no current from the connected cells at all.

On the low voltage side it features two inputs for temperature sensors and one input for a 5V current sensor, differential or single ended.

It can be cascaded to be used with more than 16 cells and has an automatic addressing scheme to forgo the use of jumpers or DIP switches. All communication is done via CAN. Supply voltage is 12V with about 20 mA draw when not balancing.

The software is not yet finished, see forum for progress [1]


The pinout is also written to the bottom silkscreen.

On the left side you see 17 inputs. The first one is connected to the negative pole (GND) of your (sub)pack, the subsequent ones to the positive poles of up to 16 cells. At least the lower two cell inputs must be connected. When cascading modules the positive-most input of module n is also the GND of module n+1, so must be spliced to connect to both.

On the top right is the vehicle interfacing or low voltage connector. From top to bottom it is low voltage GND, 12V, enable_in, enable_out, CANH, CANL. GND, 12V, CANH, CANL are connected to all modules in parallel whereas enable_out is chained to enable_in of the next module. The first enable_in must be connected to 12V whenever the BMS should become active, e.g. when charging or driving. The module with 12V on the enable_in auto-detects as "main" module, collects data from the subsequent modules and sends more high level CAN messages

On the bottom right is the temperature sensor and current sensor input. Top to bottom it is tsensor1+, tsenseor1-, tsensor2+, tsensor2-, 5V, CUR+, CUR-, GND. A single ended current sensor is just connected to CUR+.

Right now the current sensor is only supported on the main module and only one temperature sensor is supported.


All configuration, queries and firmware updates are done via the CAN bus. There is no independent web interface like known from e.g. the inverter. However there is a solution to connect an ESP32 via CAN and then have the known web interface [2] or you can use Dave Fiddes "oic" tool for the command line[3]. It is important to know that the main module has node-id 3 and the subsequent ones 3+i (i index of submodule, so 1st submodule has node-id 4). The base node id can be configured to start at something else than 3.

All info given here is preliminary and will likely change!

Apart from that the modules output periodic CAN messages depending on their role.

All modules output on ID 500 (0x1F4) + i

start length item description
0 13 umin minimum cell voltage of module i
16 13 umax maximum cell voltage of module i
30 2 counter counts from 0-3 (anti-freeze)
32 13 uavg average cell voltage of module i
48 8 tempmin Minimum temp +40 on module i
56 8 tempmax Maximum temp +40 on module i

The main module does not output its local accumulated values but accumulated values over all modules.

In addition the main module outputs on id 300 (0x12C)

start length item description
0 11 chargelim maximum charge current in A
11 11 dischargelim maximum discharge current in A
22 10 soc Pack soc in 0.1%
32 16 idcavg Averaged current reading of last 1s in 0.1A - signed!
48 10 utotal Total pack voltage in V
62 2 counter counts from 0-3 (anti-freeze)

Reading individual cell voltages

Cell voltages are only available via CAN SDO from the module that measures them. So voltages 1-16 must be queried from the first (main) module, 17-32 from the 2nd (1st submodule) and so on. With Dave Fiddes tool this translates to:

oic -n 3 dumpall #dumps all values including cell voltages from 1st module
oic -n 4 dumpall #same for second module
oic -n 4 read u0 #Read first cell voltage of second module

For querying voltages say in your arduino sketch you'll need to acquire every voltage separately by sending and receiving SDO messages

0x603#0x40 idhigh 0x21 idlow 0 0 0 0

idhigh and low are the bytes of the internal ID. The id of the first cell voltage is 2006 (0x7D6) so for querying the 1st cell voltage of the first module you send

0x603#0x40 0x07 0x21 0xD6 0 0 0 0

And you will receive the reply

0x583#0x43 0x07 0x21 0xD6 0xD0 0xED 0x01 0

0x0001EDD0 is the voltage value which decodes to mV x 32. So 0x1EDD0/32 = 3950.5 mV.

The next cell would be on 0x7D7 and the last on 0x7E5. The next 16 voltages are then queried from node id 0x604.

Configuration Parameters

There is currently a limited set of parameters which will be extended as the software grows.

Name Unit Min Max Default Description
gain uV/dig 1 1000 586 Scaling factor from ADC digits to mV
correction0 ppm -10000 10000 -1250 The first two and the last channel have slightly different topology and need their own correction factor
correction1 ppm -10000 10000 1500
correction15 ppm -10000 10000 1000
numchan 1 16 16 Number of cells connected to the module
balmode 0 3 0 Balancing mode

0=No balancing 1=Only bump up low cells 2=Only dissipate high cells 3=Do both

ubalance mV 0 4500 4500 Voltage above which top balancing is started
idlewait s 0 100000 60 Number of seconds to wait after stop of current flow to measure unloaded cell voltage und start balancing
Battery Limits
ucellmin mV 1000 4500 3300 Minimum loaded cell voltage. Discharge limit is dropped to stay above this value
ucellmax mV 1000 4500 4200 Maximum loaded cell voltage. Charge limit is dropped to stay below this value
chargemax A 1 2047 200 Maximum charge current
dischargemax A 1 2047 200 Maximum discharge current
chargeXsoc % 0 100 Percentage of charge current at soc X. In between two points charge current is interpolated
Battery Characteristics
nomcap Ah 0 1000 100 Nominal capacity
ucellXsoc mV 2000 4500 Unloaded cell voltage at SoC X. Voltages in between to points are interpolated. Used for SoC estimation.
Sensor Setup
idcgain dig/A -1000 1000 10 Gain (or actually division factor) of current sensor
idcofs dig -4095 4095 0 0A offset
idcmode 0 3 0 Current sensor mode 0=Off, 1=Single Ended ADC, 2=Differential ADC, 3=ISA current shunt
tempsns -1 3 -1 Temperature sensor -1=Off, 0=JCurve, 1=KTY81, 2=PT1000, 3=LeafBMS
pdobase 0 2047 500 base COB Id for cyclic messages. Main module uses pdobase, 1st submodule uses pdobase+1 and so on

Must always be set to the same value on all modules!

sdobase 0 63 3 base node ID for SDO queries. Main module uses sdobase, 1st submodule sdobase+1 and so on

Must always be set to the same value on all modules!


Calculating current limits

Limiting charge and discharge current are the only means of this BMS to protect the battery. It has no means to turn off the current flow by itself but instead relies on the connected components to obey the calculated current limits that are sent out via CAN. The current limits are calculated in a number of steps.

Charge Curve

Charging the battery happens via a pre-determined charge curve. Since we have no battery knowledge ourself we need to mimic what we see the OEM BMSes do. The charge curve usually starts at its maximum charge current when the battery is empty and then around 30-50% cuts back. 10 points can be configured of the charge curve at 0, 10, ..., 90%

In contrary when discharging there is no pre-determined curve, we only limit the minimum per-cell voltage by limiting the discharge current

Voltage limits

Voltage limits are enforced via a P-regulator. I.e. as we approach the upper or lower voltage limit current is cut back to stay away from the limits until it reaches 0A. The upper and lower limit is configurable

Temperature limits

These are not enforced yet. High temperature will cut back both charge and discharge current whereas low temperature will only cut back charge current.

Energy limits

Not enforced yet. Some OEM BMSes cut back charge current after a certain amount of energy has been put into the battery. E.g. When starting charge at 50% charge rate will end up higher at 70% than if we start charging at 10%.