J2534 / CANbus Protocol Reference

Targeting: Adafruit Feather M4 CAN Express (SAME51) — for building a Pass-Thru style read/write .bin interface.

Contents
  1. Hardware — Feather M4 CAN Express
  2. CAN Bus Basics
  3. Arduino CAN Setup & Code
  4. J2534 Pass-Thru Protocol
  5. J2534 API Functions
  6. PASSTHRU_MSG Structure
  7. Error Codes
  8. Supported Protocols & Baud Rates
  9. UDS Services for Read/Write .bin
  10. Connection & Flash Flow
  11. Mapping J2534 API to M4 Feather
  12. Sources

1. Hardware — Feather M4 CAN Express

Specs

  • MCU: ATSAME51J19A — 120 MHz Cortex-M4F
  • Flash: 512 KB
  • RAM: 192 KB
  • CAN Controller: Built-in (SAME51 native CAN peripheral)
  • Transceiver: On-board CAN transceiver + 5V boost
  • Connector: 3-pin 3.5mm terminal block (CANH, CANL, GND)
  • Adafruit Product: #4759

Pin Setup

  • PIN_CAN_STANDBY → set LOW (wake transceiver)
  • PIN_CAN_BOOSTEN → set HIGH (enable 5V boost)
  • Wire: H↔H, L↔L between nodes
  • GND connection optional but recommended
  • 120Ω termination resistor at each end of bus

2. CAN Bus Basics

PropertyValue
Physical LayerDifferential pair (CANH / CANL), ISO 11898
Standard ID11-bit (CAN 2.0A)
Extended ID29-bit (CAN 2.0B)
Max Data Length8 bytes per frame (classic CAN)
Common Baud Rates125, 250, 500 kbps, 1 Mbps
Bus ArbitrationNon-destructive, priority by ID (lower wins)
Termination120Ω at each end of bus

CAN Frame Structure

┌─────────┬────────┬─────┬───────────────┬─────┬─────┬─────────┐
│  SOF    │  ID    │ RTR │  DLC (0-8)    │DATA │ CRC │ ACK/EOF │
│ 1 bit   │11/29b  │1 bit│  4 bits       │0-8B │15b  │         │
└─────────┴────────┴─────┴───────────────┴─────┴─────┴─────────┘

3. Arduino CAN Setup & Code

Library

Install "Adafruit CAN" (CANSAME5x) via Arduino Library Manager. Board selection: Feather M4 CAN (SAME51).

Sender Example

#include <CANSAME5x.h>

CANSAME5x CAN;

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);

  pinMode(PIN_CAN_STANDBY, OUTPUT);
  digitalWrite(PIN_CAN_STANDBY, false);  // transceiver out of standby
  pinMode(PIN_CAN_BOOSTEN, OUTPUT);
  digitalWrite(PIN_CAN_BOOSTEN, true);   // enable 5V boost

  if (!CAN.begin(250000)) {              // 250 kbps — must match all nodes
    Serial.println("CAN init failed!");
    while (1) delay(10);
  }
  Serial.println("CAN TX ready");
}

void loop() {
  // Send a standard 11-bit ID packet
  CAN.beginPacket(0x12);        // CAN ID = 0x12
  CAN.write('H');
  CAN.write('i');
  CAN.endPacket();

  delay(100);
}

Receiver Example

#include <CANSAME5x.h>

CANSAME5x CAN;

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);

  pinMode(PIN_CAN_STANDBY, OUTPUT);
  digitalWrite(PIN_CAN_STANDBY, false);
  pinMode(PIN_CAN_BOOSTEN, OUTPUT);
  digitalWrite(PIN_CAN_BOOSTEN, true);

  if (!CAN.begin(250000)) {
    Serial.println("CAN init failed!");
    while (1) delay(10);
  }
  Serial.println("CAN RX ready");
}

void loop() {
  int packetSize = CAN.parsePacket();
  if (packetSize) {
    Serial.print("ID: 0x");
    Serial.print(CAN.packetId(), HEX);
    Serial.print("  DLC: ");
    Serial.print(packetSize);
    Serial.print("  Data: ");
    while (CAN.available()) {
      Serial.print((char)CAN.read());
    }
    Serial.println();
  }
}
Important: All nodes on the bus must use the same baud rate. 250 kbps is the recommended default for the Feather M4 CAN.

4. J2534 Pass-Thru Protocol Overview

SAE J2534 (Pass-Thru) is a standardized API that lets a PC application communicate with vehicle ECUs through a compliant hardware interface. Originally mandated for emissions-related ECU reprogramming, it now covers general diagnostics.

Key Concepts

Architecture

┌──────────────┐     USB      ┌─────────────────┐    OBD-II    ┌───────┐
│  PC / OEM    │ ◄──────────► │  J2534 Device    │ ◄──────────► │  ECU  │
│  Application │   J2534 DLL  │  (Pass-Thru HW)  │   CAN bus   │       │
└──────────────┘              └─────────────────┘              └───────┘

5. J2534 API Functions

FunctionPurpose
PassThruOpenOpen connection to J2534 device; returns DeviceID
PassThruCloseClose connection to device
PassThruConnectOpen a protocol channel (CAN, ISO15765, etc.); returns ChannelID
PassThruDisconnectClose protocol channel
PassThruReadMsgsRead messages from receive buffer
PassThruWriteMsgsSend messages to vehicle network
PassThruStartMsgFilterSet pass/block/flow-control filter
PassThruStopMsgFilterRemove a message filter
PassThruStartPeriodicMsgQueue a message for periodic transmission
PassThruStopPeriodicMsgStop a periodic message
PassThruIoctlGet/set config params, clear buffers, init protocols
PassThruSetProgrammingVoltageSet voltage on pin 15 (for flash programming)
PassThruReadVersionRead firmware/DLL/API version strings
PassThruGetLastErrorGet human-readable error description

Function Prototypes

long PassThruOpen(void *pName, unsigned long *pDeviceID);
long PassThruClose(unsigned long DeviceID);

long PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID,
                     unsigned long Flags, unsigned long BaudRate,
                     unsigned long *pChannelID);
long PassThruDisconnect(unsigned long ChannelID);

long PassThruReadMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg,
                      unsigned long *pNumMsgs, unsigned long Timeout);

long PassThruWriteMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg,
                       unsigned long *pNumMsgs, unsigned long Timeout);

long PassThruStartMsgFilter(unsigned long ChannelID, unsigned long FilterType,
                            PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
                            PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID);

long PassThruIoctl(unsigned long ChannelID, unsigned long IoctlID,
                   void *pInput, void *pOutput);

6. PASSTHRU_MSG Structure

typedef struct {
    unsigned long ProtocolID;       // Protocol for this message
    unsigned long RxStatus;         // Receive status flags
    unsigned long TxFlags;          // Transmit option flags
    unsigned long Timestamp;        // Timestamp in microseconds
    unsigned long DataSize;         // Number of bytes in Data[]
    unsigned long ExtraDataIndex;   // Start of extra data (e.g. CRC)
    unsigned char Data[4128];       // Message payload
} PASSTHRU_MSG;

Protocol IDs

IDProtocolNotes
0x01J1850VPWVariable Pulse Width
0x02J1850PWMPulse Width Modulation
0x03ISO9141Slow init K-line
0x04ISO14230 (KWP2000)K-line fast/slow init
0x05CANRaw CAN frames
0x06ISO15765CAN transport layer (needed for UDS/flash)

TX Flags

FlagValueMeaning
CAN_29BIT_ID0x00000100Use 29-bit extended CAN ID
ISO15765_FRAME_PAD0x00000040Pad ISO15765 frames to 8 bytes
WAIT_P3_MIN_ONLY0x00000200Override P3 timing

RX Status Flags

FlagValueMeaning
TX_MSG_TYPE0x0001Echo of transmitted message
START_OF_MESSAGE0x0002First-frame indication
RX_BREAK0x0004Break received
TX_INDICATION0x0008Tx complete indication
ISO15765_PADDING_ERROR0x0010Padding error detected
ISO15765_ADDR_TYPE0x0080Extended addressing

7. Error Codes

