CAN Family Guide

Overview

The CB family is NAI’s line of CANbus communication modules. Like the serial (SC) and ARINC (AR) families, CB is about digital communication between devices — but CAN has a character all its own: it’s a multi-master, broadcast serial bus. Every node shares one twisted pair, any node may start talking when the bus is idle, and a built-in priority scheme (arbitration on the message ID) decides who wins when two transmit at once. There’s no master polling slaves and no dedicated transmit/receive channels — every message is broadcast to every node, and each node decides which messages it cares about.

This page is the starting point for any CB module. Use it to understand the family, pick the member for the CAN protocol you need, wire the module onto a CAN bus, confirm the channel with a self-test, and read or write your first frames. It’s aimed at engineers connecting an NAI system to a CAN network — receiving sensor/ECU traffic, transmitting commands, or simulating a node for test.

In a real system, CAN is the robust, low-cost device network that ties together the electronic control units (ECUs), sensors, and actuators on a platform — it was born in automotive and is now everywhere reliability matters on a short, noisy bus: ground vehicles and heavy equipment, marine, industrial automation, medical equipment, and increasingly avionics. Concretely, a CB module lets your system listen to an existing CAN network (engine, transmission, brake, and body controllers on a vehicle; smart sensors on a machine), transmit frames to command or query other nodes, or simulate a device that isn’t physically present for integration test. The higher-level protocol layered on top of raw CAN matters as much as the bus itself — which is what separates the family members below. (NAI offers related avionics-bus families as well: AR for ARINC 429/575 and M1553 for MIL-STD-1553.)

For a short visual introduction to the CANbus family, watch this overview:

CB modules at a glance

Every CB module gives you eight independent, galvanically-isolated CAN channels at up to 1 Mbit/s. What differs is the higher-level protocol each one speaks, so choose the module that matches the network your equipment uses:

ModuleChannelsProtocolNotableManual
CB18CAN 2.0 A/B (ISO 11898)MilCAN compliantCB1-3 Manual
CB28SAE J1939Source-address claimingCB1-3 Manual
CB38CAN 2.0 A/B or J1939Protocol selectable per channelCB1-3 Manual
CB88CAN 2.0 A/B + CAN FDARINC 825-4 avionics CAN; ≤4 Mbps FD data phase; programmable terminationCB8 Manual

Choosing a member:

  • Standard CAN 2.0 A/B — the common case, classic 11-bit/29-bit-ID CAN with up to 8 data bytes per frame — CB1 (also MilCAN compliant, so it’s the pick for military CAN deployments).
  • SAE J1939 — the standard on trucks, buses, and heavy/off-road equipment (29-bit IDs, PGN-addressed parameters, transport protocol for payloads larger than 8 bytes) — CB2 (handles source-address claiming).
  • A mix of both on one module — some channels CAN A/B, some J1939, set independently — CB3 (each channel’s protocol is selectable in software).
  • CAN FD, higher bandwidth, or avionics CAN — the CB8 hardware adds CAN FD (larger payloads, data phase up to 4 Mbps), ARINC 825-4 avionics CAN, and software-programmable bus termination. (The standard CAN sample applications drive CB8 in classic CAN 2.0 A/B mode — confirm CAN FD / ARINC 825 API support in your SSK release before designing around it.)

NAI’s SSK sample applications also recognize a CB6 dual-protocol CAN module (CAN A/B or J1939, like CB3); contact the factory for its current availability and documentation. Unless you specifically need J1939, CAN FD, or avionics CAN, CB1 is the appropriate starting point.

Physical setup

CAN is a two-wire differential bus — a single twisted pair (CAN_H / CAN_L) shared by every node on the network. It is multi-drop: nodes tap onto the same pair in a daisy-chain (a “linear bus”), not a star. Two rules dominate the physical layer, and getting them wrong is the most common reason a CAN link won’t work:

  • Termination is required. A 120 Ω resistor must be fitted at each end of the bus (two total) to match the cable impedance and kill reflections. The CB1/CB2/CB3 channels are not internally terminated — you must apply the 120 Ω terminations externally. (CB8 adds programmable termination you can switch on per channel from software.)
  • Every node agrees on one baud rate. All nodes share the bus, so they must all run the same bit rate. Lower rates allow longer cable: ~1 Mbit/s below 40 m, ~125 kbit/s out to ~500 m.

