Skip to content
Mooiweer edited this page Apr 10, 2025 · 1 revision

ION E-Bike Battery Emulator & System Hacking Wiki

Welcome to the ION E-Bike Battery Emulator Wiki. This is a documentation effort based on a large collaborative analysis from the pedelec community to reverse-engineer and revive the ION motor system used in older Dutch e-bikes, such as those from Sparta, Batavus, and Koga.


Contents


Introduction

The ION system, once a mainstream drive unit in the Netherlands, has become obsolete due to aging batteries and proprietary designs. While the mechanical and electrical parts of the e-bikes remain functional, users are often left with unusable systems. This project explores the development of an emulator for the ION battery and display, allowing the reuse of these bikes with custom lithium-ion batteries and open-source controllers.


Project Goals

  • Replace the original ION battery with a custom Li-Ion pack.
  • Understand and emulate the serial communication protocol.
  • Enable full functionality of the motor (including assist modes).
  • Use inexpensive hardware (ESP32, USB UART) for emulation.
  • Document everything for community use and development.

ION System Architecture

Note: While the most commonly documented motor is the Toprun MMU1, there may be multiple versions or models used across Sparta, Batavus, and Koga bikes that employ the ION system. These motors are all believed to support the BOW bus protocol and share similar communication behavior, but may differ in firmware, response timing, or handshake validation routines.

Further documentation of alternative ION-compatible motors is encouraged if identified.

Components:

  • Motor: Toprun (MMU1), integrated controller.
  • Battery: PMU1 or PMU2, typically NiMH or early Li-Ion, integrated BMS.
  • Display: CU2 (round), CU3 (rectangular), with limited feedback.
  • Communication: Single-wire bus (half-duplex UART at ~9600 baud).

Communication Topology: All components communicate over a shared single-wire bus. Data is exchanged in a serialized protocol with distinct packet headers, payloads, and checksums.


BOW Bus Protocol & Communication

The ION system uses a single-wire serial protocol commonly referred to as the BOW bus. This protocol is shared across all system components β€” motor, battery, display, and external tools like BowTool or ESP32 emulators. It runs at 9600 baud and follows a defined message structure.

Byte-by-Byte Example Breakdown

Additional Command Examples

EEPROM Write Command
10 C1 31 00 00 01 FF 31
Byte(s) Description Value
10 Start Byte Constant
C1 Source (Motor or Tool) 0xC1
31 Command (Write EEPROM) 0x31
00 00 Start Address 0x0000
01 Length 1 byte
FF Data to write 0xFF
31 Checksum XOR of above
Status Response Packet
10 2B 04 01 2E
Byte(s) Description Value
10 Start Byte Constant
2B Source (Battery or Motor) 0x2B
04 Command (Status Response) 0x04
01 Payload (Assist Level = Low) 0x01
2E Checksum XOR
EEPROM Read Command
10 C1 30 00 00 01 00 30
Byte(s) Description Value
10 Start Byte Constant
C1 Source (Motor or Tool) 0xC1
30 Command (Read EEPROM) 0x30
00 00 Start Address 0x0000
01 Length 1 byte
00 Padding / reserved 0x00
30 Checksum XOR of above
Display Assist Level Request
10 21 03 01 23
Byte(s) Description Value
10 Start Byte Constant
21 Source (Display) 0x21
03 Command (Request Data) 0x03
01 Payload: Assist Level e.g. Low
23 Checksum XOR

Let's take the example message:

10 C1 08 11 22 33 08 AA

Breakdown:

Byte(s) Description Value
10 Start Byte Constant
C1 Source Address (Motor) 0xC1
08 Command Code (Handshake Request) 0x08
11 22 33 Handshake Payload (token/seed) Variable
08 Echoed Command Code or Sub-ID 0x08
AA Checksum XOR of bytes

The exact function of each byte can vary slightly by command. Many commands echo their ID later in the payload for validation.

πŸ’‘ Checksum is typically XOR of all previous bytes in the packet. Incorrect checksum causes the receiver to ignore the packet.

Basic Protocol Format:

[Start Byte] [Source] [Target] [Command] [Data ...] [Checksum]

Message Types:

  • 0x00: Alive ping (no payload)
  • 0x01: Command with payload
  • 0x02: Response with payload
  • 0x03: Response no payload (ack)
  • 0x04: Status check (no payload)

