CAN bus

CAN (Controller Area Network) is a field bus standardized in ISO 11898. For a general description of the CAN bus protocol, refer to Wikipedia.

The Linux CAN subsystem (SocketCAN) and therefore a wide range of CAN controllers are fully supported by OpenWrt. Depending on the hardware platform, CAN interfaces may be provided by native SoC peripherals or by external SPI controllers such as the Microchip MCP2515.

This page describes the required kernel modules, Device Tree configuration, interface setup, testing with can-utils and common troubleshooting steps.

  • Required packages
  • Device Tree configuration
  • Bringing up the interface
  • Testing using can-utils
  • Hardware considerations
  • Troubleshooting

The following kernel modules are required to use CAN interfaces with OpenWrt:

Package Description
kmod-can CAN network subsystem
kmod-can-raw Raw CAN socket support
kmod-can-mcp251x Driver for Microchip MCP2510 and MCP2515 SPI CAN controllers
kmod-can-mcp251xfd Driver for Microchip MCP2517FD, MCP2518FD and MCP251863 FD CAN controllers

For testing and debugging the can-utils and ip-full package is recommended:

opkg update
opkg install ip-full can-utils

The can-utils package provides several command line utilities, including:

  • candump – receive and display CAN frames
  • cansend – transmit CAN frames
  • cangen – generate test traffic
  • cansniffer – display changing CAN data
  • cangen – generate random CAN traffic

Many CAN controllers require a Device Tree configuration before they become available to the operating system.

For SoCs with a native CAN controller, this usually means enabling the CAN peripheral and assigning the required pins.

External SPI CAN controllers such as the Microchip MCP2515 and MCP2518FD additionally require a Device Tree node describing the SPI device, its clock source and the interrupt line.

Some platforms, such as the Raspberry Pi, use Device Tree overlays to enable CAN hardware. Other platforms, such as Allwinner (sunxi), require the base Device Tree to be modified or an overlay to be applied, depending on the platform and OpenWrt target.

The following section describes the Device Tree configuration for an Orange Pi PC / Zero LTS (Allwinner H3) using an MCP2515 SPI CAN controller, as commonly found on inexpensive SPI CAN modules.

Target platform: Orange Pi PC (Allwinner H3)

CAN controller: MCP2515

Operating system: OpenWrt 21.02.1

This article uses the Device Tree Blob (DTB) included in a standard OpenWrt image. The DTB is copied from the boot partition of the microSD card, decompiled, modified, compiled again and copied back to the boot partition.

This approach does not require rebuilding OpenWrt from source and is suitable for most users.

The examples below assume that the Device Tree Compiler (dtc) is installed on the development PC.

  1. Download the appropriate OpenWrt image for your target platform.
  2. Write the image to a microSD card.
  3. Mount the boot partition (20MB) of the microSD card on your development PC.
  4. Copy the file dtb from the boot partition into a working directory.

Decompile the Device Tree:

dtc -I dtb -O dts \
    -o device-tree.dts \
    dtb

The following changes are required to enable an MCP2515 SPI CAN controller on an Orange Pi PC (Allwinner H3).

  • Enable the SPI controller.
  • Configure the interrupt pin.
  • Add a fixed 8 MHz clock for the MCP2515.
  • Add the MCP2515 node to the SPI bus.

The following sections describe each modification in detail.

The MCP2515 requires an external clock source. Most inexpensive MCP2515 SPI CAN modules are fitted with an 8 MHz crystal oscillator. The frequency specified in the Device Tree must match the crystal fitted to the module.

Add the following fixed-clock node near the beginning of the decompiled Device Tree:

osc8m_clk {
    compatible = "fixed-clock";
    #clock-cells = <0>;
    clock-frequency = <0x7a1200>;
    clock-accuracy = <0xc350>;
    clock-output-names = "ext_osc8m";
    phandle = <0x2c>;
};

The hexadecimal value 0x7a1200 corresponds to 8000000 Hz. If the module is fitted with a different crystal, for example 16 MHz, the value of clock-frequency must be changed accordingly.

The value assigned to phandle must not already be used elsewhere in the Device Tree. Search the decompiled DTS for existing phandle properties and select an unused value. The same value must later be referenced by the MCP2515 node in its clocks property.

The MCP2515 uses an interrupt output to signal received CAN frames and controller events to the host system.

An unused GPIO pin must be configured as an interrupt input. In this example, PA7 is used on the Orange Pi PC. Add the following pin configuration to the pinctrl node:

can0_pin_irq {
    pins = "PA7";
    function = "irq";
    bias-pull-up;
    phandle = <0x31>;
};

The value assigned to phandle must not already be used elsewhere in the Device Tree. Select an unused value and use the same value later in the pinctrl-0 property of the MCP2515 node.

The MCP2515 interrupt output is active low. The corresponding interrupt type is specified later in the MCP2515 node.

The MCP2515 communicates with the host through the SPI bus. Therefore, an available SPI controller must be enabled before the CAN controller can be added.

On the Orange Pi PC, the first SPI controller is connected to the on-board SPI flash. In this example, the MCP2515 is connected to the second SPI controller (spi@1c69000).

Locate the spi@1c69000 node and change its status property to:

status = "okay";

If the following properties are missing, add them:

#address-cells = <1>;
#size-cells = <0>;

The MCP2515 node described in the next section is added as a child of the spi@1c69000 node. The SPI controller must also use the correct pin configuration. Verify that the pin assignment matches the selected SPI controller and the hardware design of your target board.

The MCP2515 is added as a child node of the selected SPI controller.

Insert the following node into the spi@1c69000 node:

mcp2515@0 {
    compatible = "microchip,mcp2515";
    reg = <0>;
    pinctrl-names = "default";
    pinctrl-0 = <0x31>;
    spi-max-frequency = <10000000>;
    interrupt-parent = <0x0a>;
    interrupts = <0 7 2>;
    clocks = <0x2c>;
    status = "okay";
};

The compatible property selects the Linux kernel driver for the controller.

reg specifies the SPI chip select. In this example, chip select 0 is used.

pinctrl-0 references the interrupt pin configuration created in the previous section.

spi-max-frequency specifies the maximum SPI clock frequency. The value shown above is suitable for the MCP2515.

interrupt-parent identifies the GPIO controller handling the interrupt.

interrupts specifies the GPIO pin and interrupt trigger type. In this example, GPIO PA7 is used.

clocks references the fixed 8 MHz clock defined earlier.

Finally, status must be set to “okay” to enable the device.

Note:The interrupt-parent property is mandatory. If it is missing or incorrect, the MCP2515 driver will not bind to the device, even if all other properties are correct.

Note:The interrupts property specifies the interrupt source used by the MCP2515.

interrupts = <0 7 2>;

The three values have the following meaning:

Value Description
0 GPIO bank A
7 GPIO number 7 (PA7)
2 Falling-edge triggered interrupt

In this example, the interrupt output of the MCP2515 is connected to GPIO PA7. Since the interrupt output of the MCP2515 is active low, a falling-edge triggered interrupt is used.

After all modifications have been completed, compile the Device Tree Source (DTS) into a Device Tree Blob (DTB):

dtc -I dts -O dtb \
    -o dtb \
    device-tree.dts

If the compilation completes without errors, replace the original dtb file on the boot partition with the newly generated file.

cp dtb /path/to/boot-partition/
sync

Insert the microSD card into the target system and boot OpenWrt.

If the system boots successfully, verify that the MCP2515 has been detected by the kernel:

dmesg | grep mcp251

A successful initialization is indicated by a message similar to:

mcp251x spi1.0 can0: MCP2515 successfully initialized.

After the MCP2515 has been detected successfully, the kernel creates a CAN network interface, usually named can0.

Check whether the interface is available:

ip link show can0

Before the interface can be used, the CAN bitrate must be configured. The bitrate must match the bitrate used by all other devices on the CAN bus.

The following example configures can0 for 100 kbit/s and enables automatic controller restart after a bus-off condition:

ip link set can0 type can bitrate 100000 restart-ms 100
ip link set can0 up

Verify the configuration:

ip -details link show can0

The output should contain information similar to:

can state ERROR-ACTIVE
    bitrate 100000

To disable the interface:

ip link set can0 down

The interface must be disabled before changing its bitrate or other CAN parameters.

Note: All devices connected to the CAN bus must use the same bitrate. An incorrect bitrate usually causes transmission errors and prevents communication.

Many low-cost MCP2515 CAN modules use a TJA1050 CAN transceiver, which is powered from the same supply as the MCP2515.

On many of these low-cost modules, the supply connection between the MCP2515 and the TJA1050 consists of a single PCB trace on the bottom side of the board. Cutting this trace allows the supply voltages to be separated.

After cutting the trace:

  • power the MCP2515 from 3.3 V
  • power the TJA1050 from 5 V using a separate wire

This modification allows the module to be connected directly to a 3.3 V SPI host while maintaining the correct supply voltage for the CAN transceiver.

Note: PCB layouts vary between manufacturers. Verify the circuit before modifying the board.

If the CAN interface is not available after boot, check whether the MCP2515 driver has been loaded.

Verify the contents of the file /etc/modules.d/can-mcp251x. Some OpenWrt releases contain the package name instead of the kernel module name:

can-mcp251x

Replace it with:

mcp251x

Reboot the system or load the module manually:

modprobe mcp251x

If the driver is loaded but no CAN interface is created, verify the Device Tree configuration.

Common causes include:

  • incorrect SPI controller
  • wrong GPIO interrupt configuration
  • missing interrupt-parent property
  • incorrect oscillator frequency

The kernel log usually provides the required information:

dmesg | grep mcp251

The CAN interface is now ready for use with SocketCAN applications such as candump, cansend, and custom applications using the Linux CAN API.

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2026/07/27 20:20
  • by elux011