The exact connector pins are per-module, so get them from that module’s manual; the pattern is the same:

  1. Identify the module’s slot number on your NAI motherboard or system.
  2. Bring the channel signals out through the breakout board, where the slot’s pins appear as generic IO# numbers.
  3. Map IO# pins to each channel’s CAN_H / CAN_L pair — by the pinout in the module’s manual or the module’s overlay card.
  4. Wire CAN_H to the bus CAN_H and CAN_L to the bus CAN_L, and make sure the bus has a 120 Ω terminator at both physical ends.

A few things hold for the family:

  • A channel both transmits and receives. Unlike ARINC, a CAN channel is not one-directional — the same channel can send and listen on the bus (it just can’t do both in the same instant). Enable each direction in software.
  • Every frame is broadcast; receivers filter. There’s no point-to-point addressing in raw CAN — every node sees every frame. Each channel has acceptance filters (mask + code, and on CB8 up to 8 maskable ID filters plus first-two-data-byte filtering) so you only process the messages you want.
  • Isolation per channel. Channels are galvanically isolated, which protects against ground-potential differences and fault propagation between networks — useful when one module straddles several buses.

Two worked examples (use your module’s pinout for the actual pins):

  • Join an existing CAN network (e.g. a vehicle or machine bus). Connect one channel’s CAN_H to the bus’s CAN_H and CAN_L to the bus’s CAN_L — you’re tapping in as one more node on the shared pair. The running bus already has its two end terminators, so do not add another. Set that channel to the bus’s baud rate and protocol, enable receive, and the frames already on the bus show up in the channel’s receive FIFO.
  • Two-channel bench loopback (no external bus). With nothing else attached, wire two of the module’s own channels together: channel 1’s CAN_H to channel 2’s CAN_H, and channel 1’s CAN_L to channel 2’s CAN_L — straight across, not crossed (unlike a serial null-modem, CAN’s two wires are not swapped). Fit a 120 Ω resistor across CAN_H/CAN_L at each of the two channels to terminate the short bus. Transmit on channel 1 and receive on channel 2 — this is exactly the self-test in the next section.

Software

There’s nothing CAN-specific about which software you run. The NAI SSK (naibrd library) is identical across every OS and architecture — PetaLinux, VxWorks, DEOS, Windows. What OS you’re on is determined by your motherboard/SBC, not by the CB module. The only family-specific part is which API functions you call: CB modules use the naibrd_CAN_* calls.

Where to find what you need:

  • Which functions/registers to call — the specific module’s manual (e.g. CB1-3 Manual, CB8 Manual) documents the registers behind every naibrd_CAN_* call (bit timing, protocol assignment, transmit/receive enable, FIFOs, filtering, BIT, and status).
  • Building and deploying on your platformConnecting to Boards covers the toolchain, deployment, and terminal access for PetaLinux/ARM Linux, VxWorks, DEOS, and Windows.
  • Launching the app on the board itselfRunning Applications from the Target walks through loading and launching your executable on the target.

Example — a 68ARM2 SBC with a CB3 module: pull the naibrd_CAN_* calls from the CB1-3 Manual, set up the ARM Linux toolchain per Connecting to Boards, then load and launch a CAN sample on the target per Running Applications from the Target.

Confirm communication

CAN gives you an unusually easy first check: Built-In Test (BIT). Each channel runs a self-contained loopback test — the module quietly drops the channel into loopback mode, sends a known frame to itself, verifies it, and returns to normal. No wiring is required, which makes BIT the fastest way to confirm your board connection, the SSK, and the module are all alive.

Power-On BIT runs automatically at power-up. Check it, then optionally run it again on demand:

/* Did the channel pass its power-on self-test? */
naibrd_CAN_CheckBITComplete(cardIndex, module, channel, &bitComplete);
 
/* Run BIT again on demand — returns NAI_SUCCESS on pass */
bitStatus = naibrd_CAN_InitiateBIT(cardIndex, module, channel, NAI_TRUE);

If bitStatus is NAI_SUCCESS, the channel’s transceiver and core are working end-to-end. (While BIT runs, the channel is in loopback and won’t answer real bus traffic for that brief window.)