Example Command:

  • 10 C1 21 22 01 6F: Sent from Battery to Display, requesting status/interaction.

Behavior Observed:

  • Alive messages (0x00) rotate between components.
  • Motor initiates handshake via command 0x08, expects response containing specific byte sequence.
  • Battery logs and reuses data from previous shutdown for validation.

Reverse Engineering the Communication

Key Observations:

  • Display does not send alive pings, only responses.
  • Motor-to-Battery handshake:
    • Motor sends 0x08 request with values.
    • Battery replies with 0x2B 08 ... using values previously received in 0x09 at shutdown.
  • Assist levels:
    • User button presses are logged as changes in specific bytes (e.g., 00 -> 01, 02, 03).
    • Motor doesn’t respond unless full interaction between battery and display is valid.

Issues:

  • Some data may be signed or encrypted.
  • Byte 5 of some messages acts like a rolling counter.
  • Potential use of serialized handshake token or challenge-response for security.

Hardware Requirements

Below is a complete list of components typically used to build a circuit board for emulating the ION system using an ESP32:

Core Components

  • 1Γ— ESP32 microcontroller board (e.g. DevKitC, WROOM, ESP32 SuperMini, or TTGO)
  • 1Γ— USB-to-UART bridge (if not integrated)

Power & Protection

  • 1Γ— DC-DC buck converter (26V to 5V or 3.3V output)
  • 1Γ— Fuse (e.g. 1A fast-blow)
  • 1Γ— TVS diode (e.g. SMAJ26CA)

Voltage Divider (for RX tap)

  • 1Γ— 220kΞ© resistor
  • 1Γ— 47kΞ© resistor

Bus Interface

  • 1Γ— NPN transistor (e.g. BC547 or 2N3904 for TX gating)
  • 1Γ— 10kΞ© resistor (for transistor base)
  • Optional: 1Γ— logic-level MOSFET (for active bus driving or isolation)
  • 1Γ— Diode (1N4148 or similar for TX protection)
  • 1Γ— 1kΞ© series resistor (TX line isolation)
  • 1Γ— 10kΞ© pull-up resistor (optional for RX stability)

Connectors

  • 1Γ— 2- or 3-pin screw terminal or JST for bus and power

Debug & Status

  • 1–2Γ— LEDs with current-limiting resistors
  • 1Γ— Push button (optional for reset/mode)

Optional Enhancements

  • 1Γ— SD card module (for UART log storage)

  • 1Γ— OLED or TFT display (TTGO-style boards)

  • 1Γ— 3.3V LDO regulator (if not onboard)

  • Microcontroller: ESP32 preferred (UART + Wi-Fi for debugging).

  • Sniffing tools:

    • USB-UART Converter (e.g., FTDI, CP2102).
    • Resistor divider for voltage level matching (e.g., 220k to 47k).
  • Power Supply: 26V DC (lab supply or battery).

  • Optional: Oscilloscope to visualize waveform/timing.

To-Do List: Build an ION Battery Emulator Board

  1. Gather Parts

    • Order ESP32 board (DevKit, TTGO, ESP32 SuperMini, etc.)
    • Acquire resistors, transistor, diode, connectors, etc. (see Hardware Requirements)
  2. Design Circuit

    • Draw schematic with UART tap, TX buffer, and power handling
    • Include voltage divider and optional MOSFET/LEDs
  3. Breadboard Prototype (Optional)

    • Assemble basic working version for testing
    • Validate signal levels and pinout
  4. Build PCB (optional)

    • Create PCB layout in KiCad or Fritzing
    • Order from manufacturer (e.g. JLCPCB, OSH Park)
  5. Build the Firmware

    • Clone example projects from GitHub (e.g., void-spark/ion1)
    • Implement UART receive and response logic in Arduino or PlatformIO
    • Define packet formats, timing, and assist level behavior
    • Incorporate startup handshake and alive pings
    • Use logging to fine-tune responses during interaction with motor/display
  6. Flash Firmware

    • Use Arduino IDE or PlatformIO to upload UART sniffer/emulator code
    • Modify handshake logic if needed
  7. Connect to Bike

    • Tap into display/motor wiring via bus line
    • Use lab power supply or real battery to simulate voltage
  8. Debug & Monitor

    • Use HTerm, Serial Monitor, or Telnet for log output
    • Adjust timing/response based on feedback
  9. Optimize & Share

    • Log packets, refine firmware
    • Publish schematic/code for community use
  10. Gather Parts

    • Order ESP32 board (DevKit, TTGO, etc.)
    • Acquire resistors, transistor, diode, connectors, etc. (see Hardware Requirements)
  11. Design Circuit

    • Draw schematic with UART tap, TX buffer, and power handling
    • Include voltage divider and optional MOSFET/LEDs
  12. Breadboard Prototype (Optional)

    • Assemble basic working version for testing
    • Validate signal levels and pinout
  13. Build PCB (optional)

    • Create PCB layout in KiCad or Fritzing
    • Order from manufacturer (e.g. JLCPCB, OSH Park)
  14. Flash Firmware

    • Use Arduino IDE or PlatformIO to upload UART sniffer/emulator code
    • Modify handshake logic if needed
  15. Connect to Bike

    • Tap into display/motor wiring via bus line
    • Use lab power supply or real battery to simulate voltage
  16. Debug & Monitor

    • Use HTerm, Serial Monitor, or Telnet for log output
    • Adjust timing/response based on feedback
  17. Optimize & Share

    • Log packets, refine firmware
    • Publish schematic/code for community use

ESP32 Setup & Configuration

The ESP32 is used as the main controller to both emulate and sniff bus traffic. It provides flexibility, real-time processing, and wireless debugging options.

Recommended Boards

The following ESP32 boards are commonly used in the ION emulator community:

  • ESP32 DevKitC (Espressif Official): Standard, breadboard-friendly.
  • ESP32 NodeMCU / DOIT Dev Boards: Common with CP2102/CH340 chips.
  • TTGO T-Display / T-Beam: Adds onboard screen or GPS; more complex.
  • ESP32-WROOM modules: Embedded in custom PCBs or permanent installations.
  • Estardyn ESP32-C3 SuperMini: Very small ESP32-C3 board.

ESP32-C3 Compatibility

Some users experiment with ESP32-C3 boards. These are RISC-V based, low-power versions of ESP32s. They can work, but with limitations:

Pros:

  • Small, power-efficient
  • Cheap and widely available

Cons:

  • Only one UART (usually used for USB logging)
  • Requires software serial (bit-banging) or UART reassignment

Tested ESP32-C3 Boards:

  • LILYGO TTGO T-OI Plus (C3)
  • ESP32-C3-DevKitM-1
  • WEMOS D1 Mini ESP32-C3
  • M5Stamp C3
  • Ai-Thinker ESP-C3-32S Kit
  • Estardyn ESP32-C3 SuperMini

⚠️ Tip: Use GPIO20 and GPIO21 for software UART on some C3 boards, and validate stable operation at 9600 baud.

The ESP32 is used as the main controller to both emulate and sniff bus traffic. It provides flexibility, real-time processing, and wireless debugging options.

Pin Configuration Example:

  • GPIO17 = RX (connected to voltage divider tap)
  • GPIO16 = TX (connected to motor bus via diode or resistor)
  • 3.3V and GND from ESP32 to voltage divider

Typical Voltage Divider Setup:

To safely read the 26V bus:

     26V Bus
       |
      [220k]
       |
       |------> RX (ESP32 GPIO17)
       |
      [ 47k ]
       |
      GND

Firmware/Code Base:

  • Written in C++ or Arduino framework
  • Reads raw UART data
  • Decodes frames based on ION protocol format
  • Can replay captured handshake sequences
  • Optionally logs to serial monitor or SD card

Minimal Example Code (Arduino/C++)

#define RX_PIN 17
#define TX_PIN 16

void setup() {
  Serial.begin(115200);
  Serial2.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN);
}

void loop() {
  if (Serial2.available()) {
    uint8_t b = Serial2.read();
    Serial.printf("%02X ", b);
  }
}

Debugging Tips:

  • Use Wi-Fi + Telnet for real-time monitoring
  • Use hardware serial (Serial1/Serial2) for clean separation
  • Add CRC checks to validate message structure

Example Use Case:

  • Emulate display and battery behavior to trigger motor startup
  • Intercept button presses and respond accordingly
  • Forward or generate valid speed signals

Software & Tools


BowTool

BowTool is a diagnostic and configuration utility originally developed by or for the ION system to read out and configure battery firmware parameters.

What it is:

  • A Windows-based tool (often distributed as bowtool.exe) used by professionals and enthusiasts to interface with ION battery packs.
  • It communicates through an RS232 serial port or USB-UART adapter.
  • Offers access to internal BMS data, EEPROM contents, fault codes, and battery history.

What you can do with it:

  • Read battery cycle count, temperature data, and charge levels.
  • Check error codes and reset soft faults (Like E0003).
  • Identify firmware versions and hardware IDs.
  • Extract EEPROM data for reverse engineering.

How to Use:

  1. Connect the ION battery to your PC using a USB-to-Serial interface.
  2. Set up proper COM port settings (usually 9600 baud, 8N1).
  3. Launch bowtool.exe (if available).
  4. Choose the appropriate port and begin scanning.
  5. Browse or export battery info from the interface.

NiMH vs Li-Ion Batteries

The ION system has evolved across two generations of battery technology, both with unique characteristics and challenges for emulation:

NiMH Batteries (Nickel Metal Hydride)

  • Used in early ION bikes (e.g. PMU1).
  • Typically 24-cell packs (1.2V nominal per cell).
  • Nominal pack voltage: 28.8V, fully charged: ~34V.
  • Heavy and less energy dense.
  • Includes simple internal BMS with temperature sensing and slow charging logic.
  • Known to slowly degrade and self-discharge over time.
  • Original BMS may contain EEPROM data required for handshake with the motor controller.

Li-Ion Batteries (Lithium-Ion)

  • Used in later ION bikes (e.g. PMU2).
  • Typically 7S or 8S configuration (3.6–4.2V per cell).
  • Nominal pack voltage: 25.2V (7S) or 29.6V (8S).
  • Lighter and higher energy density.
  • More sophisticated BMS with cell balancing, over/under-voltage protection, and history tracking.
  • Often contain firmware that validates the pack to the system using serial numbers or tokens.

Emulation Implications

  • Voltage matching is critical β€” emulate a realistic range for the motor to accept power.
  • Handshake data must be preserved or mimicked between shutdown/startup.
  • Thermal sensors and current sense lines may be required for full functionality.
  • Older NiMH-based bikes may be easier to spoof, but newer Li-Ion systems may perform firmware checks.

πŸ› οΈ Tip: Use an adjustable lab power supply or a custom-built Li-Ion pack to mimic NiMH voltages for testing without the original battery.

Safety Considerations

Working with e-bike battery systems, especially custom-built Li-Ion packs, introduces electrical and thermal risks. Always take the following precautions:

  • Use a BMS (Battery Management System) with overcurrent and undervoltage protection.
  • Include fuses in series with the power line to prevent short-circuit damage.
  • Avoid working on live systems; disconnect the pack before rewiring or flashing.
  • Do not charge unbalanced Li-Ion packs without protection.
  • Monitor temperature and current during charge/discharge cycles.

Motor Feedback Signals

The motor controller provides several outputs and feedback lines, including:

  • Speed signal (Hall-based): Pulses that can be measured by the display.
  • Assist signal (PWM or data): Used internally by the motor logic.
  • Voltage sense: The battery may monitor back EMF from the motor.

For full emulation, it's useful to understand and, if needed, simulate these feedback lines.


CU2 vs CU3 Display Comparison

Feature CU2 (Round) CU3 (Rectangular)
Display Shape Circular Rectangular
Serial Number Binding Sometimes ignored Often strictly checked
Protocol Behavior Identical (mostly) Identical
Assist Button Mapping Simple up/down Same, but layout varies
Compatibility High May require valid token

Logging Best Practices

  • Use HTerm or similar serial logging tools that support timestamping.
  • Include idle time or user actions in your annotations.
  • Label source (e.g. Motor β†’ Battery) for each packet.
  • Use spreadsheets to sort and highlight repeating patterns.
  • Save logs in raw hex + ASCII format for decoding tools.

Emulator Development Checklist

Feature Required? Notes
Voltage Emulation βœ… Use lab supply or BMS-controlled pack
Handshake Token Retention βœ… Needed between shutdown/startup cycles
Serial Number Emulation ⚠️ Required for CU3 and some motors
Assist Level Request/Response βœ… Required to enable motor support
Alive and Ping Message Rotation βœ… Maintains sync between components
Log File Generation Optional Helps with debugging and development

