Implementing MCP2517FD module on Verdin

Hello guys,

Im trying to implement MCP2517FD module on my Verdin development board. We are in a need of 2 CAN interfaces but Verdin only have one (the other MCP is not assembled on the SoM) so I decided to use SPI1 interface on dev board to connect those MCP modules. I modified imx8mm-verdin-nowifi-dev.dts :

// SPDX-License-Identifier: GPL-2.0+ OR MIT
/*
 * Copyright 2019 Toradex
 */

/dts-v1/;

#include "imx8mm-verdin.dtsi"
#include "imx8mm-verdin-nonwifi.dtsi"
#include "imx8mm-verdin-dev.dtsi"

/ {
	model = "Toradex Verdin iMX8M Mini on Verdin Development Board";
	compatible = "toradex,verdin-imx8mm-nonwifi-dev",
		     "toradex,verdin-imx8mm-nonwifi",
		     "toradex,verdin-imx8mm",
		     "fsl,imx8mm";
};

&spidev20 {
    status = "disabled";
};

&iomuxc {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_gpio3>, <&pinctrl_gpio7>,
		    <&pinctrl_gpio8>, <&pinctrl_gpio_hog1>,
		    <&pinctrl_gpio_hog2>, <&pinctrl_gpio_hog3>,
		    <&pinctrl_sai5>, <&pinctrl_pmic_tpm_ena>;
};

&ecspi2 {
    #address-cells = <1>;
	#size-cells = <0>;
	cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
	/* This property is required, even if marked as obsolete in the doku */
	fsl,spi-num-chipselects = <1>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_ecspi2>;
	status = "okay";

    can3: can@0 {
        compatible = "microchip,mcp2517fd";
		clocks = <&clk20m>;
		gpio-controller;
		interrupt-parent = <&gpio5>;
		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
		microchip,clock-allways-on;
		microchip,clock-out-div = <1>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_gpio4>;
		reg = <0>;
		spi-max-frequency = <2000000>;
        status = "okay";
    };
};

This is the dmesg | grep mcp output after I boot it:

[  329.775146] mcp25xxfd spi1.0: CRC read error: computed: 6c2a received: ffff - data: be 00 04 ff ff ff ff
[  329.784691] mcp25xxfd spi1.0: CRC read of clock register resulted in a bad CRC mismatch - hw not found
[  329.794047] mcp25xxfd spi1.0: Probe failed, err=84

I used pinctrl_gpio4 for INT pin. And this is SPI signals:

Any ideas what Im doing wrong ?

Hi @spasoye,

I saw that you are using TorizonCore 5.1.0.
Are you building your own through Yocto? Or using the TorizonCore Builder?

In case you want to add a new CAN Controller through SPI, the recommended approach is through the addition of a device-tree overlay using TorizonCore Builder.

In the meantime, analyzing your issue, I don’t suggest you modify imx8mm-verdin-nowifi-dev.dts (even more because probably your Verdin module is the one with WiFi).

Instead, for a quick test, work on imx8mm-verdin-dev.dtsi, adding the CAN Controller node under &ecspi2, and disabling the spidev node that is there as well.

Please try this and tell me if it worked.

Best regards,
André Curvello

Hey @andrecurvello.tx, sorry for late reply. The problem was in my level converter, namely there wasn’t any, stupid mistake. I noticed that development board comes with level converters on it so I used them. I managed to successfully modeprobe mcp25xxfd.

New problems arose when I tried to send some data over my PCAN USB adapter. I run CAN container and configured can1 interface:

# ip link set can1 type can bitrate 125000
# ip link set can1 up
# cansend can1 123#deadbeef

When issuing cansend command dmesg returns this (spi2.0 MCP25xxfd is integrated on SoM):

[  816.976505] mcp25xxfd spi2.0: MCP2517 successfully initialized.
[  817.018948] mcp25xxfd spi1.0: MCP2517 successfully initialized.
[  890.932281] mcp25xxfd spi1.0: Controller unexpectedly switched from mode 0 to 6
[  911.025284] mcp25xxfd spi1.0 can1: CAN Bus error experienced
[  911.026878] mcp25xxfd spi1.0 can1: CAN Bus error experienced
[  911.026893] mcp25xxfd spi1.0 can1: bus-off
[  911.032363] mcp25xxfd spi1.0 can1: CAN Bus error experienced

Any idea how can I get a bit more detailed error ?

Hi @spasoye,

Normally the CAN Bus error experienced is related to disturbance on CAN bus.

Possible causes:

  • Devices with different baud-rates/bitrate.
  • Missing 120ohm terminators at each end.

Due to the disturbance, the CAN Controller turned its CAN bus off (can1: bus-off).

Can you check your wirings?
The other devices you are using have the same bitrate?

Best regards,
André Curvello

@andrecurvello.tx I have 120ohm terminator (on the PCAN adapter side, should I have it on verdin side also?).
I also got idea behind interrupts properties and I fixed this in .dts since Im using gpio5_27 for MCP interrupt:

interrupt-parent = <&gpio5>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
to
interrupt-parent = <&gpio5>;
interrupts = <27 IRQ_TYPE_EDGE_FALLING>;

I’m not getting any bus-off errors anymore (dont know if this has anything to do with wrong INT pin). But I still getting bus errors when sending and receiving and no strings are sent or received, this is dmesg output:

[ 1888.515281] NOHZ: local_softirq_pending 08
[ 1888.515948] mcp25xxfd spi1.0 can1: CAN Bus error experienced

I get NOHZ: local_softirq_pending 08 only after first cansend, after I reset interface I only get CAN Bus error.

Both Verdin and local machine are using the same bitrate:

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

Hi @spasoye,

I have 120ohm terminator (on the PCAN adapter side, should I have it on verdin side also?

R: Yes. The recommendation is to have 120ohm on both sides of the CAN bus.

I also got idea behind interrupts properties and I fixed this in .dts since Im using gpio5_27 for MCP interrupt.

R: Well, nice catch. The point of the interrupts is that they notify the arrival of new CAN Frames to the system. Otherwise the driver would require a polling approach.

[ 1888.515281] NOHZ: local_softirq_pending 08

R: That is strange. It’s an indication of high CPU load. Could be a consequence of the IRQ you’ve set. And then the CAN Controller could be triggering too much IRQs.

You can disable this message by addingnohz=off to the kernel parameters during boot. But it would only be hiding an underlying issue. There is more information about NOHZ here.

Both Verdin and local machine are using the same bitrate

R: OK.

If you try to bring-up your CAN interface with just:

ip link set up can0 type can bitrate 500000

Does that work?

Best regards,
André Curvello

@andrecurvello.tx,
both sides have 120 ohm terminator, I checked it oout.

I am able to bring-up CAN interface with this:

ip link set up can0 type can bitrate 500000

But still cant send or receive anything.
Tnx for NOHZ documentation Ill take a look at it.

Hi @spasoye,

Can you share with us the connections and wirings that you are using with the CAN Controller?

Best regards,
André Curvello

mcp2517 wiring

Here is my MCP2517FD CLICK to Verdin dev board wiring.

Hi @spasoye,

Now that I realized…

The Verdin iMX8M Mini has already 1 CAN Controller integrated in the Computer-on-Module.

This CAN Controller is already referenced by CAN0 in the &ecspi3 node. It’s enabled by default in our dts and BSP.

See:

/* On-module CAN controller 1 & 2 */
&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>;
	};

	can2: can@1 {
		compatible = "microchip,mcp2517fd";
		clocks = <&clk20m>;
		gpio-controller;
		interrupt-parent = <&gpio1>;
		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_can2_int>;
		reg = <1>;
		spi-max-frequency = <2000000>;
		/* not assembled */
		status = "disabled";
	};
};

So, I think that this whole time, you were bringing up the CAN0 (and the ghost CAN1…) interface at Linux, which in turn is the CAN1 at the Verdin Development Board.

That’s why you were not seeing anything because it was unplugged.

My suggestion is: change your can@0 to can@2 at &ecspi2 in your custom dts, and try to bring-up the can2 interface instead of can0.

Edit: The information above is incorrect, as this would change the chip-select signal of the given SPI Device. So you can keep the can3: can@0 reference, for the single external CAN Controller, for example.

Can you check that, please?

Best regards,
André Curvello

We are in a need of 2 CAN interfaces but Verdin only have one (the other MCP is not assembled on the SoM) so I decided to use SPI1 interface on dev board to connect extern MCP2517FD module.

Yes, yes, you can bring up both the CAN interfaces,

My observation was about the CAN interface for the external CAN Controller.

@andrecurvello.tx, sry I didn’t get it at first.
Not posible, I get next error:

Warning (spi_bus_reg): /soc@0/bus@30800000/spi@30830000/can@1: SPI bus unit address format error, expected "0"

@Ralph tnx for reply.
Why are #address-cells, #size-cells and fsl,spi-num-chipselects empty in your .dts ?

I havent changed any reg. reg property of can3 is reg = <0>; is there another reg property to which you refered ?

I can’t compile my .dts if don’t address my MCP node with 0 (like this can3: can@0)

When linux boots it creates can1 and can0, but sometimes can1 references can1: can@0 and can0 references can3: can@0, and sometimes its the other way around. so I don’t think that node address plays a role in naming interfaces in the linux.

Sorry @spasoye , the editor seems to interpret the braces as markup and removed the values. I try to edit it and post it here as code sample again:

&ecspi2 {
        #address-cells = <1>;
	#size-cells = <0>;
        pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_ecspi2>;
        fsl,spi-num-chipselects = <1>;
        cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
	status = "okay";

        can3: can@2 {
		compatible = "microchip,mcp2518fd";
                clocks = <&clk20m>;
                gpio-controller;
                interrupt-parent = <&gpio3>;
		interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
                microchip,clock-allways-on;
                microchip,clock-out-div = <1>;
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_can2_int>;
                reg = <0>;
                spi-max-frequency = <2000000>;
        };
};

I suppose that you changed pinctrl_can2_int to gpio3_14 (MX8MM_IOMUXC_NAND_DQS_GPIO3_IO14) ?
And you are able to build it ? It looks the same as in my case only I cant build it when I change node address to can@2.

Hi @spasoye and @Ralph,

Apparently, I mistook the can@X at each node. The number after the @ is the reference for the chip-select when using SPI devices.

That said, you shall use can1: can@0, can3: can@0 respectively, as they are the only devices in each SPI bus.

Sorry!

Best regards,
André Curvello

Hi @andrecurvello.tx and @spasoye,

I’m also trying to integrate the mcp2518fd controller with Verdin IMX8MM and fail at the same step with the same error.
I also connected the MCP2518fd to ecspi2. I tried what @andrecurvello.tx suggested (replacing can@0 with can@2):

    &ecspi2 {
            #address-cells = <1>;
            #size-cells = <0>;
            pinctrl-names = "default";
            pinctrl-0 = <&pinctrl_ecspi2>;
            fsl,spi-num-chipselects = <1>;
            cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
            status = "okay";
    
            can3: can@2 {
                    compatible = "microchip,mcp2518fd";
                    clocks = <&clk20m>;
                    gpio-controller;
                    interrupt-parent = <&gpio3>;
                    interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
                    microchip,clock-allways-on;
                    microchip,clock-out-div = <1>;
                    pinctrl-names = "default";
                    pinctrl-0 = <&pinctrl_can2_int>;
                    reg = <0>;
                    spi-max-frequency = <2000000>;
            };
    };

The two CAN devices are still created with can0 and can1 - there does not exist any “can2” device.
The two devices probe successfully, but I still get errors when sending packets.
@spasoye, I think your warning comes from the reg value that you might have changed as well to “1”: reg = <1>
I think this is not possible as it defines the chip select signal…

I found out that when I switch the node name between the two can devices then the external mcp2518fd controller is working, but the CAN controller on the SOM module (connected to spi2.0 / or ecspi3) does not work any more and throws the same errors:

> mcp25xxfd spi2.0 can1: CAN Bus error experienced  
> mcp25xxfd spi2.0 can1: bus-off

(By the way: the CAN bus-off state error does not show if you configure the interface with “restart-ms 100”.)
This makes me think if the driver is even able to run those two SPI CAN controllers in parallel? Or there might still be a problem in the device tree…?

I’m thankful for any inputs!

Hi @andrecurvello.tx ,

I had described the CAN devices in the device tree as you proposed right now. But this leads to the errors that @spasoye and me mentioned before.
Did you already have two SPI CAN controllers running on your hardware? The verdin SOM module was prepared for two controllers but not assembled…
Is there something you need to take care of in the device tree or is it possible that the driver is not able to handle two instances?
Maybe the issue is related to the fact that the two devices are on separate SPI modules and do not share one SPI with two chipselects.
Do you have any ideas?

AFAIK fsl,spi-num-chipselects specifies how many chip selects has particular SPI module. can@2 specifies not the Linux CAN instance number, but corresponding SPI module chip select number. I think it should match as well reg = <0> setting inside {}. But if you specified spi-num-chipselects 1, then you can’t have can@2. Numbered from 0 num-chipselects should be 3 to reach chipselect number 2.

AFAIK to specify Linux CAN instance number instead of letting Linux autonumerate them, you should use DT aliases {} section. Add there can5 = &can3 and Linux should have can5 interface, which would belong to what you have in DT to the right from can3:.

Does pinctrl_ecspi2 group include IOMUX settings for ecspi2 MISO / MOSI / CLK and as well chipselect number 2?

Oh well, IMX8MDQLQRM says that all 3 ECSPI modules have single chip select. But you should see now some problems in your DT.

Edward