To go one step further and prove your external wiring, do a two-channel loopback on the bench: jumper channel 1’s CAN_H/CAN_L to channel 2’s (with a 120 Ω terminator at each end), transmit a frame on channel 1, and read it back on channel 2.

Run it:

/* Both channels: same protocol and baud rate */
naibrd_CAN_SetProtocol(cardIndex, module, txChannel, NAIBRD_CAN_PROTOCOL_AB);
naibrd_CAN_SetProtocol(cardIndex, module, rxChannel, NAIBRD_CAN_PROTOCOL_AB);
 
/* Configure receive channel (bit timing + enable Rx), then transmit on the other */
naiapp_Cfg_Rx_CAN(cardIndex, module, rxChannel, baudRate);
naiapp_Cfg_Tx_CAN(cardIndex, module, txChannel, baudRate);
 
naiapp_transmitFIFOChannelData_PGN(cardIndex, module, txChannel, pgn, fifoData, 1);
 
/* Read it back on the receive channel */
naibrd_CAN_GetRxFIFOFrameCount(cardIndex, module, rxChannel, &count);
naiapp_getFIFOChannelData(cardIndex, module, rxChannel, fifoData);

If the frame you sent on the transmit channel comes back on the receive channel, your wiring, termination, and baud rate are all confirmed. The can_basic_ops sample does exactly this — it runs BIT on both channels, then transmits on one and receives on the other.

Features

Each CB operation works per channel through the naibrd_CAN_* API. The blocks below group the calls by what you’re doing, with the SSK 1.x and 2.x signatures side by side. (The 1.x → 2.x rename is visible throughout: Transmit/Receive became AB_Transmit32/AB_Receive32, Transmit_J1939/Receive_J1939 became J1939_Transmit32/J1939_Receive32, SetAddress/GetAddress became J1939_SetAddress/J1939_GetAddress, GetRxFrameCount became GetRxFIFOFrameCount, and nai_can_* enum types became naibrd_can_*.)

Configure a channel

What it does: set the channel’s protocol (CAN 2.0 A/B or J1939), its baud rate (or explicit bit timing), and enable transmit/receive.

Applies to: all CB modules (protocol is selectable per channel on CB3/CB6; fixed on CB1/CB2).

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_CAN_SetProtocol(int32_t cardIndex, int32_t module, int32_t channel, nai_can_protocol_type_t protocol);
nai_status_t naibrd_CAN_SetBaudRate(int32_t cardIndex, int32_t module, int32_t channel, nai_can_baud_rate_type_t baudRate);
nai_status_t naibrd_CAN_SetBitTiming(int32_t cardIndex, int32_t module, int32_t channel, int32_t prescaler, int32_t SJW, int32_t tseg1, int32_t tseg2);
nai_status_t naibrd_CAN_SetTxEnable(int32_t cardIndex, int32_t module, int32_t channel, bool_t enable);
nai_status_t naibrd_CAN_SetRxEnable(int32_t cardIndex, int32_t module, int32_t channel, bool_t enable);
/* SSK 2.x */
nai_status_t naibrd_CAN_SetProtocol(int32_t cardIndex, int32_t module, int32_t channel, naibrd_can_protocol_type_t protocol);
nai_status_t naibrd_CAN_SetBaudRate(int32_t cardIndex, int32_t module, int32_t channel, naibrd_can_baud_rate_type_t baudRate);
nai_status_t naibrd_CAN_SetBitTiming(int32_t cardIndex, int32_t module, int32_t channel, int32_t prescaler, int32_t sjw, int32_t tseg1, int32_t tseg2);
nai_status_t naibrd_CAN_SetTxEnable(int32_t cardIndex, int32_t module, int32_t channel, bool_t enable);
nai_status_t naibrd_CAN_SetRxEnable(int32_t cardIndex, int32_t module, int32_t channel, bool_t enable);

Exercise it: CAN Basic Ops · ESP2 “CB” tab.

Transmit frames

What it does: send CAN frames — a CAN 2.0 A/B frame (message ID + up to 8 data bytes) or a J1939 message (PGN + priority + destination, up to 345 bytes). Queue them into the transmit FIFO.