Protocol State Diagram

Below is a simplified state diagram showing the flow of communication during system operation:

[Startup] 
   ↓
[Battery β†’ Display] β€” Alive Ping
   ↓
[Motor β†’ Battery] β€” Handshake Init (0x08)
   ↓
[Battery β†’ Motor] β€” Handshake Reply
   ↓
[Display β†’ Battery] β€” Assist Level Request
   ↓
[Motor Engaged] if valid token + assist level

πŸ’‘ This loop continues as long as the system is powered and correctly emulated.


Firmware Flashing Notes (ESP32)

For flashing firmware onto ESP32 (DevKit, WROOM, or C3):

Option 1: Arduino IDE

  • Use ESP32 board manager from Espressif
  • Select the right board (e.g., ESP32 Dev Module or ESP32C3 Dev Module)
  • Upload via USB

Option 2: PlatformIO (VSCode)

  • Create platformio.ini with appropriate board
  • Use built-in terminal to build/flash
  • Example config:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200

Frequently Asked Questions (FAQ)

Q: Why doesn’t the motor engage even after startup? A: You may be missing a valid handshake or assist level response. Also verify the serial number logic if using CU3.

Q: Do I need to emulate both display and battery? A: In some cases, yes β€” especially if the motor expects full traffic and assist commands from the display.

Q: Can I use USB UART adapter instead of ESP32? A: For sniffing/logging β€” yes. For real-time emulation β€” no, you need something programmable like ESP32.

Q: My bike turns off after 5 seconds β€” what now? A: It may expect continuous alive pings or motor-side acknowledgment. Check for byte 0x00 rotations.


Community & Support

Join the ongoing conversation, ask questions, or contribute your findings:

If there's interest, a Discord or Matrix room could be started!

Glossary

Term Definition
BOW Battery On-Wire; the UART-based communication protocol used in ION systems
CU2/CU3 Types of ION displays (CU2 = round, CU3 = rectangular)
ESP32 Microcontroller used for emulation and logging
BMS Battery Management System controlling charge, discharge, and safety
UART Universal Asynchronous Receiver-Transmitter (serial communication)
PMU1/2 Battery models used in older/newer ION systems (NiMH vs. Li-Ion)

Versioning

Last updated: April 9, 2025


Suggested Tools and Repos


License

This documentation is released under the Creative Commons Attribution 4.0 International (CC BY 4.0) license. You are free to share and adapt the material, as long as appropriate credit is given.


Current Progress

  • Partial emulation of display-battery communication is working.
  • Display responds to button input and updates assist level.
  • Motor provides speed feedback but does not engage support.
  • Handshake logic between display and motor is likely not fully reproduced.
  • ESP32-based emulator developed for testing.

Known Issues & Challenges

  • Motor may require cryptographic validation of messages.
  • Lack of manufacturer software makes configuration difficult.
  • Display serial number appears to be verified by the motor.
  • Potentially unique keys per device chain (Display ↔ Battery ↔ Motor).
  • CU2 vs CU3 display compatibility dependent on battery firmware.

Resources & References

  • GitHub repos from Infant, Thi3rryzz, and stancecoke
  • Pedelec-Forum thread: "Zweiter FrΓΌhling fΓΌr ION-Antrieb"
  • Python scripts for decoding UART logs
  • EEPROM and microcontroller fuse analysis
  • Logs from multiple bike setups and conditions

Contributing

Please join the effort! Share logs, reverse-engineering tools, and insights.

  • Fork and clone the GitHub repo.
  • Submit logs from working ION systems.
  • Help decode unknown messages.
  • Test emulator setups.

Contributors

  • mooiweertje β€” documentation review, insights, and testing support
  • hochsitzcola β€” extensive logging, protocol analysis, ESP32 firmware
  • Mike747 β€” hardware testing and community feedback
  • InfantEudora β€” original sparta_ion repository and reverse-engineering insights
  • Thi3rryzz β€” GitHub contributions and refinement
  • void-spark β€” Python log decoders, CU3 compatibility tests
  • TyraMisoux β€” deep technical insights into AVR bootloaders and system security
  • Everyone on the Pedelec-Forum who shared logs, ideas, and support

This documentation is an evolving community effort. Contributions, corrections, and new discoveries are welcome!