RS485 CAN HAT - hwthomas/ccs-chademo GitHub Wiki

Notes taken (with modifications) from "CAN communication on RaspberryPI with SocketCAN" by Pragmatic Linux
see https://www.pragmaticlinux.com/2021/10/can-communication-on-the-raspberry-pi-with-socketcan/

The Waveshare RS485/CAN hat attaches to the 40-pin GPIO connector on your Raspberry PI. The add-on board contains a Microchip MCP2515 CAN controller and a Texas Instruments SN65HVD230 CAN transceiver. The screw terminal connector and the 2.54 male header connector, expose the CAN transceiver’s CAN high and CAN low signals. You need those to connect to the actual CAN bus. The CAN transceiver translates the CAN high and low signals to the right signal and voltage levels for the CAN controller’s transmit and receive pins. SPI communication enables the Raspberry PI to communicate with the CAN controller itself.

The Linux kernel of the Raspberry PI operating system can handle a CAN device, based on the Microchip MCP2515. We just need to enable it with the help of a device tree overlay. Assuming that your Raspberry PI is all booted up, run the following command to edit the config.txt file in the boot partition:

sudo nano /boot/config.txt (or possibly /boot/firmware/config.txt)

Add this line to the file:

dtoverlay=mcp2515-can0,oscillator=12000000,interrupt=25,spimaxfrequency=2000000

This assumes the manufacturer installed a 12 MHz crystal oscillator on your Waveshare RS485/CAN hat. It’s the shiny silver colored and oval shaped component on the edge of the board. The number on it should read 12.000.

One more step, before we can use the Waveshare RS485/CAN hat as a SocketCAN interface on the Raspberry PI: We need to enable SPI communication with the help of the raspi-config tool. Open it by running command:

sudo raspi-config

Go to section Interface Options → SPI and select Yes to enable the SPI interface, and reboot.

Run the following command to list all CAN devices that the Linux kernel detected:

ip addr | grep "can"

Before our Raspberry PI can bring the can0 SocketCAN network interface in the UP state, we need to first load the SocketCAN related kernel modules. Open up the terminal again and run these commands:

sudo modprobe can
sudo modprobe can_raw

To verify that the SocketCAN related kernel modules loaded properly, run:

lsmod | grep "can"

Bring the can0 SocketCAN network interface in the UP state. It is a two step process:

Configure the SocketCAN network interface. Transition the SocketCAN network interface to the UP state. Commencing with the first step, open up the terminal and run the command:

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

This configures the can0 network interface for a CAN communication speed of 500,000 bits/second. Feel free to adjust this to match the CAN communication speed on your CAN bus. Furthermore, it configures can0 to automatically re-initialize the CAN controller in case of a CAN bus off event, after 100 milliseconds. Feel free to adjust this if needed, but 100 milliseconds works fine in most cases.

With the can0 SocketCAN network interface configured, we can attempt to transition it to the UP state. From the terminal run the command:

sudo ip link set up can0

To verify that the can0 SocketCAN network interface successfully transitioned to the UP state,run
ip addr | grep "can"

We next need to install the can-utils package on our Raspberry PI system:

sudo apt install can-utils

For receiving and displaying CAN messages, we run the candump program from the terminal:

candump -tz can0

NB -tz prints timestamp on each message

We send a CAN message with the cansend program. For example:-

CAN identifier: 456h; CAN data: 00h FFh AAh 55h 01h 02h 03h 04h (8 bytes)

cansend can0 456#00FFAA5501020304

If you only have a single RS485/CAN module attached to the RPi, and you monitor the CAN_H and CAN_L lines with a scope, you will see that after sending just this 1 message the output continues indefinitely. This is because part of the CAN message, which all other stations will respond to, is an inbuilt ACK, and if the transmitting node does not receive one, it will retransmit its message (and so on and...).

You can run candump in another terminal at the same time, to see the transmitted message on the CAN bus, but - this doesn't seem to work at the moment, and candump will hang until it sees a message from another node.

Note that you need to perform the above steps each time you reboot your Raspberry PI

ie

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

Luckily, you can automatic these steps, as follows.

First, add a file to the /etc/modules-load.d/ directory (needs root permissions) so that the can and can_raw SocketCAN kernel modules are loaded at boot time.

sudo nano /etc/modules-load.d/can.conf  

with contents

can
can_raw  

on separate lines, and save.

Use systemd-networkd to manage SocketCAN network interfaces, and enable for restart on boot-up

sudo systemctl start systemd-networkd
sudo systemctl enable systemd-networkd  

Configure SocketCAN network interface

sudo nano /etc/systemd/network/80-can.network  

Add the following lines to this 80-can.network file, and save.

[Match]
Name=can0
  
[CAN]
BitRate=500K
RestartSec=100mS

Reboot the system and check that the systemd-networkd interface is running, and with the correct parameters

ip addr | grep "can"  
ip -details link show can0  

Install python-can library

pip3 install python-can