Applies to: A/B transmit on CB1/CB3/CB6; J1939 transmit on CB2/CB3/CB6.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_CAN_Transmit(int32_t cardIndex, int32_t module, int32_t channel, bool_t ismodeA, int32_t msgid, uint8_t* buffer, int32_t length);
nai_status_t naibrd_CAN_Transmit_J1939(int32_t cardIndex, int32_t module, int32_t channel, int32_t PGN, int32_t priority, int32_t destination, uint8_t* buffer, int32_t length);
nai_status_t naibrd_CAN_GetTxFrameCount(int32_t cardIndex, int32_t module, int32_t channel, int32_t* outcount);
/* SSK 2.x */
nai_status_t naibrd_CAN_AB_Transmit32(int32_t cardIndex, int32_t module, int32_t channel, bool_t isModeA, int32_t msgId, uint32_t* p_buffer, int32_t txCount);
nai_status_t naibrd_CAN_J1939_Transmit32(int32_t cardIndex, int32_t module, int32_t channel, int32_t pgn, int32_t priority, int32_t destination, uint32_t* p_buffer, int32_t txCount);
nai_status_t naibrd_CAN_GetTxFIFOFrameCount(int32_t cardIndex, int32_t module, int32_t channel, int32_t* p_outcount);

Exercise it: CAN Transmit · ESP2 “CB” tab.

Receive frames

What it does: poll the receive FIFO and read frames — A/B (message ID + data) or J1939 (PGN + source/destination + data).

Applies to: A/B receive on CB1/CB3/CB6/CB8; J1939 receive on CB2/CB3/CB6.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_CAN_GetRxFrameCount(int32_t cardIndex, int32_t module, int32_t channel, int32_t* outcount);
nai_status_t naibrd_CAN_Receive(int32_t cardIndex, int32_t module, int32_t channel, int32_t buflen, bool_t* outismodeA, int32_t* outmsgid, uint8_t* outbuffer, int32_t* outlength);
nai_status_t naibrd_CAN_Receive_J1939(int32_t cardIndex, int32_t module, int32_t channel, int32_t buflen, int32_t* outPGN, int32_t* outsource, int32_t* outdestination, uint8_t* outbuffer, int32_t* outlength);
/* SSK 2.x */
nai_status_t naibrd_CAN_GetRxFIFOFrameCount(int32_t cardIndex, int32_t module, int32_t channel, int32_t* p_outcount);
nai_status_t naibrd_CAN_AB_Receive32(int32_t cardIndex, int32_t module, int32_t channel, bool_t* p_outisModeA, int32_t* p_outmsgId, uint32_t bufferLength, uint32_t* p_outbuffer, int32_t* p_outrxCount);
nai_status_t naibrd_CAN_J1939_Receive32(int32_t cardIndex, int32_t module, int32_t channel, int32_t* p_outpgn, int32_t* p_outsource, int32_t* p_outdestination, uint32_t bufferLength, uint32_t* p_outbuffer, int32_t* p_outrxCount);

Exercise it: CAN Receive · ESP2 “CB” tab.

J1939 addressing, BIT & status

What it does: claim/read a J1939 source address, run Built-In Test, and read bus/error status for diagnostics.

Applies to: J1939 addressing on CB2/CB3/CB6; BIT and status on all CB modules.

Relevant APIs:

/* SSK 1.x */
nai_status_t naibrd_CAN_SetAddress(int32_t cardIndex, int32_t module, int32_t channel, int32_t address);
nai_status_t naibrd_CAN_GetAddress(int32_t cardIndex, int32_t module, int32_t channel, int32_t* outaddress, int32_t* outstatus);
nai_status_t naibrd_CAN_InitiateBIT(int32_t cardIndex, int32_t module, int32_t channel, bool_t waitForResult);
nai_status_t naibrd_CAN_CheckBITComplete(int32_t cardIndex, int32_t module, int32_t channel, bool_t* outBitComplete);
nai_status_t naibrd_CAN_GetBusStatus(int32_t cardIndex, int32_t module, int32_t channel, int32_t* outstatus);
nai_status_t naibrd_CAN_GetErrorCount(int32_t cardIndex, int32_t module, int32_t channel, bool_t* outiserrorpassive, int32_t* outrxerrors, int32_t* outtxerrors);
/* SSK 2.x */
nai_status_t naibrd_CAN_J1939_SetAddress(int32_t cardIndex, int32_t module, int32_t channel, int32_t address);
nai_status_t naibrd_CAN_J1939_GetAddress(int32_t cardIndex, int32_t module, int32_t channel, int32_t* p_outaddress, int32_t* p_outstatus);
nai_status_t naibrd_CAN_InitiateBIT(int32_t cardIndex, int32_t module, int32_t channel, bool_t waitForResult);
nai_status_t naibrd_CAN_CheckBITComplete(int32_t cardIndex, int32_t module, int32_t channel, bool_t* p_outbitComplete);
nai_status_t naibrd_CAN_GetBusStatus(int32_t cardIndex, int32_t module, int32_t channel, int32_t* p_outstatus);
nai_status_t naibrd_CAN_GetErrorCount(int32_t cardIndex, int32_t module, int32_t channel, bool_t* p_outisErrorPassive, int32_t* p_outrxErrorCount, int32_t* p_outtxErrorCount);

