Jetson nano and mcp2515 can module

Hey
I want to communicate with my jetson nano and mcp2515 can module over spi. I have read a lot of guides, but with no luck.
can anyone give me a step by step guide from scratch
Thank you

Hi,

Here are the steps you can follow:

  1. Choose a GPIO pin on J41 (40 pin header) and enable interrupts on that pin.
  2. Make proper connections from MCP2515 to SPI controller on J41. There are 2 SPI controller present on J41. I have connected two MCP chips on respective SPI controller with INT pin connected to chosen GPIO.
  3. Make changes in Nano DTB:
    can_clock: can_clock {
    compatible = “fixed-clock”;
    #clock-cells = <0>;
    clock-frequency = <20000000>;
    clock-accuracy = <100>;
    };
    spi@7000d400 { /* SPI 1 to 40 pin header */
    status = “okay”;
    spi@0 {
    compatible = “microchip,mcp2515”;
    reg = <0x0>;
    spi-max-frequency = <10000000>;
    nvidia,enable-hw-based-cs;
    nvidia,rx-clk-tap-delay = <0x7>;
    clocks = <&can_clock>;
    interrupts = <&gpio TEGRA_GPIO(Z, 0) 0x1>; // GPIO pin chosen from 40 pin header
    controller-data {
    nvidia,cs-setup-clk-count = <0x1e>;
    nvidia,cs-hold-clk-count = <0x1e>;
    nvidia,rx-clk-tap-delay = <0x1f>;
    nvidia,tx-clk-tap-delay = <0x0>;
    };

};
};

spi@7000d600 { /* SPI 2 to 40 pin header */
status = “okay”;
spi@0 {
compatible = “microchip,mcp2515”;
reg = <0x0>;
spi-max-frequency = <10000000>;
nvidia,enable-hw-based-cs;
nvidia,rx-clk-tap-delay = <0x6>;
clocks = <&can_clock>;
interrupts = <&gpio TEGRA_GPIO(V, 0) 0x1>;
controller-data {
nvidia,cs-setup-clk-count = <0x1e>;
nvidia,cs-hold-clk-count = <0x1e>;
nvidia,rx-clk-tap-delay = <0x1f>;
nvidia,tx-clk-tap-delay = <0x0>;
};
};
4) Make changes in Nano pinmux and GPIO dtb:
Enable SPI0 and SPI1 with SPI functionality by configuring pins(tristate disable, input enable, change function property…)
Add GPIO entry in gpio-input section.

Flash with the change in DTB.

Now on device after boot, run following commands:
ip link set can0 type can bitrate 500000
ip link set can0 up
ip link set can1 type can bitrate 500000
ip link set can1 up
candump -x any
cansend can0 123#abcdabcd

Thanks,
Shubhi

I followed this guide to enable SPI1 and SPI2
https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide/hw_setup_jetson_io.html
and also generated a DTBO and DTS file from that link.

My .DTS file is

/dts-v1/;

/ {
overlay-name = “User Custom [2020-02-24-152913]”;
compatible = “nvidia,p3449-0000-b00+p3448-0000-b00”, “nvidia,p3449-0000-a02+p3448-0000-a02”;

fragment@0 {
	target = <0xffffffff>;

	__overlay__ {
		pinctrl-names = "default";
		pinctrl-0 = <0x1>;

		header-40pin-pinmux {
			linux,phandle = <0x1>;
			phandle = <0x1>;

			pin8 {
				nvidia,function = "uartb";
				nvidia,pins = "uart2_tx_pg0";
				nvidia,pull = <0x0>;
				nvidia,tristate = <0x0>;
				nvidia,enable-input = <0x0>;
			};

			pin10 {
				nvidia,function = "uartb";
				nvidia,pins = "uart2_rx_pg1";
				nvidia,pull = <0x2>;
				nvidia,tristate = <0x1>;
				nvidia,enable-input = <0x1>;
			};

			pin19 {
				nvidia,function = "spi1";
				nvidia,pins = "spi1_mosi_pc0";
				nvidia,pull = <0x1>;
				nvidia,tristate = <0x0>;
				nvidia,enable-input = <0x1>;
			};

			pin21 {
				nvidia,function = "spi1";
				nvidia,pins = "spi1_miso_pc1";
				nvidia,pull = <0x1>;
				nvidia,tristate = <0x0>;
				nvidia,enable-input = <0x1>;
			};

			pin23 {
				nvidia,function = "spi1";
				nvidia,pins = "spi1_sck_pc2";
				nvidia,pull = <0x1>;
				nvidia,tristate = <0x0>;
				nvidia,enable-input = <0x1>;
			};

			pin24 {
				nvidia,function = "spi1";
				nvidia,pins = "spi1_cs0_pc3";
				nvidia,pull = <0x2>;
				nvidia,tristate = <0x0>;
				nvidia,enable-input = <0x1>;
			};

			pin26 {
				nvidia,function = "spi1";
				nvidia,pins = "spi1_cs1_pc4";
				nvidia,pull = <0x2>;
				nvidia,tristate = <0x0>;
				nvidia,enable-input = <0x1>;
			};

		};
	};
};

__symbols__ {
	hdr40_pinmux = "/fragment@0/__overlay__/header-40pin-pinmux";
};

__fixups__ {
	pinmux = "/fragment@0:target:0";
};

__local_fixups__ {

	fragment@0 {

		__overlay__ {
			pinctrl-0 = <0x0>;
		};
	};
};

};

