Skip to main content

CAN Bus

The CAN (Controller Area Network) interface provides robust communication for automotive and industrial applications. Supports standard and extended CAN IDs with configurable filtering and optional 120Ω termination resistors.

TIP

As described in the introduction, industrial communication interfaces share GPIOs, meaning only one feature can be enabled at a given time: Either regular GPIOs, or one of the industrial communication interfaces.

CAN shares pins with RS485_0

The CAN bus and RS485_0 share the same GPIO pins for communication. Therefore, only one of these interfaces can be enabled at a time.

When enabling either the CAN bus or RS485_0, the shared GPIO pins will be automatically configured for the selected interface.

User friendly multiplexing!

In order to avoid any confusion, we recommend following this standard procedure when using an industrial communication port:

  1. Start by enabling the port
  2. Disable the port when done using it.

If there are any conflicts (e.g. enabling an interface before disabling another one that uses the same resources), an error will be raised during the configure() phase, allowing you to easily detect and correct any conflicts.

Quick Start

The CAN bus supports enabling/disabling, termination resistance, setting message acceptance filters, transmitting, and receiving data.

import AT1000 from '@ikalogic/at1000';
let testers = await AT1000.findDevices(500); // Find the device with serial number 12345
let tester = testers[0]; // Target the first detected device
let can = tester.com.can(0); // Access CAN bus 0 on AT1000
// Enable CAN bus on AT1000
let can_cfg_result = await can.configure(
{
baud_rate:500000,
enabled : true,
termination_resistors:true,
rx_filters:[{
mask:0xFF9F,
filter:0x25A,
extended_id: false
}]
});

// Start receiving CAN messages
await can.start_rx(); // Updated to use the 'can' variable

// Transmit a CAN message
await can.tx({can_id:0x123, data:[0x11, 0x22, 0x33, 0x44]});

//add delay of 100ms
await new Promise(resolve => setTimeout(resolve, 100));

// Receive messages (returns an array of objects containing ID & data)
let data_rx = await can.rx();

// Print received messages
data_rx.forEach(msg => {
console.log(`CAN Message ID: ${msg.id}, Data: ${msg.data}`);
});

// Disable CAN bus receiving
await can.stop_rx();

API Reference

Accessing CAN

const can = tester.com.can(id);

Parameters:

  • id (number): The CAN interface identifier (0-based index)

Returns: Can instance


Methods

configure(config)

Configures the CAN interface parameters without changing the enabled state.

await can.configure({ 
baud_rate: 500000,
termination_resistors: true,
rx_filter: {
extended_id: false,
id: 0x100,
mask: 0x7FF
}
});

Parameters:

  • config (CanConfigPatch): Configuration object with optional properties:
    • enabled (boolean, optional): Enable or disable the interface
    • baud_rate (number, optional): CAN baud rate (see valid values below)
    • termination_resistors (boolean, optional): Enable/disable 120Ω termination resistors
    • rx_filter (object, optional): Receive filter configuration:
      • extended_id (boolean): Use extended (29-bit) or standard (11-bit) IDs
      • id (number): Filter ID value
      • mask (number): Filter mask (0 = don't care, 1 = must match)

Valid baud rates: 5000, 10000, 20000, 31250, 33000, 40000, 50000, 80000, 83300, 95000, 100000, 125000, 200000, 250000, 500000, 1000000

Returns: Promise<CanConfig> - The updated configuration

Exceptions:

  • Throws validation error if baud_rate is not one of the valid values
  • Throws validation error if parameters don't match expected types

enable([config])

Enables the CAN interface and optionally applies configuration.

await can.enable({ 
baud_rate: 250000,
termination_resistors: true
});

Parameters:

  • config (CanEnableConfig, optional): Optional configuration to apply:
    • baud_rate (number, optional): CAN baud rate (see valid values above)
    • termination_resistors (boolean, optional): Enable/disable termination resistors
    • rx_filter (object, optional): Receive filter configuration

Returns: Promise<CanConfig> - The updated configuration with enabled: true

Exceptions:

  • Throws validation error if baud_rate is not one of the valid values

disable()

Disables the CAN interface.

await can.disable();

Returns: Promise<CanConfig> - The updated configuration with enabled: false


tx(data)

Transmits a CAN frame.

// Send standard CAN frame
await can.tx({
can_id: 0x123,
data: [0x01, 0x02, 0x03, 0x04]
});

// Send frame with 8 bytes (maximum)
await can.tx({
can_id: 0x456,
data: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]
});

Parameters:

  • data (CanFrame): CAN frame to transmit:
    • can_id (number): CAN identifier (11-bit: 0-0x7FF, 29-bit: 0-0x1FFFFFFF)
    • data (number[]): Data bytes (0 to 8 bytes, each 0-255)

Returns: Promise<CanFrame> - The transmitted frame

Exceptions:

  • Throws validation error if data array length is not between 0 and 8
  • Throws validation error if any byte value is outside the range [0, 255]

start_rx()

Starts buffering received CAN frames.

await can.start_rx();

Returns: Promise<void>

Note: Frames matching the configured filter will be buffered and can be retrieved using rx().


stop_rx()

Stops buffering received CAN frames.

await can.stop_rx();

Returns: Promise<void>


rx()

Reads all buffered CAN frames received since start_rx() was called.

const frames = await can.rx();
for (const frame of frames) {
console.log(`ID: 0x${frame.can_id.toString(16)}, Data:`, frame.data);
}

Returns: Promise<CanFrame[]> - Array of received CAN frames

Note: This method returns all frames accumulated since the last start_rx() call and clears the buffer.


Types

CanConfig

Complete configuration object returned by configuration methods.

{
enabled: boolean,
baud_rate: number, // Valid baud rate from list
termination_resistors: boolean,
rx_filter: {
extended_id: boolean,
id: number,
mask: number
}
}

CanConfigPatch

Partial configuration for the configure() method. All properties are optional.

{
enabled?: boolean,
baud_rate?: number, // Valid baud rate from list
termination_resistors?: boolean,
rx_filter?: {
extended_id: boolean,
id: number,
mask: number
}
}

CanEnableConfig

Optional configuration for the enable() method.

{
baud_rate?: number, // Valid baud rate from list
termination_resistors?: boolean,
rx_filter?: {
extended_id: boolean,
id: number,
mask: number
}
}

CanFrame

CAN message frame structure.

{
can_id: number, // CAN identifier
data: number[] // Data bytes (0-8 bytes)
}

Usage Example

import AT1000 from '@ikalogic/at1000';

// Find and connect to device
const devices = await AT1000.findDevices(500);
const tester = devices[0];

// Access CAN interface 0
const can = tester.com.can(0);

// Enable with 500k baud rate and receive filter
await can.enable({
baud_rate: 500000,
termination_resistors: true,
rx_filter: {
extended_id: false,
id: 0x100,
mask: 0x700 // Accept IDs 0x100-0x1FF
}
});

// Start receiving frames
await can.start_rx();

// Send a frame
await can.tx({
can_id: 0x123,
data: [0x01, 0x02, 0x03, 0x04]
});

// Wait for responses
await new Promise(resolve => setTimeout(resolve, 100));

// Read received frames
const frames = await can.rx();
console.log("Received frames:", frames);

// Stop receiving
await can.stop_rx();

// Disable interface
await can.disable();

Common Patterns

CAN Filter Configuration

// Accept all standard IDs
await can.configure({
rx_filter: {
extended_id: false,
id: 0x000,
mask: 0x000 // All bits are "don't care"
}
});

// Accept only specific ID (0x123)
await can.configure({
rx_filter: {
extended_id: false,
id: 0x123,
mask: 0x7FF // All bits must match
}
});

// Accept range of IDs (0x200-0x2FF)
await can.configure({
rx_filter: {
extended_id: false,
id: 0x200,
mask: 0x700 // Match upper 3 bits
}
});

// Extended (29-bit) ID filtering
await can.configure({
rx_filter: {
extended_id: true,
id: 0x12345678,
mask: 0x1FFFFFFF
}
});

Request-Response Pattern

await can.start_rx();

// Send request
await can.tx({
can_id: 0x7DF, // OBD-II broadcast
data: [0x02, 0x01, 0x0C] // Request engine RPM
});

// Wait for response
await new Promise(resolve => setTimeout(resolve, 50));

const frames = await can.rx();
for (const frame of frames) {
if (frame.can_id >= 0x7E8 && frame.can_id <= 0x7EF) {
console.log("ECU response:", frame.data);
}
}

await can.stop_rx();

Continuous Monitoring

// Start monitoring
await can.start_rx();

// Poll periodically
const monitor = setInterval(async () => {
const frames = await can.rx();
for (const frame of frames) {
console.log(`[${Date.now()}] ID: 0x${frame.can_id.toString(16).padStart(3, '0')}, Data:`,
frame.data.map(b => b.toString(16).padStart(2, '0')).join(' '));
}
}, 100);

// Stop after some time
setTimeout(async () => {
clearInterval(monitor);
await can.stop_rx();
}, 10000);

Common Baud Rates

  • 1000000 (1 Mbps): High-speed CAN, short distance
  • 500000 (500 kbps): Most common for automotive CAN
  • 250000 (250 kbps): Industrial applications
  • 125000 (125 kbps): Longer distance CAN networks
  • 83300 (83.3 kbps): CANopen default