CodeNameMeaning
0x00STATUS_NOERRORSuccess
0x01ERR_NOT_SUPPORTEDFunction not supported by device
0x02ERR_INVALID_CHANNEL_IDBad channel identifier
0x03ERR_INVALID_PROTOCOL_IDUnrecognized protocol
0x04ERR_NULL_PARAMETERNull pointer passed
0x05ERR_INVALID_IOCTL_VALUEInvalid config parameter
0x06ERR_INVALID_FLAGSInvalid flags in message
0x07ERR_FAILEDUnspecified error
0x08ERR_DEVICE_NOT_CONNECTEDDevice disconnected
0x09ERR_TIMEOUTTimeout expired
0x0AERR_INVALID_MSGMessage violates constraints
0x0BERR_INVALID_TIME_INTERVALTime value out of range
0x0CERR_EXCEEDED_LIMITFilter/periodic limit exceeded
0x0DERR_INVALID_MSG_IDUnknown message handle
0x0EERR_DEVICE_IN_USEDevice already opened
0x0FERR_INVALID_IOCTL_IDUnknown ioctl command
0x10ERR_BUFFER_EMPTYNo messages to read
0x11ERR_BUFFER_FULLTransmit queue full
0x12ERR_BUFFER_OVERFLOWReceive buffer overflow
0x13ERR_PIN_INVALIDUnknown or in-use pin
0x14ERR_CHANNEL_IN_USEProtocol channel occupied
0x15ERR_MSG_PROTOCOL_IDMessage protocol mismatch
0x16ERR_INVALID_FILTER_IDUnknown filter handle
0x17ERR_NO_FLOW_CONTROLMissing flow control filter
0x18ERR_NOT_UNIQUEDuplicate filter pattern
0x19ERR_INVALID_BAUDRATERequested baud rate not achievable
0x1AERR_INVALID_DEVICE_IDUnknown device handle

8. Supported Protocols & Baud Rates

J2534-1 (Mandatory)

ProtocolBaud Rates
CAN (ISO 11898)125, 250, 500 kbps; 11-bit & 29-bit IDs
ISO 15765 (CAN transport)Same as CAN — adds segmentation & flow control
ISO 9141-210400 baud (±0.5%), plus 4800–19200 range
ISO 14230-4 (KWP2000)Same range as ISO 9141
J1850 VPW10.4 kbps (high-speed 41.6 kbps)
J1850 PWM41.6 kbps (high-speed 83.3 kbps)
SAE J2610DaimlerChrysler SCI

J2534-2 (Optional Extensions)

For M4 Feather CAN: The SAME51 supports classic CAN at 62.5, 125, 250, 500 kbps and 1 Mbps. OBD-II / automotive standard is typically 500 kbps for CAN, though some vehicles use 250 kbps.

9. UDS Services for Read/Write .bin Files

UDS (Unified Diagnostic Services — ISO 14229) runs on top of ISO 15765 (CAN transport layer). These are the services you need for reading/writing binary firmware to/from ECUs.

Session & Security (Required Before Flashing)

SIDServicePurpose
0x10DiagnosticSessionControlSwitch to Programming Session (sub-function 0x02)
0x27SecurityAccessSeed/Key authentication to unlock ECU
0x3ETesterPresentKeep session alive (send periodically)
0x11ECUResetReset ECU after flashing

Upload / Download Services (The Core for .bin R/W)

SIDServiceDirectionPurpose
0x34RequestDownloadPC → ECUInitiate writing .bin data TO the ECU. Specifies memory address & size.
0x35RequestUploadECU → PCInitiate reading .bin data FROM the ECU. Specifies memory address & size.
0x36TransferDataBothTransfer data blocks (chunked). Block counter increments each call.
0x37RequestTransferExitSignal transfer complete. ECU verifies integrity.

Memory Erase (Often Needed Before Write)

SIDServicePurpose
0x31RoutineControlStart/stop routines — commonly used to erase flash memory before writing

UDS Negative Response Codes (Flash-Related)

NRCNameMeaning
0x13incorrectMessageLengthOrInvalidFormatBad request format
0x31requestOutOfRangeAddress/size outside valid range
0x33securityAccessDeniedNot authenticated
0x72generalProgrammingFailureFlash erase/program failed
0x73wrongBlockSequenceCounterTransferData block number mismatch
0x78requestCorrectlyReceivedResponsePendingECU busy, wait for response

