The electric vehicle market in India is growing faster than the supply of engineers who can build the intelligent systems that power it. At the centre of every EV is a Battery Management System — the embedded intelligence that keeps a lithium-ion pack safe, efficient, and long-lasting.
This is not a beginner tutorial. It is a complete engineering guide — the kind we use at Knowx Innovations when we build BMS systems for clients and when we train ECE and EEE students to build their own. Whether you are a final year student choosing your project, a working engineer moving into the EV domain, or a startup founder building an EV product, this guide gives you the technical foundation you need.
What a BMS Does — and Why Embedded Engineers Build It
A Battery Management System is the embedded controller responsible for every intelligent function of a battery pack. Its job is to keep the pack safe, maximise energy delivery, and extend battery life — simultaneously, in real time, across every operating condition the vehicle encounters.
A Battery Management System (BMS) is an embedded electronic system that monitors and controls a rechargeable battery pack. It measures cell voltages, temperatures, and currents; estimates State of Charge and State of Health; performs cell balancing; enforces protection limits; and communicates with the vehicle's power electronics via protocols like CAN bus. Modern AI-enhanced BMS systems add machine learning for predictive SoC accuracy, degradation forecasting, and thermal anomaly detection.
The reason embedded engineers — not just electrical engineers — build BMS systems is that the intelligence layer is entirely software-defined. The hardware measures and actuates. The firmware makes decisions. And in a modern AI-enhanced BMS, machine learning models run on the microcontroller, making predictions that fixed-rule firmware could never achieve.
BMS Architecture — 5 Layers Every Engineer Must Understand
Hardware Choice — STM32 for Production, ESP32 for Learning
- ARM Cortex-M0 to M7 — automotive grade
- Hardware CAN bus peripheral built-in
- Real-time clock and watchdog timers
- STM32Cube.AI for TFLite model deployment
- ISO 26262 functional safety support
- Used by Bosch, Continental, and Tier-1 suppliers
- Cost: Rs.300–2,500 depending on variant
- Dual-core 240MHz — enough for BMS + ML
- Built-in Wi-Fi and BLE for IoT connectivity
- MicroPython or C/C++ — flexible development
- CAN via MCP2515 external module
- TFLite Micro runs comfortably
- Large community, easy debugging
- Cost: Rs.400–800
Module 1 — Cell Voltage Monitoring
The BQ76920 is Texas Instruments' battery monitor IC — it measures up to 5 series cells simultaneously, handles cell balancing in hardware, and communicates with your microcontroller via I2C. It also handles overvoltage and undervoltage protection in hardware — a critical safety feature.
Every Li-ion cell operates safely between 2.5V (minimum) and 4.2V (maximum). The BMS must monitor every cell individually — a single cell outside these limits can cause thermal runaway. Monitoring the pack voltage alone is not sufficient.
# Cell voltage reading via I2C — BQ76920 import machine, time # I2C setup on ESP32 i2c = machine.I2C(0, scl=machine.Pin(22), sda=machine.Pin(21), freq=100000 ) BQ76920_ADDR = 0x08 # Default I2C address CELL1_HI = 0x0C # Register: Cell 1 voltage high byte def read_cell_voltage(cell_num): # Each cell register = 2 bytes, 0.382mV per LSB reg = CELL1_HI + (cell_num - 1) * 2 data = i2c.readfrom_mem(BQ76920_ADDR, reg, 2) raw = (data[0] << 8) | data[1] voltage = raw * 0.000382 # Convert to volts return round(voltage, 3) def check_cell_safety(voltage, cell_id): if voltage > 4.20: print(f"ALERT: Cell {cell_id} overvoltage: {voltage}V") trigger_protection() elif voltage < 2.50: print(f"ALERT: Cell {cell_id} undervoltage: {voltage}V") trigger_protection() # Monitor all 5 cells every 500ms while True: for i in range(1, 6): v = read_cell_voltage(i) check_cell_safety(v, i) print(f"Cell {i}: {v}V") time.sleep_ms(500)
Module 2 — State of Charge Prediction with ML
Traditional SoC estimation uses Coulomb counting — integrating current over time to track charge in and out of the pack. The problem: it accumulates error. After 100 charge cycles, a 1% current measurement error becomes a 10–15% SoC error. Your dashboard shows 40% charge remaining when the battery actually has 25%.
An LSTM neural network trained on voltage, current, temperature, and cycle history estimates SoC with significantly better accuracy — typically under 3% error across the battery's lifetime. TFLite Micro runs this model directly on ESP32 or STM32 without any cloud dependency.
import numpy as np import tensorflow as tf from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.models import Sequential # Features: voltage, current, temperature, cycle_count # Target: SoC (0.0 to 1.0) SEQ_LEN = 20 # Look back 20 time steps N_FEAT = 4 # voltage, current, temp, cycle model = Sequential([ LSTM(64, input_shape=(SEQ_LEN, N_FEAT), return_sequences=True), Dropout(0.2), LSTM(32), Dropout(0.2), Dense(16, activation='relu'), Dense(1, activation='sigmoid') # SoC 0-1 ]) model.compile(optimizer='adam', loss='mse', metrics=['mae']) model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_val, y_val)) # Convert to TFLite for deployment on STM32/ESP32 converter = tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations = [tf.lite.Optimize.DEFAULT] tflite_model = converter.convert() with open('soc_model.tflite', 'wb') as f: f.write(tflite_model) print(f"Model size: {len(tflite_model)/1024:.1f} KB")
Module 3 — Thermal Management with AI
Li-ion thermal runaway is the most dangerous failure mode in EV batteries — it can cause fire within seconds once initiated. A traditional BMS cuts power when temperature exceeds a threshold. An AI-enhanced thermal management system detects the pattern that precedes thermal runaway — hours before it happens.
The key signals are not just absolute temperature but rate of temperature rise, differential temperature between cells, and correlation between temperature and current draw. An anomaly detection model trained on these multi-variable patterns catches dangerous conditions that simple threshold monitoring misses entirely.
import machine, time, math # NTC thermistor reading — Steinhart-Hart equation def read_temperature_celsius(adc_pin): adc = machine.ADC(machine.Pin(adc_pin)) adc.atten(machine.ADC.ATTN_11DB) raw = adc.read() # Voltage divider: 10kΩ pullup, NTC thermistor R_REF = 10000 # Reference resistor (ohms) V_MAX = 4095 # 12-bit ADC max R_NTC = R_REF * (V_MAX / raw - 1) # Steinhart-Hart constants for 10k NTC B=3950 B = 3950 T_NOM = 298.15 # 25°C in Kelvin R_NOM = 10000 # Resistance at 25°C temp_k = 1 / (1/T_NOM + math.log(R_NTC/R_NOM)/B) return round(temp_k - 273.15, 1) # Thermal runaway precursor detection temp_history = [] def detect_thermal_anomaly(current_temp): temp_history.append(current_temp) if len(temp_history) < 10: return False # Rate of rise over last 10 samples (1 sample/sec) rise_rate = (temp_history[-1] - temp_history[-10]) / 10 # >2°C/min rise rate = early thermal warning if rise_rate > 2.0: print(f"WARNING: Rapid temp rise {rise_rate:.2f}°C/min") return True return False
Module 4 — Cell Balancing Algorithms
Without cell balancing, the weakest cell in a series pack determines the entire pack's usable capacity. If Cell 3 reaches 4.2V (full) while Cells 1, 2, 4, and 5 are at 4.1V, charging must stop — even though 4 of the 5 cells still have capacity remaining. Cell balancing equalises voltages so the full pack capacity is available.
| Aspect | Passive Balancing | Active Balancing |
|---|---|---|
| Mechanism | Dissipates excess charge as heat via resistor | Transfers charge from high to low cells |
| Efficiency | Low — energy wasted as heat | High — energy redistributed |
| Complexity | Simple — BQ76920 handles in hardware | Complex — requires DC-DC converter |
| Best For | Student builds, low-cost BMS | Production EV BMS |
| Heat Generated | Significant — needs thermal management | Minimal |
Module 5 — Battery Degradation Prediction
Battery degradation is gradual and invisible until it is sudden. A cell that was at 95% capacity last month may be at 78% today — and the traditional BMS has no way to predict when it will drop below the 80% threshold that defines end-of-useful-life for an EV application.
A degradation prediction model trained on charge-discharge cycle data — capacity fade curves, internal resistance growth, voltage curve shape changes — can forecast remaining useful life months in advance. This is the difference between a fleet operator who replaces batteries reactively (after failure) and one who replaces them proactively (before failure causes downtime).
Key features for degradation prediction: capacity fade rate (Ah delivered vs rated), internal resistance growth (measured from voltage recovery after load), Coulombic efficiency (charge in vs charge out per cycle), and dV/dQ curve shape (characteristic changes as degradation progresses).
Module 6 — CAN Bus Integration
In a real EV, the BMS does not operate in isolation. It communicates with the motor controller, charger, dashboard, and vehicle ECU via CAN bus — the automotive industry standard for reliable, noise-resistant embedded communication. The BMS broadcasts cell voltages, SoC, temperature, and fault status. It receives charging limits and current setpoints.
For ESP32-based builds, the MCP2515 CAN controller with SPI interface is the most accessible option. For STM32, most variants have a hardware bxCAN peripheral — no external IC needed.
// STM32 CAN — Transmit BMS status frame // CAN ID 0x100 = BMS Status (custom DBC definition) CAN_TxHeaderTypeDef TxHeader; uint8_t TxData[8]; uint32_t TxMailbox; void BMS_CAN_SendStatus( uint16_t soc_pct, // SoC in 0.1% units (e.g. 756 = 75.6%) int16_t current_mA, // Pack current in mA (signed) uint16_t temp_degC, // Max cell temp in 0.1°C units uint8_t fault_flags // Bit flags: bit0=OV, bit1=UV, bit2=OT ) { TxHeader.StdId = 0x100; TxHeader.DLC = 8; TxHeader.IDE = CAN_ID_STD; TxHeader.RTR = CAN_RTR_DATA; // Pack data into 8 bytes (little-endian) TxData[0] = soc_pct & 0xFF; TxData[1] = (soc_pct >> 8) & 0xFF; TxData[2] = current_mA & 0xFF; TxData[3] = (current_mA >> 8) & 0xFF; TxData[4] = temp_degC & 0xFF; TxData[5] = (temp_degC >> 8) & 0xFF; TxData[6] = fault_flags; TxData[7] = 0x00; // Reserved HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox); }
Real Build Stories — Clients and Students at Knowx
Frequently Asked Questions
Knowx Innovations is a product development company in Bangalore building embedded AI systems for EV clients. Our training division gives ECE, EEE and CSE students hands-on experience building BMS systems and other real-world embedded AI products — with mentors who have built these systems commercially. Online and offline batches. Weekday and weekend schedules. University-compliant internship certificate included.