Setting up CAN bus (MCP2515) at Linux 6.2

Which Khadas SBC do you use?

VIM3

Which system do you use? Android, Ubuntu, OOWOW or others?

Ubuntu 20.04

Which version of system do you use? Khadas official images, self built images, or others?

fenix build from sources, Linux 6.2.0

Please describe your issue below:

Hi everyone. I couldn’t find working info how to set up CAN bus interface (MCP2515 via SPI) with Khadas VIM 3 board (Amlogic A311D chip) and newest Linux 6.2 version. Configuration took some time for me, maybe this information helpful.

Wiring VIM3 to MCP2515 board

Khadas VIM3 pin - function
15 - PIN.H6 - SPI_B_SSO (chip select)
16 - PIN.H7 - SPI_B_SCLK
22 - PIN.A15 - INT (interrupt from MCP2515 when received data)
35 - PWM-F - SPI_B_MISO
37 - PIN.H4 - SPI_B_MOSI

At Linux 4.9 CAN bus works properly out of box and all we need is add “can” overlay to /boot/env.txt

At Linux 6.2 (fenix build) MCP2515 drivers not included in kernel so we need rebuild Kernel with CAN drivers:

$make menuconfig

Networking support → CAN bus subsystem support → check all (M)

Device drivers → Network device support → CAN device drivers → check if you need Virtual local can interface (vcan) and CAN SPI Interface → check MCP251x drivers (M)

Save new configuration arch/arm64/configs/kvims_defconfig

Add a new overlay:

$cd arch/arm64/boot/dts/amlogic/overlays/kvim3

$touch can.dts

/dts-v1/;
/plugin/;
#include <dt-bindings/gpio/meson-g12a-gpio.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
/ {
fragment@0 {target = <&spicc1>;

  __overlay__ {
  	status = "okay";
  	#address-cells = <1>;
      		#size-cells = <0>;

  	can0: mcp2515@0 {
  		spi-max-frequency = <2000000>;
  		compatible = "microchip,mcp2515";
  		reg = <0>;
  		interrupt-parent = <&gpio_intc>;
  		interrupts = <76 IRQ_TYPE_LEVEL_LOW>; /* GPIO_A15 pin = 76, CBUS register, see A311D datasheet */
  		clock-frequency = <12000000>;
  		status = "okay";
  	};
  };

};

fragment@1 {
target = <&i2c3>;

  __overlay__ {
  	status = "disabled";
  };

};

fragment@2 {
target = <&pwm_ef>;

  __overlay__ {
  	// NOTE: This syntax DOES NOT work on device tree overlays
  	// If you want to use SPI1, you have to remove pwm_f overlay
  	/delete-property/ pinctrl-names;
  	/delete-property/ pinctrl-0;
  };

};

fragment@3 {
target = <&uart_C>;

  __overlay__ {
  	status = "disabled";
  };

};
};

If your INT pin is differ than GPIOA_15 you need define interrupt value from A311D datasheet 8-34 table.

Add “can.dtbo” to arch/arm64/boot/dts/amlogic/overlays/kvim3/Makefile

Check spi1.dts:

status = “okay”;

Then configure fenix and build:
$source setenv.sh
$export NO_GIT_UPDATE=1
$make kernel && make debs && make

Change overlays in /boot/env.txt:

overlays=can watchdog

Now we need to verify MCP2515 working:

$lsmod | grep “can”:

can_dev 40960 1 mcp251x

Check system log:

$dmesg | grep mcp

If driver loaded and wiring connections is done right we could have message:

[ 3.614276] mcp251x spi1.0 can0: MCP2515 successfully initialized.

Check MCP2515 interrupt (it is NOT the same the system .spi interrupt):
$cat /proc/interrupts

34: 51135 0 0 0 0 0 meson-gpio-irqchip 76 Level spi1.0

Check clock value of can0:

$ip -details link show can0

… clock 6000000 … (as the crystal/2 value)

Bring up can0 interface:

$sudo ip link set can0 up type can bitrate 125000

So now can0 works! Check to read data from CAN bus:

$candump -tz can0

(000.201365) can0 011 [8] 00 03 04 00 00 00 00 00
(000.402712) can0 011 [8] 00 03 04 00 00 00 00 00

2 Likes

Hello @vkshardware

Thanks for your how-to document~ :wink: