Difference between revisions of "RPi CANBus"

From eLinux.org
Jump to: navigation, search
m (Kernel configuration and compilation)
m (SPI low latency patch: fixed typo "patch -p1 << ..." --> "patch -p1 < ...")
(One intermediate revision by one other user not shown)
Line 42: Line 42:
  
 
Then the CAN bus support must be added using "menuconfig" (see. http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=7027&start=50)
 
Then the CAN bus support must be added using "menuconfig" (see. http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=7027&start=50)
<source>
+
<source lang="bash">
 
  cd  /opt/raspberrypi/linux
 
  cd  /opt/raspberrypi/linux
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- menuconfig
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- menuconfig
Line 142: Line 142:
  
 
Then compile the kernel. The example below is for cross compilation, using a 2 core x86 machine. For compiling on the Pi, just type "make".
 
Then compile the kernel. The example below is for cross compilation, using a 2 core x86 machine. For compiling on the Pi, just type "make".
<source>
+
<source lang="bash">
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3
 
</source>  
 
</source>  
Line 228: Line 228:
  
 
This can be reduced using the following patch. Refer to the discussion on the forum for more details : http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=19489.
 
This can be reduced using the following patch. Refer to the discussion on the forum for more details : http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=19489.
 +
 +
<font color="red">'''Warning'''</font> : following the commit of 22 January 2013 (https://github.com/raspberrypi/linux/commit/91a3be5b2b783b930b2d7cdbf38283b613bce7d4) the patch fails to apply. A new patch is in process, see the forum above to check the last patch.
 +
  
 
These instructions download it from the forum and apply it.
 
These instructions download it from the forum and apply it.
Line 234: Line 237:
 
  wget http://www.raspberrypi.org/phpBB3/download/file.php?id=1492 -O spi-latency-branch3.6.y.patch.bz2
 
  wget http://www.raspberrypi.org/phpBB3/download/file.php?id=1492 -O spi-latency-branch3.6.y.patch.bz2
 
  bunzip2 spi-latency-branch3.6.y.patch.bz2  
 
  bunzip2 spi-latency-branch3.6.y.patch.bz2  
  patch -p1 << spi-latency-branch3.6.y.patch
+
  patch -p1 < spi-latency-branch3.6.y.patch
 
</source>  
 
</source>  
  
 
Then a new compilation of the kernel is done.
 
Then a new compilation of the kernel is done.
<source>
+
<source lang="bash">
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- modules_install INSTALL_MOD_PATH=/opt/raspberrypi/build/modules -j3
 
  make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- modules_install INSTALL_MOD_PATH=/opt/raspberrypi/build/modules -j3

Revision as of 13:22, 23 May 2013

CAN-bus is a communication protocol used mainly in car and some industrial products.

The Raspberry pi doesn't have CANbus built in, but it can be added through USB or SPI converters.

This document presents how to enable CANbus support in the kernel, using a SPI to CANbus converter (MCP2515). The same can be done for other SPI converters, or for PeakCAN Usb.

Raspbian kernel doesn't come with modules needed, so the kernel must be compiled from source. Refer to http://elinux.org/RPi_Kernel_Compilation for more information on this. The following instructions present all steps requiered to build a kernel with the correct modules, and some useful commands to use it.

Prerequisite

At least, a proper gcc installation is needed, and ncurses development package are used by kernel menuconfig.

 sudo apt-get install gcc ncurses-dev

Kernel configuration and compilation

For this example, everything will be done in a directory "/opt/raspberrypi/". So first create it, and then checkout the last version of the kernel for the raspberrypi in the linux subdirectory.

 cd /opt
 sudo mkdir raspberrypi
 cd raspberrypi 
 sudo chmod og+w .
 git clone --depth 1 https://github.com/raspberrypi/linux/
 cd linux

At the time of writing, the current kernel trunk version is 3.2. To use the 3.6 kernel, an additional branch has to be fetch.

 git fetch --depth=1  git://github.com/raspberrypi/linux.git rpi-3.6.y:refs/remotes/origin/rpi-3.6.y
 git checkout rpi-3.6.y

Then copy the default cutdown .config file, and run the "oldconfig" make to make it up to date.

 
 cp arch/arm/configs/bcmrpi_cutdown_defconfig .config
 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- oldconfig -j 3

From the default file, I only changed the two following lines (first is for cross-compiling the kernel), and pressed "enter" for all other (there are a lot...).

Cross-compiler tool prefix (CROSS_COMPILE) [] (NEW) arm-rpi-linux-gnueabi-
Default hostname (DEFAULT_HOSTNAME) [(none)] (NEW) raspberrypi


Then the CAN bus support must be added using "menuconfig" (see. http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=7027&start=50)

 cd  /opt/raspberrypi/linux
 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- menuconfig

Activate the following lines:

[*] Networking support --->
....<M> CAN bus subsystem support --->
........<M> Raw CAN Protocol (raw access with CAN-ID filtering)
........<M> Broadcast Manager CAN Protocol (with content filtering)
............CAN Device Drivers --->
................<M> Platform CAN drivers with Netlink support
................[*] CAN bit-timing calculation
................<M> Microchip MCP251x SPI CAN controllers
................[*] CAN devices debugging messages

....Device Drivers --->
........[*] SPI support --->
............<M> BCM2798 SPI controller driver (SPI0)
............<M> User mode SPI driver support
.......-*- GPIO Support --->
............[*] /sys/class/gpio/... (sysfs interface)

If another driver is used, activate it in place of the "MCP251x SPI CAN controllers". If using a USB controller, then SPI support is not needed, but USB must be correctly set up.

Then edit the board definition, to add the informations about the SPI bus, and to configure the interrupt pin of the MCP2515.

 vi arch/arm/mach-bcm2708/bcm2708.c
 #apply patch

Note that the "IRQF_ONESHOT" flag is only required for kernel 3.6. For kernel 3.2 you should remove it. Adjust the GPIO pin used for interrupt (here 25), the SPI frequency (here 10MHz) and MCP2515 oscillator frequency (here 20MHz) to your setup.

diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index 838e0f2..10026ec 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -54,6 +54,12 @@
 #include <mach/vcio.h>
 #include <mach/system.h>
 
+#include <linux/can/platform/mcp251x.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#define MCP2515_CAN_INT_GPIO_PIN 25
+
 #include <linux/delay.h>
 
 #include "bcm2708.h"
@@ -586,11 +592,21 @@ static struct platform_device bcm2708_spi_device = {
 	.resource = bcm2708_spi_resources,
 };
 
+static struct mcp251x_platform_data mcp251x_info = {
+   .oscillator_frequency   = 20000000,
+   .board_specific_setup   = NULL,
+   .irq_flags              = IRQF_TRIGGER_FALLING|IRQF_ONESHOT,
+   .power_enable           = NULL,
+   .transceiver_enable     = NULL,
+};
+
 #ifdef CONFIG_SPI
 static struct spi_board_info bcm2708_spi_devices[] = {
 	{
-		.modalias = "spidev",
-		.max_speed_hz = 500000,
+		.modalias = "mcp2515",
+		.max_speed_hz = 10000000,
+		.platform_data = &mcp251x_info,
+		/* .irq = unknown , defined later thru bcm2708_mcp251x_init */
 		.bus_num = 0,
 		.chip_select = 0,
 		.mode = SPI_MODE_0,
@@ -602,6 +618,13 @@ static struct spi_board_info bcm2708_spi_devices[] = {
 		.mode = SPI_MODE_0,
 	}
 };
+
+static void __init bcm2708_mcp251x_init(void) {
+   bcm2708_spi_devices[0].irq = gpio_to_irq(MCP2515_CAN_INT_GPIO_PIN);
+   printk(KERN_INFO " BCM2708 mcp251x_init:  got IRQ %d for MCP2515\n", bcm2708_spi_devices[0].irq);
+   return;
+};
+
 #endif
 
 static struct resource bcm2708_bsc0_resources[] = {
@@ -749,6 +772,7 @@ void __init bcm2708_init(void)
 	system_serial_low = serial;
 
 #ifdef CONFIG_SPI
+	bcm2708_mcp251x_init();
 	spi_register_board_info(bcm2708_spi_devices,
 			ARRAY_SIZE(bcm2708_spi_devices));
 #endif

Then compile the kernel. The example below is for cross compilation, using a 2 core x86 machine. For compiling on the Pi, just type "make".

 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3

Then install the tools from git.

 cd /opt/raspberrypi/
 git clone --depth 1 git://github.com/raspberrypi/tools.git

Use the tools to generate an image from the build kernel, and copy that to a new "build" directory.

 cd tools/mkimage
 ./imagetool-uncompressed.py ../../linux/arch/arm/boot/zImage
 mkdir -p /opt/raspberrypi/build/boot
 mv kernel.img /opt/raspberrypi/build/boot

Then return to the linux directory, to compile the kernel modules, and copy them to the build directory.

 cd ../../linux/
 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- modules_install INSTALL_MOD_PATH=/opt/raspberrypi/build/ -j3
 cp .config ../build/boot/

Again from git, get the last firmware for the raspberrypi, and copy it to the build directory.

 cd ..
 git clone --depth 1 git://github.com/raspberrypi/firmware.git
 cd firmware
 git fetch  --depth 1 git://github.com/raspberrypi/firmware.git next:refs/remotes/origin/next
 git checkout next
 
 cp boot/bootcode.bin /opt/raspberrypi/build/boot
 cp boot/fixup.dat /opt/raspberrypi/build/boot
 cp boot/start.elf /opt/raspberrypi/build/boot
 
 mkdir -p /opt/raspberrypi/build/opt
 cp -r hardfp/opt/vc /opt/raspberrypi/build/opt

You should now have the complete new kernel/modules/firmware in the "/opt/raspberrypi/build" directory. If you want to use it, simply puts its contents to the root directory. It is possible to do it directly without using a temporary build directory, but this method has the advantage of being possible on a remote machine, and to allow easier save of the binary generated (simply archive this directory if you need to give it to someone else).

MCP2515 Asynchronous Driver

The standard MCP251x has some drawbacks with kernel 3.6. It happens that it hangs and stop receiving frames. It has something to do with the "IRQF_ONESHOT" flag. Refer to the Raspberry Pi forum, for latest discussions on this point : http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=7027.

However, another MCP2515 driver exists, and has been successfully tested with kernel 3.6. Please not that it only allows to use a MCP2515 and no MCP2510 like the MCP251x driver.

You can download it and activate it in your kernel like follows.

 cd /opt/raspberrypi/linux
 wget http://clientes.netvisao.pt/anbadeol/linux-mcp2515-20101018.patch.gz
 gunzip linux-mcp2515-20101018.patch.gz
 patch -p1 < linux-mcp2515-20101018.patch
 
 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- menuconfig

Activate the following lines.

[*] Networking support --->
....<M> CAN bus subsystem support --->
........<M> Raw CAN Protocol (raw access with CAN-ID filtering)
........<M> Broadcast Manager CAN Protocol (with content filtering)
............CAN Device Drivers --->
................<M> Platform CAN drivers with Netlink support
................[*] CAN bit-timing calculation
................<M>  Microchip MCP2515 SPI CAN controller
................[*] CAN devices debugging messages

Then go again through the kernel compilation (see above if some line is missing).

 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3
 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- modules_install INSTALL_MOD_PATH=/opt/raspberrypi/build/modules -j3
 cd ../tools/mkimage
 ./imagetool-uncompressed.py ../../linux/arch/arm/boot/zImage
 mv kernel.img /opt/raspberrypi/build/boot
 cd ../../linux

The build directory is updated with the kernel and module with MCP2515 driver support.

SPI low latency patch

Finally, the SPI adds a lot of latency, that can results in frame lost at high CANbus rate, due to the small receive buffer of the MCP2515 controller.

This can be reduced using the following patch. Refer to the discussion on the forum for more details : http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=19489.

Warning : following the commit of 22 January 2013 (https://github.com/raspberrypi/linux/commit/91a3be5b2b783b930b2d7cdbf38283b613bce7d4) the patch fails to apply. A new patch is in process, see the forum above to check the last patch.


These instructions download it from the forum and apply it.

 cd /opt/raspberrypi/linux
 wget http://www.raspberrypi.org/phpBB3/download/file.php?id=1492 -O spi-latency-branch3.6.y.patch.bz2
 bunzip2 spi-latency-branch3.6.y.patch.bz2 
 patch -p1 < spi-latency-branch3.6.y.patch

Then a new compilation of the kernel is done.

 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- -j3
 make ARCH=arm CROSS_COMPILE=arm-rpi-linux-gnueabi- modules_install INSTALL_MOD_PATH=/opt/raspberrypi/build/modules -j3
 cd ../tools/mkimage
 ./imagetool-uncompressed.py ../../linux/arch/arm/boot/zImage
 mv kernel.img /opt/raspberrypi/build/boot
 cd ../../linux

The build directory is updated with the kernel patched SPI driver with low latency.