Exercise it: CAN Basic Ops (BIT + address claim) · CAN Interrupt (SSK 1.x).

Try it out

Every NAI sample starts with the standard connection flow — naiapp_RunBoardMenu() opens or loads a board connection, then naiapp_query_CardIndex() and naiapp_query_ModuleNumber() pick the board and module slot, giving you the cardIndex / module / channel coordinates every naibrd_CAN_* call takes. The app then confirms the slot really holds a CAN module with naibrd_CAN_GetChannelCount() (it returns 0 for non-CAN modules). When you write your own program, you do the same — see Opening a Software Handle to Your Board.

Set the protocol and baud rate first — pick the protocol (skip on fixed-protocol CB1/CB2; required per channel on CB3), then the bus speed. Supported rates are 250 K / 500 K / 1 Mbaud for CAN A/B, and 250 K (standard) or 500 K for J1939.

Transmitting a channel — configure it, enable transmit, then send a frame. CAN A/B carries a message ID + up to 8 data bytes; J1939 is addressed by a PGN (Parameter Group Number) and carries 8–345 bytes:

/* SSK 1.x */
naibrd_CAN_SetProtocol(cardIndex, module, channel, NAI_CAN_PROTOCOL_AB);
naibrd_CAN_SetBaudRate(cardIndex, module, channel, NAI_CAN_500K_BAUD);
naibrd_CAN_SetTxEnable(cardIndex, module, channel, NAI_TRUE);
naibrd_CAN_Transmit(cardIndex, module, channel, isModeA, msgId, txData, length);   /* or naibrd_CAN_Transmit_J1939(...) */
/* SSK 2.x */
naibrd_CAN_SetProtocol(cardIndex, module, channel, NAIBRD_CAN_PROTOCOL_AB);
naibrd_CAN_SetBaudRate(cardIndex, module, channel, NAIBRD_CAN_500K_BAUD);
naibrd_CAN_SetTxEnable(cardIndex, module, channel, NAI_TRUE);
naibrd_CAN_AB_Transmit32(cardIndex, module, channel, isModeA, msgId, txData, txCount);   /* or naibrd_CAN_J1939_Transmit32(...) */

Receiving a channel — enable receive, then poll the FIFO frame count and read whatever frames have arrived:

/* SSK 1.x */
naibrd_CAN_SetRxEnable(cardIndex, module, channel, NAI_TRUE);
naibrd_CAN_GetRxFrameCount(cardIndex, module, channel, &count);
naibrd_CAN_Receive(cardIndex, module, channel, buflen, &isModeA, &msgId, rxData, &length);   /* or naibrd_CAN_Receive_J1939(...) */
/* SSK 2.x */
naibrd_CAN_SetRxEnable(cardIndex, module, channel, NAI_TRUE);
naibrd_CAN_GetRxFIFOFrameCount(cardIndex, module, channel, &count);
naibrd_CAN_AB_Receive32(cardIndex, module, channel, &isModeA, &msgId, bufferLength, rxData, &rxCount);   /* or naibrd_CAN_J1939_Receive32(...) */

This is a polling model — frames pile up in the hardware FIFO between reads. For event-driven reception, use an interrupt-based CAN sample. (The SSK sample apps wrap this FIFO data movement in naiapp_* helper functions, but the underlying calls are the naibrd_CAN_* ones shown here.)

