CAN (Linux)
Introductionβ
CAN (ISO 11898) bus support requires two hardware components being a CAN controller as well as a CAN transceiver. The first component acts on the data-link layer and allows to send and receive CAN datagrams. The second component, the CAN transceiver, is external to the module and makes sure the electrical specification (the physical layer) is met. CAN transceivers are available on the Apalis and Colibri Evaluation Boards (2x resp. 1x MCP2551T).
The Apalis module family provides two mandatory on-module CAN controllers available in its standard pinout. Additional CAN controllers may be available as alternate functions (e.g. Apalis iMX8 have 3 integrated CAN controllers). The Apalis iMX6 and iMX8 use the SoC internal FlexCAN CAN controllers.
The Colibri iMX6 and iMX7 modules support two FlexCAN controllers provided by the SoC available as alternate functions while the Colibri iMX8X supports even three of them. Our Colibri Evaluation boards have external CAN controllers (MCP2515 (on V3.x) or SJA1000 (on V2.1)) connected through SPI resp. the parallel bus. The former is supported by all Colibri modules.
The Verdin modules have up to two on-module CAN controllers on Reserved pins, learn more about what it means on the Verdin Family Specification. The Verdin iMX8M Mini implements them with up to two MCP2518FD CAN controllers while the Verdin iMX8M Plus implements them with FlexCAN controllers available on the SoC.
On the software side, the Linux kernel provides CAN through the SocketCAN layer, which makes use of the network socket API to communicate with devices on the CAN bus. For a short introduction to the SocketCAN layer please refer to the Linux Kernel Documentation.
CAN Protocolsβ
Several different high-level communication protocols can run on top of the CAN bus stack. Some examples are:
- ISOBUS (ISO 11783): tractors and machinery for agriculture and forestry serial control and communications data network
- SAE J1939: vehicle bus recommended practice used for communication and diagnostics among vehicle components
- Supported by the Toradex BSP on the kernel space from BSP 5 onward.
- CANopen: communication protocol and device profile specification for embedded systems used in automation
- NMEA 2000 (IEC 61162-3): plug-and-play communications standard used for connecting marine sensors and display units within ships and boats
Torizon OSβ
Torizon OS, our Industrial Linux Platform, is based in our Board Support Packages. So, for the compatible modules with Torizon, the support is as expected as the BSP.
When the CAN functionality is not enabled, you shall enable it using the Device Tree Overlays for Torizon OS, enabling the required features for the desired CAN interface.
You can find detailed instructions in our article How to Use CAN on Torizon OS, which present a step-by-step guide showing the configuration of the Container parameters, setup of a given CAN interface, and finalizing with an example of an application with our Torizon Extension for Visual Studio Code.
BSP Layers and Reference Imagesβ
For the setup of CAN in our Reference Images for Yocto Project, you can find detailed instructions in the sections below for each of our Computer-on-Modules. The standard CAN bus names are can<x>
in all module families that have integrated CAN support, where <x>
is the same number used in the datasheet.
The i.MX6, i.MX7 and i.MX6 ULL based modules, for BSP 6.x.y, are upstream-based. So in this article, there is no information about the downstream related information.
Apalis Familyβ
On the Apalis family, CAN is enabled by default in our BSP. That means that the kernel and, if applicable, a device tree are provided. Apalis modules provide 2 CAN buses identified as can0
and can1
.
Colibri Familyβ
NXP based Colibri modules have CAN support built-in or configured as a module by default. Once the device tree is set up to use a CAN device, the modules will get loaded automatically. However, on Colibri modules, CAN is not a standard pin mux, and therefore the corresponding pin allocation for CAN pins is not set by our default image in most of the cases. Hence, for Colibri iMX6 images, the kernel and/or the device tree need to be configured and recompiled (see Build U-Boot and Linux Kernel from Source Code) to support the Carrier Board CAN controller or if applicable the SoC CAN controller.
Kernel Support Colibri iMX6β
For Colibri iMX6 it's recommended to use the internal CAN controller rather than an external SPI connected controller if compatibility to other Colibri module types is not needed. Colibri iMX6 modules use device tree enabled kernels with the drivers for FlexCAN and (in newer kernels) MCP251x enabled in our default configuration. The drivers have to be enabled and configured in the device tree.
FlexCAN on Colibri iMX6β
- Open the imx6dl device tree include file
imx6qdl-colibri.dtsi
- To enable the use of FlexCAN1 (pins 55/63) or FlexCAN2 (pins 178/188) controllers, change the property
status
tookay
on&can1
and/or&can2
node.
&can1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan1>;
- status = "disabled";
+ status = "okay";
};
/* Optional on SODIMM 178/188 */
&can2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan2>;
- status = "disabled";
+ status = "okay";
};
- Remove the jumpers
JP4
/JP5
and use jumper wires to route the FlexCAN RX/TX signals to the CAN transceiver, bypassing the MCP251x CAN controller on Colibri Evaluation Board V3.2.
MCP251x on Colibri iMX6β
MCP251x is enabled by default and all the required configurations are already defined in the device tree, as it can be seen by checking the driver:
# zcat /proc/config.gz | grep CONFIG_CAN_MCP251X
CONFIG_CAN_MCP251X=y
Kernel Support Colibri iMX6ULLβ
For Colibri iMX6ULL its recommended to use the internal CAN controller rather than an external SPI connected MCP251x controller if compatibility to other Colibri module types is not needed. Colibri iMX6ULL modules use device tree enabled kernels with the drivers for FlexCAN built as a kernel module.
FlexCAN on Colibri iMX6ULLβ
- Open the imx6ull device tree include file
imx6ull-colibri.dtsi
- To enable the use of FlexCAN1 (pins 55/63) or FlexCAN2 (pins 178/188) controllers, change the property
status
tookay
on&can1
and/or&can2
node.
&can1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan1>;
- status = "disabled";
+ status = "okay";
};
&can2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan2>;
- status = "disabled";
+ status = "okay";
};
Make sure that &pinctrl_7
and &pinctrl_3
nodes are not being used in your device tree.
- With the Colibri Evaluation Board V3.2 the CAN transceiver can be isolated from the MCP251x CAN controller with the jumpers JP4/JP5. Remove the jumpers and use jumper wires to route the FlexCAN RX/TX signals to the CAN transceiver (X3-A20 is CAN2 RX and X3-B12 is CAN2 TX).
Kernel Support Colibri iMX7β
For Colibri iMX7 its recommended to use the internal CAN controller rather than an external SPI connected MCP251x controller if compatibility to other Colibri module types is not needed. Colibri iMX7 modules use device tree enabled kernels with the drivers for FlexCAN built as a kernel module.
FlexCAN on Colibri iMX7β
- Open the iMX7 device tree include file
imx7-colibri.dtsi
- To enable the use of FlexCAN1 (pins 55/63) or FlexCAN2 (pins 178/188) controllers, add the property
status
with the valueokay
on&can1
and/or&can2
node.
&flexcan1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
};
&flexcan2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
};
&iomuxc {
pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3 &pinctrl_gpio4>;
+ pinctrl-0 = <&pinctrl_gpio1 &pinctrl_gpio2 &pinctrl_gpio3>;
...
- With the Colibri Evaluation Board V3.2 the CAN transceiver can be isolated from the MCP251x CAN controller with the jumpers JP4/JP5. Remove the jumpers and use jumper wires to route the FlexCAN RX/TX signals to the CAN transceiver (X3-A20 is CAN2 RX and X3-B12 is CAN2 TX).
Kernel Support Colibri iMX8Xβ
For Colibri iMX8X, the CAN interface, located at pin 63/55, is compatible with the Colibri iMX6, the Colibri iMX6ULL, and the Colibri iMX7. Therefore, whenever only one CAN interface is required, it is recommended to use the one available at pin 63/55. Additionally, the CAN interface on pin 34/32 is compatible with the Colibri iMX6ULL, but not with the rest of the Colibri modules. Colibri iMX8X modules use device tree enabled kernels with the drivers for FlexCAN built as a kernel module.
Verdin Familyβ
Verdin modules provide 2 CAN buses identified as can0
and can1
.
Verdin iMX8M Miniβ
For using CAN with Verdin iMX8M Mini, please remember that the module does not have a native CAN Controller, which, in turn, requires the usage of an external CAN Controller through SPI port (normally).
Additional information can be found both at Controller Area Network (CAN) and SPI Sections at Verdin iMX8M Mini Datasheets.
With that in mind, you can use CAN on Verdin iMX8M Mini with the following approaches:
Without any CAN Controller assembled on SoMβ
The Verdin iMX8M Mini DualLite 1GB and Verdin iMX8M Mini DualLite 1GB WB IT are provided without CAN Controllers on the SoM itself.
So, to use one or more external SPI CAN Controllers with them, you can use the "always" compatible SPI pins for the Verdin Family, exposed through the ECSPI2 signals at the edge connector.
These models without CAN Controllers assembled on SoM will have the ECSPI3 signals exposed in the edge connector, which you can use as well.
You can use a CAN Controller like the MCP2518, and similarly as presented in the fsl-imx8mm-verdin.dtsi device-tree file, which you can find in our Linux sources, you can assign a CAN Controller as shown below:
// You can use ecspi2 or ecspi3 in the SKUs without CAN Controller on SoM
&ecspi3 {
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&gpio5 25 GPIO_ACTIVE_LOW>,
<&gpio1 5 GPIO_ACTIVE_LOW>;
/* This property is required, even if marked as obsolete in the doku */
fsl,spi-num-chipselects = <2>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";
can1: can@0 {
compatible = "microchip,mcp2517fd";
clocks = <&clk20m>;
gpio-controller;
interrupt-parent = <&gpio1>;
interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
microchip,clock-allways-on;
microchip,clock-out-div = <1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_can1_int>;
reg = <0>;
spi-max-frequency = <2000000>;
};
};
With 1 CAN Controller assembled on SoMβ
This is the default configuration for the SKUs of Verdin iMX8M Mini Quad 2GB WB IT and Verdin iMX8M Mini Quad 2GB IT.
Its CAN interface is already enabled by default in our Linux BSPs.
In case you want to add another SPI CAN Controller, the ECSPI3 signals, used for the embedded CAN Controller present in the SoM, are not exposed in the edge connector. So you can't use them to interface with your additional CAN Controller.
That said, a quick solution for the usage of one additional external SPI CAN Controllers is to connect it to the "always" compatible SPI pins for the Verdin Family, exposed through the ECSPI2 signals at edge connector.
And to setup this CAN controller SPI interface, you can use a similar approach for the Device-Tree as shown above for ECSPI2, for example.
Build-to-order of a SoM with 2 CAN Controllersβ
The Verdin iMX8M Mini SoM is ready to hold up to 2 CAN Controllers assembled on the SoM itself. This configuration needs to be discussed with Sales for the Build-to-order.
How to change CAN clock sourceβ
Due to product changes on Verdin i.MX8M Mini 2GB Quad 0055 and 0059, the CAN clock source changed from 20MHz to 40MHz. So, the projects using CAN protocol since BSP 5.7.0_devel_202205
may stop working properly. A workaround to avoid this problem is to change the CAN clock from 40MHz to 20MHz using BSP Layers and Reference Images for Yocto Project Software.
The following patch should work to change the clock-frequency
of clk40m
node, which is the node that describes the CAN clock source. Copy and the following .patch
, and then use Yocto project layers to build an image for your project.
imx8mm-verdin-clock-fix.patch
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
index d03e33a..a5ac27c 100755
--- a/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin.dtsi
@@ -35,7 +35,7 @@
clk40m: oscillator {
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <40000000>;
+ clock-frequency = <20000000>;
};
gpio-keys {
Verdin iMX8M Plusβ
The i.MX 8M Plus SoC features two Flexible Controller Area Network (FlexCAN) interfaces.
Both of them are available and enabled by default as Verdin Reserved interfaces, and therefore compatible with other Verdin modules. It doesn't mean all Verdin modules will come with 2x CAN interfaces. It means that, if a Verdin module comes with up to 2x interfaces, they will be available on the same pins.
Depending on the SoC version, the CAN interface supports the CAN Flexible Data Rate (CAN FD). Please check section 1.4.3 on Verdin iMX8M Plus datasheet for more information on which CAN version is supported by the selected Verdin iMX8M Plus module.
CAN Utilitiesβ
The CAN utilities are pre-installed on the Reference Minimal Image and the Reference Multimedia Image.
Note that the canutils come in two flavors, one provided by Pengutronix and a fork thereof, currently hosted at https://github.com/linux-can. Both can be built with OpenEmbedded, the former with bitbake canutils
and the later with bitbake can-utils
. The Toradex reference image comes with the can-utils
fork, make sure to read the can-utils README, as we only provide a basic introduction on this article.
The syntax of the cansend
command is different between the two.
Pengutronix uses for standard / extended frame format:
# cansend can1 -i 0x1F 0x11 0x22 0x33 0x44 0x55 0x55 0x77 0x88
# cansend can1 -e -i 0x1F334455 0x11 0x22 0x33 0x44 0x55 0x55 0x77 0x88
while the Linux-CAN project's equivalent would be:
# cansend can1 01F#1122334455667788
# cansend can1 01F334455#1122334455667788
The following examples are shown in the Linux-CAN format.
Configuration/Testingβ
Configureβ
A good usage explanation of CAN specific settings can be retrieved using this help command:
# ip link set can0 type can help
Usage: ip link set DEVICE type can
[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] |
[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1
phase-seg2 PHASE-SEG2 [ sjw SJW ] ]
[ loopback { on | off } ]
[ listen-only { on | off } ]
[ triple-sampling { on | off } ]
[ one-shot { on | off } ]
[ berr-reporting { on | off } ]
[ restart-ms TIME-MS ]
[ restart ]
Where: BITRATE := { 1..1000000 }
SAMPLE-POINT := { 0.000..0.999 }
TQ := { NUMBER }
PROP-SEG := { 1..8 }
PHASE-SEG1 := { 1..8 }
PHASE-SEG2 := { 1..8 }
SJW := { 1..4 }
RESTART-MS := { 0 | NUMBER }
The most important configuration is bitrate. Besides that, the interface needs to start using the up command:
# ip link set can0 type can bitrate 500000
# ip link set can0 up
One can also combine those commands:
# ip link set can0 up type can bitrate 500000 berr-reporting on
A detailed CAN state can be retrieved using the -detail option:
# ip -details link show can0
2: can0: <NOARP,ECHO> mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
link/can promiscuity 0
can state STOPPED (berr-counter tx 0 rx 0) restart-ms 0
flexcan: tseg1 4..16 tseg2 2..8 sjw 1..4 brp 1..256 brp-inc 1
clock 83368421
Custom CAN Interface Namesβ
If you decide to enable custom can interfaces - for example, additional CAN through SPI controllers or the i.MX FlexCAN - it may happen that the interfaces are enumerated in a random order with every boot.
To make it possible to use the can interfaces correctly, you can create udev rules. This section covers an example on how to do it, assuming all interfaces are already enabled and working.
Find out the names of the can interfaces:
# ip link
You will see can0
, can1
up-to canX
being X the number of interfaces enabled. Get the udev information for each of them:
# udevadm info -a -p $(udevadm info -q path -p /sys/class/net/can0)
Create a rules file at /etc/udev/rules.d/. Here is an example with 3 CAN interfaces, being them:
- CAN0: MCP251x through SPI
- CAN1: i.MX FlexCAN 1
- CAN2: i.MX FlexCAN 2
And here is the file based on properties found on the previous command:
KERNELS=="spi0.0", SUBSYSTEMS=="spi", DRIVERS=="mcp251x", ACTION=="add", NAME="CAN0"
KERNELS=="2090000.can", ACTION=="add", NAME="CAN1"
KERNELS=="2094000.can", ACTION=="add", NAME="CAN2"
Reload the udev rules and reboot:
# udevadm control --reload-rules
# reboot
Confirm that the name is always the same with ip link
after a few reboots.