but its a bit unclear where to make the changes, to get it working with the MCP2515 and do i have to compile that dts file into a dtb.

In the above guide you posted, the lines
interrupts = <&gpio TEGRA_GPIO(Z, 0) 0x1>; // GPIO pin chosen from 40 pin header and
interrupts = <&gpio TEGRA_GPIO(V, 0) 0x1>;
makes it a bit unclear what GPIO pins you are enabling an interrupt for on the development board out of the 40 pin headers?

Thanks!

Hi,

There is already existing node spi@7000d400 and spi@7000d600 in Nano dtsi: tegra210-p3448-0000-p3449-0000-a00.dts or something similar file (depends on which board version you are using). Add details given above under these nodes: spi@7000d400 and spi@7000d600.
Convert changed dtsi to dtb and reflash with this dtb.
I have used Pin 31 on 40-pin header as one interrupt pin of MCP2515 chip which is TEGRA_GPIO(Z, 0)
Pin 32 on 40-pin header as second interrupt pin of second MCP2515 chip which is TEGRA_GPIO(V, 0)

Let me know if you are facing any issues further.

Thanks,
Shubhi

Hi
Thank you for your quick reply

I made these changes

can_clock: can_clock {
compatible = “fixed-clock”;
#clock-cells = <0>;
clock-frequency = <20000000>;
clock-accuracy = <100>;
};

	spi@7000d400 {
		status ="okay";
		compatible = "nvidia,tegra210-spi";
		reg = <0x0 0x7000d400 0x0 0x200>;
		interrupts = <0x0 0x3b 0x4>;
		iommus = <0x2b 0xe>;
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		dmas = <0x4c 0xf 0x4c 0xf>;
		dma-names = "rx", "tx";
		nvidia,clk-parents = "pll_p", "clk_m";
		clocks = <0x21 0x29 0x21 0xf3 0x21 0xe9>;
		clock-names = "spi", "pll_p", "clk_m";
		resets = <0x21 0x29>;
		reset-names = "spi";
		status = "okay";
		linux,phandle = <0x10c>;
		phandle = <0x10c>;

		prod-settings {
			#prod-cells = <0x3>;

			prod {
				prod = <0x4 0xfff 0x0>;
			};

			prod_c_flash {
				status = "disabled";
				prod = <0x4 0x3f 0x7>;
			};

			prod_c_loop {
				status = "disabled";
				prod = <0x4 0xfff 0x44b>;
			};
		};

		spi@0 {
			compatible = "spidev, microchip,mcp2515";
			reg = <0x0>;
			spi-max-frequency = <10000000>;
			nvidia,enable-hw-based-cs;
			nvidia,rx-clk-tap-delay = <0x7>;
			clocks = <&can_clock>;
			interrupts = <&gpio TEGRA_GPIO(Z, 0) 0x1>; 

			controller-data{
				nvidia,cs-setup-clk-count = <0x1e>;
				 nvidia,cs-hold-clk-count = <0x1e>;
				nvidia,rx-clk-tap-delay = <0x1f>;
				nvidia,tx-clk-tap-delay = <0x0>;
			};		 
			
		};
	};

	spi@7000d600 {
		status ="okay";
		compatible = "nvidia,tegra210-spi";
		reg = <0x0 0x7000d600 0x0 0x200>;
		interrupts = <0x0 0x52 0x4>;
		iommus = <0x2b 0xe>;
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		dmas = <0x4c 0x10 0x4c 0x10>;
		dma-names = "rx", "tx";
		nvidia,clk-parents = "pll_p", "clk_m";
		clocks = <0x21 0x2c 0x21 0xf3 0x21 0xe9>;
		clock-names = "spi", "pll_p", "clk_m";
		resets = <0x21 0x2c>;
		reset-names = "spi";
		status = "okay";
		linux,phandle = <0x10d>;
		phandle = <0x10d>;

		prod-settings {
			#prod-cells = <0x3>;

			prod {
				prod = <0x4 0xfff 0x0>;
			};

			prod_c_flash {
				status = "disabled";
				prod = <0x4 0x3f 0x6>;
			};

			prod_c_loop {
				status = "disabled";
				prod = <0x4 0xfff 0x44b>;
			};
		};

		spi@0 {
			compatible = "spidev, microchip,mcp2515";
			reg = <0x0>;
			spi-max-frequency = <10000000>;
			nvidia,enable-hw-based-cs;
			nvidia,rx-clk-tap-delay = <0x6>;
			clocks = <&can_clock>;
			interrupts = <&gpio TEGRA_GPIO(V, 0) 0x1>;
			controller-data {
				 nvidia,cs-setup-clk-count = <0x1e>;
				nvidia,cs-hold-clk-count = <0x1e>;
				nvidia,rx-clk-tap-delay = <0x1f>;
				nvidia,tx-clk-tap-delay = <0x0>;
			};				
			
		};
	};

in the tegra210-p3448-0000-p3449-0000-b00.dts file
But when I convert that dts file to dtb with the command
dtc -I dts -O dtb -f tegra210-p3448-0000-p3449-0000-b00.dts -o tegra210-p3448-0000-p3449-0000-b00.dtb

I get an error saying
syntax error
FATAL ERROR: Unable to parse input tree

I get the error from the line
interrupts = <&gpio TEGRA_GPIO(Z, 0) 0x1>;

Thank you for your help so far!

Hi,
Since you are adding in dts:
Please add under
spi@7000d400 {
spi@0 {
compatible = “spidev, microchip,mcp2515”;
reg = <0x0>;
spi-max-frequency = <0x989680>;
nvidia,enable-hw-based-cs;
nvidia,rx-clk-tap-delay = <0x7>;
interrupts = <0x56 0xc8 0x1>;

    controller-data {
            nvidia,enable-hw-based-cs;
            nvidia,rx-clk-tap-delay = <0x7>;
    };

};
};

spi@7000d600 {
spi@0 {
compatible = “spidev, microchip,mcp2515”;
reg = <0x0>;
spi-max-frequency = <0x989680>;
nvidia,enable-hw-based-cs;
nvidia,rx-clk-tap-delay = <0x6>;
interrupts = <0x56 0xa8 0x1>;

           controller-data {
           nvidia,enable-hw-based-cs;
           nvidia,rx-clk-tap-delay = <0x1f>;
          };
    };

};

Please do not add spi@0 nodes separately, they should be slave of spi.
Please enable pins as SPI also by following guidelines mentioned earlier.

Thanks,
Shubhi

Hi again

Im also adding in the existing nodes spi@7000d400 and spi@7000d600 in the dts file
I dont add spi0@ separately
but get the error
syntax error
FATAL ERROR: Unable to parse input tree
The lines that are giving me this error is

interrupts = <&gpio TEGRA_GPIO(Z, 0) 0x1>;
and
interrupts = <&gpio TEGRA_GPIO(V, 0) 0x1>;
Do I have to replace the lines

interrupts = <&gpio TEGRA_GPIO(V, 0) 0x1>;

with

interrupts = <0x56 0xa8 0x1>;

or what to do?

and do I have to remove the code

compatible = “nvidia,tegra210-spi”;
reg = <0x0 0x7000d600 0x0 0x200>;
interrupts = <0x0 0x52 0x4>;
iommus = <0x2b 0xe>;
#address-cells = <0x1>;
#size-cells = <0x0>;
dmas = <0x4c 0x10 0x4c 0x10>;
dma-names = “rx”, “tx”;
nvidia,clk-parents = “pll_p”, “clk_m”;
clocks = <0x21 0x2c 0x21 0xf3 0x21 0xe9>;
clock-names = “spi”, “pll_p”, “clk_m”;
resets = <0x21 0x2c>;
reset-names = “spi”;
status = “okay”;
linux,phandle = <0x10d>;
phandle = <0x10d>;

prod-settings {
#prod-cells = <0x3>;

prod {
prod = <0x4 0xfff 0x0>;
};

prod_c_flash {
status = “disabled”;
prod = <0x4 0x3f 0x6>;
};

prod_c_loop {
status = “disabled”;
prod = <0x4 0xfff 0x44b>;
};
};

there already was existing inside spi@7000d600 ?

Thank you for your reply so far!

Hi,
do not remove the code. Yes, replace with interrupts = <0x56 0xc8 0x1>; interrupts = <0x56 0xa8 0x1>; as mentioned by me above.
Let me know if you still face issue.

Thanks,
Shubhi

Hi Thank you a lot

I enabled pins as SPI with the following guide

https://docs.nvidia.com/jetson/l4t/index.html#page/Tegra%20Linux%20Driver%20Package%20Development%20Guide/hw_setup_jetson_io.html

That gave me the file tegra210-p3448-0000-p3449-0000-b00-user-custom.dts

Where the pins are setup as

pinmux@700008d4 {
compatible = “nvidia,tegra210-pinmux”;
reg = <0x0 0x700008d4 0x0 0x2a5 0x0 0x70003000 0x0 0x294>;
#gpio-range-cells = <0x3>;
status = “okay”;
pinctrl-names = “default”;
pinctrl-0 = <0x12c>;
pinctrl-1 = <0x39>;
pinctrl-2 = <0x3a>;
linux,phandle = <0x3b>;
phandle = <0x3b>;

	header-40pin-pinmux {
		phandle = <0x12c>;
		linux,phandle = <0x12c>;

		pin26 {
			nvidia,enable-input = <0x1>;
			nvidia,tristate = <0x0>;
			nvidia,pull = <0x2>;
			nvidia,pins = "spi1_cs1_pc4";
			nvidia,function = "spi1";
		};

		pin24 {
			nvidia,enable-input = <0x1>;
			nvidia,tristate = <0x0>;
			nvidia,pull = <0x2>;
			nvidia,pins = "spi1_cs0_pc3";
			nvidia,function = "spi1";
		};

		pin23 {
			nvidia,enable-input = <0x1>;
			nvidia,tristate = <0x0>;
			nvidia,pull = <0x1>;
			nvidia,pins = "spi1_sck_pc2";
			nvidia,function = "spi1";
		};

		pin21 {
			nvidia,enable-input = <0x1>;
			nvidia,tristate = <0x0>;
			nvidia,pull = <0x1>;
			nvidia,pins = "spi1_miso_pc1";
			nvidia,function = "spi1";
		};

		pin19 {
			nvidia,enable-input = <0x1>;
			nvidia,tristate = <0x0>;
			nvidia,pull = <0x1>;
			nvidia,pins = "spi1_mosi_pc0";
			nvidia,function = "spi1";
		};

and the same for spi2
But I made the changes you suggested in your post in #6 in the file
tegra210-p3448-0000-p3449-0000-b00.dts

But should it be in the same file, if so which one of them.

and what to do when I run this line
ip link set can0 type can bitrate 500000

and gets the error

Cannot find device “can0”

I can see spi0.0 and spi1.0 in /dev, but I cant see can0.

Thank you for your reply so far!

Hi,
I am writing documentation on this topic where I will mention exact steps to follow, how to enable SPI etc. Please wait. I will reply here again in sometime and share revised steps here as well.

Thanks,
Shubhi

1 Like

Hi,

Documentation may take time.
Please try below steps:

  1. Changes you made in tegra210-p3448-0000-p3449-0000-b00.dts as suggested by me, keep them as it is and flash with this dts.
  2. when system boots up, use jetson-io to enable SPI1 and SPI2 as mentioned by you above. Follow the exact same method. System will boot again with this change.
  3. Now you SPI is enabled and MCP is added as slave. At this point, You should not be able to see spi0.0 and spi1.0 in /dev.
  4. Now run commands:
    ip link set can0 type can bitrate 500000
    ip link set can0 up
    ip link set can1 type can bitrate 500000
    ip link set can1 up
    candump -x any
    cansend can0 123#abcdabcd

Let me know at which step, you are facing issue.

Thanks,
Shubhi

Hi, Thanks for this info!

Can the interrupt pin be disabled for the Jetson Nano when configuring for the MCP? Would the Linux MCP2515 driver still work? We have access to another GPIO pin on our board, but requires level translator and would not want to do that if not required.
Thanks
Wietz

Hi, where to find the dts file to edit, I download the image from https://developer.nvidia.com/embedded/jetpack, and start with the SD card Image. As I want to enable the can module, I can’t find the dts file. Where could I find it?

Hi again Shubhi

I followed your steps in #11

So what I did

  1. I used jetson-io to enable SPI1 and SPI2 as I mentioned in #9. and got the dtb file
    tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb and reboot.

  2. I compiled tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb to tegra210-p3448-0000-p3449-0000-b00-user-custom.dts and made the changes as you suggested in #6

  3. When the system boot I was not able to see spi0.0 and spi1.0 in /dev as you mentioned.

  4. When I run ip link set can0 type can bitrate 500000. I get an error Cannot find device “can0”.

When I use ifconfig I cant see the can0 device

How can I fix this problem

Thanks for your help so far!

Hi, shgarg, could u please share your dts file?

hi, wietzj, could u share the dts file?

Hi shgarg,
When you will share the documentation for this topic. Dtb, dts are new for me that why I couldn’t understood clear your guide.

My board is compatible with this p3449-0000-b00+p3448-0000-b00 dtb files.
I follow same steps with you just for one SPI port. My Result is SPI0.0 is not available anymore . When I run " ip link set can0 type can bitrate 500000" successful. But “ip link set can0 up” this command turn back with “RTNETLINK answers: Invalid argument” fault. On my settings I’m not sure with interrupt settings. Because according to “interrupts = <&gpio TEGRA_GPIO(Z, 0) 0x1>; // GPIO pin chosen from 40 pin header” this setting I could not build dts file to dtb. I couldn’t find any documentation about editing dts file. I don’t know how can I assign an unused GPIO pin as interrupt.
Here is my dts setting;

can_clock {
compatible = “fixed-clock”;
#clock-cells = <0x0>;
clock-frequency = <0x1312d00>;
clock-accuracy = <0x64>;
phandle = <0x12d>;
};

spi@7000d400 {
	compatible = "nvidia,tegra210-spi";
	reg = <0x0 0x7000d400 0x0 0x200>;
	interrupts = <0x0 0x3b 0x4>;
	iommus = <0x2b 0xe>;
	#address-cells = <0x1>;
	#size-cells = <0x0>;
	dmas = <0x4c 0xf 0x4c 0xf>;
	dma-names = "rx", "tx";
	nvidia,clk-parents = "pll_p", "clk_m";
	clocks = <0x21 0x29 0x21 0xf3 0x21 0xe9>;
	clock-names = "spi", "pll_p", "clk_m";
	resets = <0x21 0x29>;
	reset-names = "spi";
	status = "okay";
	linux,phandle = <0x10c>;
	phandle = <0x10c>;

	prod-settings {
		#prod-cells = <0x3>;

		prod {
			prod = <0x4 0xfff 0x0>;
		};

		prod_c_flash {
			status = "disabled";
			prod = <0x4 0x3f 0x7>;
		};

		prod_c_loop {
			status = "disabled";
			prod = <0x4 0xfff 0x44b>;
		};
	};

	spi@0 {
		compatible = "microchip,mcp2515";
		reg = <0x0>;
		spi-max-frequency = <0x989680>;
		nvidia,enable-hw-based-cs;
		nvidia,rx-clk-tap-delay = <0x7>;
		clocks = <0x12d>;
		interrupts = <0x56 0xc8 0x1>;

		controller-data {
			nvidia,cs-setup-clk-count = <0x1e>;
			nvidia,cs-hold-clk-count = <0x1e>;
			nvidia,rx-clk-tap-delay = <0x1f>;
			nvidia,tx-clk-tap-delay = <0x0>;
		};
	};
};
  1. Dows"Flashing dts" mean convert (build) to dtb and flash this dtb file? I found one method with linux host to flas dtb file. I download Linux_for_Tegra folder and run flash.sh script on Linux host and recovery mode on jetson nano. But the flash script command never end up.
  2. when I use jetson-io script to configure it creates “tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb” file and under /boot/extlinux.conf configure this file and add this “FDT /boot/tegra210-p3448-0000-p3449-0000-b00-user-custom.dtb” line. I think this is other way to load IO settings which is included in dtb file. If I’m correct we should do switch with step1 and step2 because 2nd step will overwrite.

Hi shgarg

Are there some updates regarding the documentation
Thanks!