10. Connection & Flash Flow

J2534 Initialization Sequence

1. PassThruOpen()                          → get DeviceID
2. PassThruConnect(DeviceID,
       ISO15765,                           // ProtocolID = 0x06
       0,                                  // Flags (0 = 11-bit CAN ID)
       500000,                             // Baud rate
       &channelID)                         → get ChannelID
3. PassThruStartMsgFilter(channelID,
       FLOW_CONTROL_FILTER,                // FilterType
       &maskMsg,                           // Mask: which bits to check
       &patternMsg,                        // Pattern: ECU response ID (e.g. 0x7E8)
       &flowControlMsg,                    // Flow control: tester ID (e.g. 0x7E0)
       &filterID)
4. PassThruIoctl(SET_CONFIG, ...)          → set timing params (P1–P4, etc.)

Write .bin to ECU (Download)

1. UDS 0x10 0x02          → Enter Programming Session
2. UDS 0x27 0x01          → SecurityAccess: request seed
3. UDS 0x27 0x02 [key]    → SecurityAccess: send key
4. UDS 0x31 [erase]       → RoutineControl: erase flash region
5. UDS 0x34 [addr][size]  → RequestDownload: specify address & total size
                             Response contains max block length
6. Loop:
   UDS 0x36 [blockN][data]→ TransferData: send .bin in chunks
7. UDS 0x37               → RequestTransferExit
8. UDS 0x11 0x01          → ECUReset (hard reset)

Read .bin from ECU (Upload)

1. UDS 0x10 0x02          → Enter Programming Session
2. UDS 0x27 0x01/0x02     → SecurityAccess (seed/key)
3. UDS 0x35 [addr][size]  → RequestUpload: specify address & size
                             Response contains max block length
4. Loop:
   UDS 0x36 [blockN]      → TransferData: receive .bin chunks
   Save chunks to file
5. UDS 0x37               → RequestTransferExit
6. UDS 0x11 0x01          → ECUReset

11. Mapping J2534 API → M4 Feather CAN

The Feather M4 CAN isn't a J2534 device, but you can implement the equivalent functionality on it. Here's the mapping:

J2534 ConceptM4 Feather Equivalent
PassThruOpenCAN.begin(baudRate) + pin setup
PassThruConnect (ISO15765)Use CAN.begin() + implement ISO-TP framing in software
PassThruReadMsgsCAN.parsePacket() + CAN.read()
PassThruWriteMsgsCAN.beginPacket(id) / CAN.write() / CAN.endPacket()
PassThruStartMsgFilterSoftware filter on CAN.packetId(), or use SAME51 hardware filters
PassThruIoctlTiming managed in firmware (millis/micros)
ISO 15765 transport layerMust implement manually: Single Frame / First Frame / Consecutive Frame / Flow Control
UDS service layerMust implement manually: Build/parse UDS request/response bytes
PC ↔ Feather linkUSB Serial — send commands / receive data from a PC-side script
Key requirement for .bin read/write: You need to implement ISO 15765-2 (ISO-TP) on top of raw CAN. This handles segmentation of messages larger than 8 bytes — essential since UDS flash transfers send/receive blocks of up to ~4 KB at a time. The CANSAME5x library gives you raw CAN frames only.

ISO-TP Frame Types (ISO 15765-2)

TypeNibblePurpose
Single Frame (SF)0x0Message fits in one CAN frame (≤7 bytes)
First Frame (FF)0x1First segment of multi-frame message; contains total length
Consecutive Frame (CF)0x2Subsequent segments; sequence number 0–F
Flow Control (FC)0x3Receiver tells sender: continue / wait / abort

Minimal Implementation Checklist

  1. CAN driver init (CANSAME5x at 500 kbps for OBD-II)
  2. ISO-TP layer: assemble/disassemble multi-frame messages
  3. UDS request builder: construct SID + sub-function + data bytes
  4. UDS response parser: handle positive responses, NRCs, and 0x78 pending
  5. Serial command interface: PC sends commands like READ addr size / WRITE addr file.bin
  6. File transfer over serial: chunked binary transfer between PC and Feather

12. Sources


Reference compiled March 2026. SAE J2534 v04.04 specification. For official details, obtain the full SAE standard document.