Chris Collins

Tools · embedded

Modbus and CAN bus workbench

Build and decode Modbus RTU, ASCII, and TCP frames, decode registers in every word order, draw CAN bit streams with stuff bits and CRC-15, calculate MCP2515, ESP32 TWAI, STM32, and SJA1000 bit timing, estimate bus load, and decode DBC signals, candump logs, OBD-II PIDs, and J1939 IDs.

Added · updated 28 October 2026

Works with

How to use it

Modbus

Modbus frames builds a request once and shows it in all three framings. RTU adds a CRC-16 sent low byte first. ASCII is : followed by hex, then an LRC (the two’s complement of the byte sum) and CR LF. TCP puts a 7-byte MBAP header in front (transaction id, protocol 0, length, unit id) and has no checksum. The RTU timing line gives the frame time and the 3.5-character silent gap, which is fixed at 1.75 ms above 19200 baud. Paste any frame into the decoder. It detects the framing, checks the CRC, LRC, or MBAP length, and decodes functions 1–6, 8, 15, 16, 22, 23, and 43/14 (device identification). It also explains exception responses. For a plain RTU CRC, use the CRC tool.

Registers shows a block of 16-bit registers as every common type under all four word/byte orders. ABCD is big-endian, the Modbus default. CDAB swaps the words, which many PLCs and energy meters do. BADC swaps the bytes inside each register, and DCBA is fully little-endian. Turn on "start a value at every register" to find a value that is off by one register. The register map turns a response into named, scaled values. Write one line per register: address (0-based, or a 40001-style reference), name, type, scale, unit, and an optional order. The encoder turns a number into the registers to write.

CAN

CAN frame draws the whole classic frame, bit by bit. Stuff bits are highlighted, and a logic trace runs underneath. It also gives the CRC-15 (polynomial 0x4599, computed over SOF to the end of the data before stuffing), the frame length, and the time on the wire. The default frame is the published example (ID 0x014, one data byte 0x01, CRC 0x7753, three stuff bits) from Ken Tindell’s oscilloscope capture, which is used on Wikipedia. The CAN-FD table maps DLC 9–15 to 12–64 bytes. Its frame times are estimates that leave out dynamic stuff bits.

Bit timing lists every prescaler and segment split that gives the bit rate from your controller’s clock. The list is ranked by rate error, then by distance from the target sample point (87.5 % is the CiA recommendation for CANopen), then by more time quanta per bit. Click a row to get register values for that controller:

  • MCP2515: CNF1–3, with TQ = 2·(BRP+1)/Fosc.

  • ESP32 TWAI: a twai_timing_config_t initialiser.

  • STM32 bxCAN: the BTR value and the HAL fields.

  • SJA1000: BTR0 and BTR1.

The decoder works the other way. For example, the MCP2515 values 00 F0 86 at 16 MHz, used by the MCP_CAN Arduino library, are 500 kbit/s with a 56 % sample point and triple sampling.

Bus load totals the bits per second of a message list. A classic frame without stuffing is 47 + 8n bits (11-bit ID) or 67 + 8n bits (29-bit ID), counting the 3-bit interframe space. The worst case adds ⌊(34 + 8n − 1)/4⌋ or ⌊(54 + 8n − 1)/4⌋ stuff bits.

DBC + candump parses BO_, SG_ (Intel and Motorola byte order, signed, factor and offset, units, simple multiplexing), VAL_, and comments. It decodes logs in either candump format: (ts) can0 123#DEADBEEF (candump -l, including ## CAN-FD frames) or can0 123 [4] DE AD BE EF. Pick a signal to plot it over time. Frames that aren’t in the DBC are tried as J1939 or OBD-II.

OBD-II + J1939 decodes mode 01 responses for about 60 common PIDs (formulas from SAE J1979, as listed on Wikipedia’s OBD-II PIDs page) and builds the 0x7DF request. It also splits a 29-bit J1939 identifier into priority, PGN, and source and destination addresses, and decodes a few common SPNs (EEC1 engine speed, ET1 coolant, CCVS speed, and others).

Limits

Modbus decoding guesses whether a frame is a request or a response from its length. You can override the guess. DBC support covers the common subset: extended multiplexing, signal groups, and float signals (SIG_VALTYPE_) are not decoded. The TWAI prescaler range shown is the original ESP32’s. Later chips allow larger even prescalers.

Sharing

Share link copies a URL that opens this tool with your current settings — every value it remembers between visits, packed into ?s=. Opening a link replaces your saved settings for this tool. You can also write a short link by hand with frame (a Modbus frame to decode), for example /tools/modbus-can/?frame=01%2003%2004%2000%2064%2000%20C8%20BA%207A.

Runs entirely in your browser; nothing you type leaves this page.