19. CAN总线

CAN是控制器局域网络(Controller Area Network)的简称, 它是由研发和生产汽车电子产品著称的德国BOSCH公司开发的, 并最终成为国际标准(ISO11519),是国际上应用最广泛的现场总线之一。

19.1. 使能CAN设备树插件

CAN总线的设备树插件和485总线设备树插件存在引脚冲突,因此在启用CAN总线设备树插件时需要关闭 485设备树插件。 修改 boot/uEnv.txt 文件,找到can、485相关设备树插件修改如下, 修改后并重启开发板。

boot/uEnv.txt
1
2
3
4
5
 #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-485r1-overlay.dtbo
 #dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-485r2-overlay.dtbo

 dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-can1.dtbo
 dtoverlay=/usr/lib/linux-image-4.19.35-imx6/overlays/imx-fire-can2.dtbo

19.2. 简单测试CAN功能

将开发板中CAN总线的跳帽连接上, 接着将CAN接口按照下图所示的方法对接,CAN1H与CAN2H连接,CAN1L与CAN2L连接。

未找到图片07|
  1. 使用以下命令查看是否存在CAN总线设备

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 ifconfig -a

 can0: flags=128<NOARP>  mtu 16
         unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
         RX packets 0  bytes 0 (0.0 B)
         RX errors 0  dropped 0  overruns 0  frame 0
         TX packets 0  bytes 0 (0.0 B)
         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
         device interrupt 25

 can1: flags=128<NOARP>  mtu 16
         unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 10  (UNSPEC)
         RX packets 0  bytes 0 (0.0 B)
         RX errors 0  dropped 0  overruns 0  frame 0
         TX packets 0  bytes 0 (0.0 B)
         TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
         device interrupt 26
  1. 安装can测试工具

1
sudo apt-get -y install can-utils
  1. 运行以下命令,设置can总线设备的波特率等信息,并且使能can总线设备。

1
2
3
4
5
 #设置can0
 sudo ip link set can0 type can bitrate 1000000;sudo ip link set can0 up

 #设置can1
 sudo ip link set can1 type can bitrate 1000000;sudo ip link set can1 up
  1. 打开两个不同的终端,一个用于读取设备数据,一个用于发送设备数据

终端1
1
2
#获取can数据
candump can0
终端2
1
2
 #发送数据
 cansend can1 123#abcdabcd

此时在终端1中将会接收到终端2传来的数据。

19.3. CANopenNode简介

CANopen 协议是在 20 世纪 90 年代末在 CAL(CAN Application Layer)的基础上发展而来的, 由CiA301(或EN 50325-4)标准指定,是用于嵌入式控制系统的国际标准化的基于CAN的高层协议。 有很多代码可以实现这个标准协议,其中就有CANopenNode, CANopenNode是免费的开源CANopen协议栈,遵循Apache 2.0开源协议,这意味着你可以使用他进行商用, 闭源等,当然更具体的协议约束得具体看协议的内容,CANopenNode可以在任何Linux机器上运行, 代码仓库位于 https://github.com/CANopenNode/CANopenNode

除此之外CANopenNode以面向对象的方式用ANSI C语言编写, 它可以作为独立应用程序或与RTOS在不同的微控制器上运行。

19.3.1. CANopenNode实验

在拉取仓库源码前,需要先安装一些编译工具。

1
2
sudo apt update
sudo apt install gcc make git can-utils

官方代码仓库位于: https://github.com/CANopenNode/CANopenNode.git

也可从野火的代码仓库中拉取libmodbus源码,

1
2
#gitee仓库地址
git clone  https://gitee.com/Embedfire/CANopenNode.git

拉取下来后看到本地有CANopenNode文件夹,我们点进去, 可以看到CANopen源码相关的文件与文件夹,如下所示

1
2
3
root@npi:/home/debian/CANopenNode# ls
301  309        CANopen.h    doc       example  LICENSE   README.md
305  CANopen.c  codingStyle  Doxyfile  extra    Makefile  socketCAN

使用make命令编译源码

1
2
3
4
5
6
7
make

# 编译输出的内容
···
cc -Wall -g -IsocketCAN -I. -Iexample -IsocketCAN -c example/CO_OD.c -o example/CO_OD.o
cc -Wall -g -IsocketCAN -I. -Iexample -IsocketCAN -c socketCAN/CO_main_basic.c -o socketCAN/CO_main_basic.o
cc -pthread socketCAN/CO_driver.o socketCAN/CO_error.o socketCAN/CO_Linux_threads.o socketCAN/CO_OD_storage.o 301/CO_SDOserver.o 301/CO_Emergency.o 301/CO_NMT_Heartbeat.o 301/CO_HBconsumer.o 301/CO_SYNC.o 301/CO_PDO.o 301/CO_TIME.o 301/CO_SDOclient.o 301/crc16-ccitt.o 301/CO_fifo.o 305/CO_LSSslave.o 305/CO_LSSmaster.o 309/CO_gateway_ascii.o extra/CO_trace.o CANopen.o example/CO_OD.o socketCAN/CO_main_basic.o -o canopend

编译完成之后在当前目录下生成了canopend可执行文件,

在其中一个终端上运行以下命令:

1
candump can0

在另外一个终端上运行以下命令:

1
./canopend can1 -i 4 -s od4_storage -a od4_storage_auto

可以看到接收端的开发板收到了很多数据,其中包括心跳以及CANopen协议的其他数据内容。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
root@npi:~# candump can0
can0  704   [1]  00
can0  084   [8]  00 50 01 2F F3 FF FF FF
can0  704   [1]  7F
can0  704   [1]  7F
can0  704   [1]  7F
can0  704   [1]  7F
can0  704   [1]  7F
can0  704   [1]  7F
can0  704   [1]  7F
can0  704   [1]  7F

发送端终端打印消息如下

1
2
3
4
5
6
7
8
debian@npi:~/CANopenNode$  ./canopend can1 -i 4 -s od4_storage -a od4_storage_auto
./canopend[662]: CANopen device, Node ID = 0x04, starting
./canopend[662]: CANopen device, Node ID = 0x04, communication reset
./canopend[662]: CAN Interface "can1" Buffer set to 367 messages (163840 Bytes)
./canopend[662]: CANopen NMT state changed to: "initializing" (0)
./canopend[662]: CANopen device, Node ID = 0x04, running ...
./canopend[662]: CANopen NMT state changed to: "pre-operational" (127)
./canopend[662]: CANopen Emergency message from node 0x04: errorCode=0x5000, errorRegister=0x01, errorBit=0x2F, infoCode=0xFFFFFFF3

19.4. CAN设备树

野火imx6ull提供了很多的设备树插件源码,若想要添加或修改不同的引脚作为CAN引脚, 可参考:

/arch/arm/boot/dts

仓库中提供了CAN1、CAN2的设备树插件, 其中CAN1的设备树插件文件为 imx-fire-can1-overlay.dts ,源码如下所示

/arch/arm/boot/dts/overlays/ebf/imx-fire-can1-overlay.dts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/dts-v1/;
/plugin/;
#include "imx6ul-pinfunc.h"
#include "dt-bindings/gpio/gpio.h"

/ {
   fragment@0 {
      target = <&flexcan1>;
      __overlay__ {
         pinctrl-names = "default";
         pinctrl-0 = <&pinctrl_flexcan1>;

         status = "okay";
      };
   };

   fragment@1 {
      target = <&iomuxc>;
      __overlay__ {
         pinctrl_flexcan1: flexcan1grp{
            fsl,pins = <
               MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX    0x1b020
               MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX    0x1b020
            >;
         };
      };
   };

};

can设备树插件修改相对简单,若想修改相对应的引脚,只需修改代码的22-23行即可。