J1939 note: before a J1939 channel can talk, it must claim a source address — set it (naibrd_CAN_SetAddress in 1.x / naibrd_CAN_J1939_SetAddress in 2.x) and poll until the claim succeeds (naibrd_CAN_GetAddress / naibrd_CAN_J1939_GetAddress). Claiming needs at least one other J1939 node active on the bus, so enable your receive channels before claiming on the transmit channel.

Run it: CAN Transmit (SSK 2.x) · CAN Receive (SSK 2.x) · CAN Basic Ops (SSK 2.x); SSK 1.x equivalents include CAN Transmit, CAN Receive, CAN Interactive, and the interrupt-driven CAN Interrupt. For the full set and how to build/run them, see the sample-application guides: Using NAI SSK 2.x Sample Applications · Using NAI SSK 1.x Sample Applications.

Hardware capabilities and status monitoring

This section covers what the CB hardware provides and what you can monitor — for how to drive configure/transmit/receive/addressing (with the 1.x/2.x APIs), see Features above.

Hardware capabilities. Each channel backs those operations with independent Tx and Rx FIFOs (configurable almost-full / almost-empty and high/low watermarks for pacing and overrun avoidance) and hardware acceptance filtering (mask + code; CB8 adds up to 8 maskable ID filters per channel plus first-two-data-byte filtering), with continuous background BIT running transparently. CB8 additionally provides CAN FD, ARINC 825-4, and programmable termination at the hardware level (larger payloads, data phase up to 4 Mbps, avionics CAN) — the documented CAN samples drive CB8 in classic CAN 2.0 A/B, so confirm CAN FD / ARINC 825 API support in your SSK release before relying on it.

Statuses you can monitor programmatically. CAN’s status is communication- and bus-health-oriented:

StatusWhat it tells youWhere
Rx data availableFrames are waiting in a channel’s receive FIFOnaibrd_CAN_GetRxFIFOFrameCount; FIFO Status register (Rx Almost Full / watermarks)
Bus error typeWhich CAN error occurred — CRC, form, stuff, bit, or ACK errorBus Status register (NAI_CAN_ERROR_*: CRC/FORM/STUFF/BIT1/ACK)
Core / bus stateError-active, error-passive, or Bus-Off; bus busy/idle; normal vs config/loopbackCore Status register (ESTAT bits, ERRWRN warning ≥ 96)
Error countersLive transmit/receive error counts and whether the channel has gone error-passiveTransmit/Receive Error Counter register (TEC/REC)
Dropped framesCount of received frames discarded because the Rx FIFO was fullDrop Count register
BIT resultPer-channel power-on / initiated self-test pass/failnaibrd_CAN_CheckBITComplete, naibrd_CAN_InitiateBIT

A channel that accumulates too many errors transitions to Bus-Off and stops communicating; a channel reset initiates the CAN recovery sequence (it waits for 129 occurrences of bus-idle before resuming). ESP2’s status panel shows CAN status interactively if you’d rather watch it in a GUI first.

Common pitfalls

  • Missing or wrong termination. The #1 CAN problem. The bus needs exactly two 120 Ω terminators, one at each physical end — no more, no fewer. Too few causes reflections and errors; too many over-loads the bus. CB1/2/3 have no internal termination (add it externally); CB8’s termination is programmable.
  • Baud-rate mismatch. Every node on the bus must run the same rate. A mismatch yields no usable data and can drive the channel into an error state. Set it via the bit-timing configuration.
  • Protocol mismatch. A J1939 node and a plain CAN A/B node on the same bus won’t understand each other’s framing. Match the protocol end-to-end — and don’t ask a CB1 (CAN A/B only) to speak J1939, or a CB2 (J1939 only) to speak raw CAN A/B. Use CB3 when you need both.
  • J1939 address claim fails. Claiming needs at least one other J1939 node on the bus, a unique address (watch the reserved/dynamic ranges), and TX + RX enabled while claiming. Enable receive channels before claiming on the transmit channel.
  • FIFO overflow with polling. In the polling model, frames arriving faster than you read them fill the Rx FIFO and then get dropped (watch the Drop Count). Poll more often, raise the threshold, or switch to interrupt-driven reception.
  • Adding a terminator when tapping a live bus. When you join an existing, already-terminated bus as another drop, don’t add a third terminator — the running bus already has its two.
  • Forgetting the channel is shared/broadcast. There are no private channels on CAN — every node sees every frame. Use acceptance filters to keep only the IDs you care about rather than processing the whole bus.