This article documents the process of adding hardware support for a 2-Channel CAN HAT from WaveShare using dual Microchip MCP2515 controllers over SPI on the NXP i.MX93 FRDM evaluation board.
By default, the board exposes native FlexCAN interfaces, but utilizing a popular Raspberry Pi-compatible CAN HAT requires customizing the Linux device tree and kernel configuration.
Hardware: NXP i.MX93 FRDM board, 2-Channel CAN HAT.
Software: NXP Linux BSP (Tested in 6.18.y).
Toolchain: Toolchain obtained from Yocto (Refer to the 4.5.12 How to build U-Boot and Kernel in standalone environment from i.MX Linux User's Guide).
We need to edit the main board device tree file arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts to configure the SPI master, add the dual MCP2515 nodes, assign interrupt pins, and disable conflicting native interfaces.
The key changes:
VEXP_3V3 and VEXP_5V) correctly pull up and preserve state using pinctrl-assert-gpios.16MHz clock element required by the MCP2515 crystal oscillators.flexcan2 nodes sharing pins.spidev dummy node with two microchip,mcp2515 nodes, adding two distinct Chip Select (CS) pins (GPIO2_IO08 and GPIO2_IO07) and mapping the respective hardware interrupts (GPIO2_IO23 and GPIO2_IO25).diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
index 18afe964e020..7b3af73f144f 100644
--- a/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
@@ -134,6 +134,7 @@ reg_vexp_3v3: regulator-vexp-3v3 {
compatible = "regulator-fixed";
regulator-name = "VEXP_3V3";
gpio = <&pcal6524 2 GPIO_ACTIVE_HIGH>;
+ pinctrl-assert-gpios = <&pcal6524 2 GPIO_ACTIVE_HIGH>;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-high;
@@ -144,6 +145,7 @@ reg_vexp_5v: regulator-vexp-5v {
compatible = "regulator-fixed";
regulator-name = "VEXP_5V";
gpio = <&pcal6524 8 GPIO_ACTIVE_HIGH>;
+ pinctrl-assert-gpios = <&pcal6524 8 GPIO_ACTIVE_HIGH>;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
@@ -269,6 +271,15 @@ K3: user_btn2 {
interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
};
};
+
+ clocks {
+ clk16m: clk16m {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <16000000>;
+ clock-output-names = "clk16m";
+ };
+ };
};
&adc1 {
@@ -292,7 +303,7 @@ &flexcan2 {
pinctrl-0 = <&pinctrl_flexcan2>;
pinctrl-1 = <&pinctrl_flexcan2_sleep>;
xceiver-supply = <®_can2_stby>;
- status = "okay";
+ status = "disabled";
};
&mu1 {
@@ -620,15 +631,29 @@ typec1_dr_sw: endpoint {
&lpspi3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpspi3>;
- cs-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
- pinctrl-assert-gpios = <&pcal6408 0 GPIO_ACTIVE_HIGH>;
+ cs-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>, <&gpio2 7 GPIO_ACTIVE_LOW>;
+ pinctrl-assert-gpios = <&pcal6408 0 GPIO_ACTIVE_LOW>;
status = "okay";
- spidev0: spi@0 {
+ can0: can@0 {
+ compatible = "microchip,mcp2515";
reg = <0>;
- compatible = "lwn,bk4";
- spi-max-frequency = <1000000>;
+ clocks = <&clk16m>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <23 IRQ_TYPE_LEVEL_LOW>;
+ spi-max-frequency = <10000000>;
};
+
+ can1: can@1 {
+ compatible = "microchip,mcp2515";
+ reg = <1>;
+ clocks = <&clk16m>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <25 IRQ_TYPE_LEVEL_LOW>;
+ spi-max-frequency = <10000000>;
+ };
+
+
};
&lpuart1 { /* console */
@@ -894,9 +919,12 @@ MX93_PAD_GPIO_IO29__LPI2C3_SCL 0x40000b9e
pinctrl_lpspi3: lpspi3grp {
fsl,pins = <
MX93_PAD_GPIO_IO08__GPIO2_IO08 0x39e
+ MX93_PAD_GPIO_IO07__GPIO2_IO07 0x39e
MX93_PAD_GPIO_IO09__LPSPI3_SIN 0x39e
MX93_PAD_GPIO_IO10__LPSPI3_SOUT 0x39e
MX93_PAD_GPIO_IO11__LPSPI3_SCK 0x39e
+ MX93_PAD_GPIO_IO23__GPIO2_IO23 0x39e
+ MX93_PAD_GPIO_IO25__GPIO2_IO25 0x39e
>;
};
After modifying the file, compile your device tree blobs (.dtb) and deploy them to your target boot partition.
You can refer to the below post to know the process:
How to compile Linux Kernel Image and device tree using Yocto SDK.
The MCP251x driver must be enabled within the Linux kernel configuration framework. Run the configuration tool:
user@host:~/linux-imx$ make menuconfig
Navigate through the menu to enable the driver either statically ([*]) or as a module ([M]
[*] Networking support
<*> CAN bus subsystem support
<*> Raw CAN Protocol (raw access with CAN-ID filtering) <*> Broadcast Manager CAN Protocol (with content filtering)<*> CAN Gateway/Router (with netlink configuration)And:
Device Drivers
[*] Network device support
<*> CAN Device Drivers
CAN SPI interfaces
<*> Microchip MCP251x and MCP25625 SPI CAN controllers<*> Microchip MCP251xFD SPI CAN controllersSave your configuration and compile your kernel/modules.
Once the board boots with the new device tree and kernel, you should see two new network interfaces listed under ip link show (can0 and can1).
Manuel_Salas_0-1790114307590.png
Now, you can setup the CAN interfaces:
$ sudo ip link set can0 up type can bitrate 1000000
$ sudo ip link set can1 up type can bitrate 1000000
$ sudo ifconfig can0 txqueuelen 65536
$ sudo ifconfig can1 txqueuelen 65536
Connect the HAT in loopback:
Manuel_Salas_5-1790114793732.png
From Interface can0:
candump can0
From interface can1:
cansend can1 000#11.22.33.44
Manuel_Salas_1-1790114548204.png
Manuel_Salas_2-1790114560757.png
Manuel_Salas_3-1790114583087.png
Hope this can be helpful.
Best regards,
Salas.