linux can 总线socket接口测试使用

时间:2021-03-30 15:11:21

该篇文章由徐老师编写,我因为需要重新修改该socket驱动到一个PMC CAN卡,故重新把资料粘贴整理了一下,上传到这里方面以后自己查阅。

原文链接如下:http://blog.chinaunix.net/uid-13889805-id-3072479.html

最近调试一个sja1000的can驱动,发现到了2.6.36,linux把can总线封装成了网络接口。内核文档里给出了这么修改的原因。

1. Overview / What is Socket CAN

--------------------------------

The socketcan package is an implementation of CANprotocols (Controller Area Network) for Linux.  CAN is a networkingtechnology which has widespread use in automation, embedded devices, andautomotive fields.  While there have been other CAN implementations forLinux based on character devices, Socket CAN uses the Berkeley socket API, theLinux network stack and implements the CAN device drivers as networkinterfaces.  The CAN socket API has been designed as similar as possibleto the TCP/IP protocols to allow programmers, familiar with networkprogramming, to easily learn how to use CAN sockets.

2. Motivation / Why using the socket API

----------------------------------------

There have been CAN implementations for Linux beforeSocket CAN so the question arises, why we have started another project. Most existing implementations come as a device driver for some CANhardware, they are based on character devices and provide comparatively littlefunctionality.  Usually, there is only a hardware-specific device driverwhich provides a character device interface to send and receive raw CAN frames,directly to/from the controller hardware. Queueing of frames and higher-leveltransport protocols like ISO-TP have to be implemented in user spaceapplications.  Also, most character-device implementations support onlyone single process to open the device at a time, similar to a serial interface. Exchanging the CAN controller requires employment of another devicedriver and often the need for adaption of large parts of the application to thenew driver's API.

Socket CAN was designed to overcome all of theselimitations.  A new protocol family has been implemented which provides asocket interface to user space applications and which builds upon the Linuxnetwork layer, so to use all of the provided queueing functionality.  Adevice driver for CAN controller hardware registers itself with the Linuxnetwork layer as a network device, so that CAN frames from the controller canbe passed up to the network layer and on to the CAN protocol family module andalso vice-versa.  Also, the protocol family module provides an API fortransport protocol modules to register, so that any number of transportprotocols can be loaded or unloaded dynamically.  In fact, the can core modulealone does not provide any protocol and cannot be used without loading at leastone additional protocol module.  Multiple sockets can be opened at thesame time, on different or the same protocol module and they can listen/sendframes on different or the same CAN IDs.  Several sockets listening on thesame interface for frames with the same CAN ID are all passed the same receivedmatching CAN frames.  An application wishing to communicate using aspecific transport protocol, e.g. ISO-TP, just selects that protocol whenopening the socket, and then can read and write application data byte streams,without having to deal with CAN-IDs, frames, etc.

Similar functionality visible from user-space could beprovided by a character device, too, but this would lead to a technicallyinelegant solution for a couple of reasons:

* Intricate usage.  Instead of passing a protocolargument to socket(2) and using bind(2) to select a CAN interface and CAN ID,an application would have to do all these operations using ioctl(2)s.

* Code duplication.  A character device cannot makeuse of the Linux network queueing code, so all that code would have to beduplicated

  for CAN networking.

* Abstraction.  In most existing character-deviceimplementations, the hardware-specific device driver for a CAN controllerdirectly

  provides the character device for the applicationto work with.

  This is at least very unusual in Unix systems forboth, char and

  block devices.  For example you don't have acharacter device for a certain UART of a serial interface, a certain sound chipin your computer, a SCSI or IDE controller providing access to your hard

  disk or tape streamer device.  Instead, youhave abstraction layers which provide a unified character or block deviceinterface to the application on the one hand, and a interface forhardware-specific device drivers on the other hand.  These abstractionsare provided

  by subsystems like the tty layer, the audiosubsystem or the SCSI

  and IDE subsystems for the devices mentionedabove.

  The easiest way to implement a CAN device driveris as a character device without such a (complete) abstraction layer, as isdone by most existing drivers.  The right way, however, would be to addsuch a

  layer with all the functionality like registeringfor certain CAN

  IDs, supporting several open file descriptors and(de)multiplexing

  CAN frames between them, (sophisticated) queueingof CAN frames, and providing an API for device drivers to register with. However, then

  it would be no more difficult, or may be eveneasier, to use the networking framework provided by the Linux kernel, and thisis what Socket CAN does.

  The use of the networking framework of the Linuxkernel is just the natural and most appropriate way to implement CAN for Linux.

  

  

  

  

  

  好吧,我是干活的,最喜欢内核自带的驱动。plx_pci.c是plx905x扩展几个sja1000的驱动。我这里是fpga做的pci-localbus桥,扩展2片sja1000。简直是专门为我准备的嘛,很快就改吧好了驱动,ifocnfig -a 也能看到can节点了。在sja1000.h头文件里有关于sja1000的最大发送缓冲区和最大中断数的限制。

  但是如何使用 Socket CAN API真犯愁啊。参照http://archive.cnblogs.com/a/1916143/,交叉编译了can-utils 4.0.6的几个重要工具。busybox的文件系统还要移植ip命令。

  1

  首先配置can0

  ip link set can0 type can tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1

  这时dmesg可以看到sja1000_fpga_pci 0000:07:04.0:setting BTR0=0x01 BTR1=0x1c

  周立功的usbcan-2a测试模块里,波特率250kbs时就是BTR0=0x01 BTR1=0x1c

  2

  ip -details link show can0 查看一下

  can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdiscpfifo_fast state UNKNOWN qlen 10

    link/can 

    can state ERROR-ACTIVE (berr-counter tx 0rx 0) restart-ms 0 

    bitrate 500000 sample-point 0.875 

    tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2sjw 1

    sja1000: tseg1 1..16 tseg2 1..8 sjw 1..4brp 1..64 brp-inc 1

    clock 16000000

    

3、接收测试,接收周立功测试软件发送的帧:

# ./candump can0

interface = can0, family = 29, type = 3, proto = 1

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

<0x00000002> [8] 70 01 02 03 04 05 06 07 

 

4、发送测试

./cansend can0 -e 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88

interface = can0, family = 29, type = 3, proto = 1

周立功测试软件上能看到接收的帧

 

5、重启

使用内核文档说的ip link set can0 type can restart-ms 100会报

RTNETLINK answers: Device or resource busy

使用ifconfig can0 down ;ip link set can0 up type can

即可

 

并没有掌握sja1000波特率的配置。摸索出4种常见波特率:

250kbps

ip link set can0 type can tq 125 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1   

125kbps:                                   

ip link set can0 type can tq 250 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1                                     

500kbps

ip link set can0 type can tq 75 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1 

1000kbps        

ip link set can0 up type can bitrate 2000000                                                          

常见用法:

ip -details link show can0

ifconfig can0 down ;ip link set can0 up type can bitrate2000000

./candump can0 ###可以通过 –o选项指定保存文件,但是是以ASCII码保存的。

./cansend   can0 -e 0x11 0x22 0x33 0x44 0x55 0x660x77 0x88 ###可以用 –loop=number来指定发送次数,发送速度较快,如果去掉缓冲区不够大,很容易因发送失败退出,可以自己在该应用程序里添加延迟,或扩大驱动发送缓冲区。

以上两个工具可以通过–h选项查看帮助文档。

 

以下部分是相关工具的编译:

linux之socketcan

Socket CAN 对CAN protocol做了封装,对CAN设备的读写变成了类似tcp/ip的读写网络(socket操作)。

 

目标环境:linux2.6.37, i.mx27开发板带mcp2515

 

首先注册spi device和mcp2515 device:

 

 

 

代码

make menuconfig中加入:

 

 

 

代码

 

 

编译安装mod:

 

insmod can.ko

 

insmod can-raw.ko

 

insmod can-bcm.ko

 

insmod can-dev.ko

 

insmod mcp251x.ko

 

 

 

最新版busybox的ip还是不支持socketcan,所以要自己编译一个。

 

上http://corp-dev.linuxfoundation.org/collaborate/workgroups/networking/iproute2下载iproute2,目前版本是2.6.35。

 

编译iproute2的时候有很多问题,安装了bison,flex,libdb4.7-dev还是死在tc目录,后来想想只要用它的ip,于是最终修改Makefile如下:

 

CC =/opt/arm-2010q1/bin/arm-none-linux-gnueabi-gcc

SUBDIRS=lib ip

 

make通过,把ip目录中的ip(elf文件)拷到目标板中运行:

 

chmod 777 ip

 

./ip link set can0 up typecan bitrate 250000

./ip -details link showcan0

 

can0设置好后可以用以下命令修改bitrate

 

ifconfig can0 down 

echo 125000 >/sys/class/net/can0/can_bitrate 

ifconfig can0 up 

 

 

到这一步socketcan就算配置完成了,不过还是可以给它添加一些工具。

 

1.用socketcan里的can-utils:

 

sudo apt-get installsubversion

svn checkoutsvn://svn.berlios.de/socketcan/trunk socketcan

cp -r socketcan../Workspaces

修改socketcan/can-utils/Makefile

PREFIX=./bin

KERNELDIR =http://www.cnblogs.com/linux-2.6.37

CC=/opt/arm-2010q1/bin/arm-none-linux-gnueabi-gcc (新增)

socketcan和linux2.6.37带的socketcan版本不同,导致有些不能编译成功,不过大部分工具都有了,剩下的如果要的话可以考虑merge linux内核----还不如自己写工具呢

 

2.在http://www.pengutronix.de/software/socket-can下载can-utils 4.0.6,也可以通过谷歌搜索can-utils 4.0.6下载,百度不行。里面有5个工具,不过搞不定它的configure,手工编译之吧:

 

先在include下建一个can_config.h,里面就一句话#define VERSION 20090105  (随便怎么写吧,我是看到can.ko的版本是20090105) 

 

然后进到src目录

 

/opt/arm-2010q1/bin/arm-none-linux-gnueabi-gcc -o xxx  xxx.c -I$PWD/../include -I$PWD/***/linux-2.6.37/include (faint,http://www.cnblogs.com/被转成www.cnblogs.com)

 

除了canconfig.c通不过(需要libsocketcan.h,好在已经有iproute2了)其他的都成功。 感觉这个cansend比socketcan里的cansend好用。