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.
Contents
- Required packages
- Device Tree configuration
- Bringing up the interface
- Testing using can-utils
- Hardware considerations
- Troubleshooting
Required packages
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
Device Tree configuration
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
Editing the Device Tree
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.
- Download the appropriate OpenWrt image for your target platform.
- Write the image to a microSD card.
- Mount the boot partition (20MB) of the microSD card on your development PC.
- Copy the file
dtbfrom 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.
Fixed clock
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.
Interrupt pin
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.
SPI controller
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.
MCP2515 node
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.
Compiling the Device Tree
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.
Bringing up the CAN interface
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.
Hardware considerations
Power supply
Many low-cost MCP2515 CAN modules use a TJA1050 CAN transceiver, which is powered from the same supply as the MCP2515.
Hardware modification (optional)
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.
Troubleshooting
MCP2515 driver is not loaded
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
Driver does not bind to the device
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-parentproperty - 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.