CAN 是目前应用非常广泛的现场总线之一,主要应用于汽车电子和工业领域,尤其是汽车 领域,汽车上大量的传感器与模块都是通过 CAN 总线连接起来的。CAN 总线目前是自动化领 域发展的热点技术之一,由于其高可靠性,CAN 总线目前广泛的应用于工业自动化、船舶、汽 车、医疗和工业设备等方面。I.MX6ULL 自带了 CAN 外设,因此可以开发 CAN 相关的设备, 本章我们就来学习一下如何驱动 I.MX6U-ALPHA 开发板上的 CAN 接口。
1:CAN 协议简析
有关 CAN 协议详细内容请参考开发板资料里面由瑞萨电子编写的《CAN 入门教程》,路径 为:4、参考资料->CAN 入门教程.pdf,本小节参考自此教程。
1.1:何为 CAN?
CAN 的全称为 Controller Area Network,也就是控制局域网络,简称为 CAN。CAN 最早是 由德国 BOSCH(博世)开发的,目前已经是国际标准(ISO 11898),是当前应用最广泛的现场总线 之一。BOSCH 主要是做汽车电子的,因此 CAN 一开始主要是为汽车电子准备的,事实也是如 此,CAN 协议目前已经是汽车网络的标准协议。当然了,CAN 不仅仅应用于汽车电子,经过 几十年的发展,CAN 协议的高性能和高可靠性已经得到了业界的认可,目前除了汽车电子以外 也广泛应用于工业自动化、医疗、工业和船舶等领域。 以汽车电子为例,汽车上有空调、车门、发动机、大量传感器等,这些部件都是通过 CAN 总线连在一起形成一个网络,车载网络结构如图 66.1.1.1 所示:
图 66.1.1.1 中各个单元通过 CAN 总线连接在一起,每个单元都是独立的 CAN 节点。同一 个 CAN 网络中所有单元的通信速度必须一致,不同的网络之间通信速度可以不同。比如图 66.1.1.1 中 125Kbps 的 CAN 网络下所有的节点速度都是 125Kbps 的,整个网络由一个网关与其 他的网络连接。 CAN 的特点主要有一下几点:
①、多主控制 在总线空闲时,所有单元都可以发送消息(多主控制),而两个以上的单元同时开始发送消 息时,根据标识符(Identifier 以下称为 ID)决定优先级。ID 并不是表示发送的目的地址,而 是表示访问总线的消息的优先级。两个以上的单元同时开始发送消息时,对各消息 ID 的每个 位进行逐个仲裁比较。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的 单元则立刻停止发送而进行接收工作。
②、系统的柔软性 与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变。
③、通信速度快,距离远 最高 1Mbps(距离小于 40M),最远可达 10KM(速率低于 5Kbps)。
④、具有错误检测、错误通知和错误恢复功能 所有单元都可以检测错误(错误检测功能),检测出错误的单元会立即同时通知其他所有单 元(错误通知功能),正在发送消息的单元一旦检测出错误,会强制结束当前的发送。强制结束 发送的单元会不断反复地重新发送此消息直到成功发送为止(错误恢复功能)。
⑤、故障封闭功能 CAN 可以判断出错误的类型是总线上暂时的数据错误(如外部噪声等)还是持续的数据错 误(如单元内部故障、驱动器故障、断线等)。由此功能,当总线上发生持续数据错误时,可将 引起此故障的单元从总线上隔离出去。
⑥、连接节点多 CAN 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际 上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增 加;提高通信速度,则可连接的单元数减少。
1.2:CAN 电气属性
CAN 总线使用两根线来连接各个单元:CAN_H 和 CAN_L,CAN 控制器通过判断这两根 线上的电位差来得到总线电平,CAN 总线电平分为显性电平和隐性电平两种。显性电平表示逻 辑“0”,此时 CAN_H 电平比 CAN_L 高,分别为 3.5V 和 1.5V,电位差为 2V。隐形电平表示 逻辑“1”,此时 CAN_H 和 CAN_L 电压都为 2.5V 左右,电位差为 0V。CAN 总线就通过显性 和隐形电平的变化来将具体的数据发送出去,如图 66.1.2.1 所示:
CAN 总线上没有节点传输数据的时候一直处于隐性状态,也就是说总线空闲状态的时候一 直处于隐性。CAN 网络中的所有单元都通过 CAN_H 和 CAN_L 这两根线连接在一起,如图 66.1.2.2 所示:
途中所有的 CAN 节点单元都采用 CAN_H 和 CAN_L 这两根线连接在一起,CAN_H 接 CAN_H、CAN_L 接 CAN_L,CAN 总线两端要各接一个 120Ω的端接电阻,用于匹配总线阻抗, 吸收信号反射及回拨,提高数据通信的抗干扰能力以及可靠性。 CAN 总线传输速度可达 1Mbps/S,最新的 CAN-FD 最高速度可达 5Mbps/S,甚至更高, CAN-FD 不在本章讨论范围,感兴趣的可以自行查阅相关资料。CAN 传输速度和总线距离有关, 总线距离越短,传输速度越快。
1.3:CAN 协议
通过 CAN 总线传输数据是需要按照一定协议进行的,CAN 协议提供了 5 种帧格式来传输 数据:数据帧、遥控帧、错误帧、过载帧和帧间隔。其中数据帧和遥控帧有标准格式和扩展格 式两种,标准格式有 11 位标识符(ID),扩展格式有 29 个标识符(ID)。这 5 中帧的用途见表 66.1.3.1:
1.3.1:数据帧
数据帧由 7 段组成:
①、帧起始,表示数据帧开始的段。
②、仲裁段,表示该帧优先级的段。
③、控制段,表示数据的字节数及保留位的段。
④、数据段,数据的内容,一帧可发送 0~8 个字节的数据。
⑤、CRC 段,检查帧的传输错误的段。
⑥、ACK 段,表示确认正常接收的段。
⑦、帧结束,表示数据帧结束的段。 数据帧结构如图 66.1.3.1 所示:
图 66.1.3.1 给出了数据帧标准格式和扩展格式两种帧结构,图中 D 表示显性电平 0、R 表 示隐性电平 1,D/R 表示显性或隐性,也就是 0 或 1,我们来简单分析一下数据帧的这 7 个段。
①、帧起始
帧起始很简单,标准格式和扩展格式都是由一个位的显性电平 0 来表示帧起始。
②、仲裁段
仲裁段表示帧优先级,仲裁段结构如图 66.1.3.2 所示:
标准格式和扩展格式的仲裁段不同,从图 66.1.3.2 可以看出,标准格式的 ID 为 11 位,发 送顺序是从 ID10 到 ID0,最高 7 位 ID10~ID4 不能全为隐性(1),也就是禁止 0X1111111XXXXX这样的 ID。扩展格式的 ID 为 29 位,基本 ID 从 ID28 到 ID18,扩展 ID 由 ID17 到 ID0,基本 ID 与标准格式一样,禁止最高 7 位都为隐性。
③、控制段
控制段由 6 个位构成,表示数据段的字节数,标准格式和扩展格式的控制段略有不同,如 图 66.1.3.3 所示:
图 66.1.3.3 中 r1 和 r0 为保留位,保留位必须以显性电平发送。DLC 为数据长度,高位在 前,DLC 段有效值范围为 0~8。
④、数据段 数据段也就是帧的有效数据,标准格式和扩展格式相同,可以包含 0~8 个字节的数据,从 最高位(MSB)开始发送,结构如图 66.1.3.4 所示:
注意,图 66.1.3.4 中数据段的 0~64 为 bit,对应到字节就是 0~8 字节。
⑤、CRC 段
CRC 段保存 CRC 校准值,用于检查帧传输错误,标准格式和扩展格式相同,CRC 段结构 如图 66.1.3.5 所示:
从图 66.1.3.5 可以看出,CRC 段由 15 位的 CRC 值与 1 位的 CRC 界定符组成。CRC 值的 计算范围包括:帧起始、仲裁段、控制段、数据段,接收方以同样的算法进行计算,然后用计 算得到的 CRC 值与此 CRC 段进行比较,如果不一致的话就会报错。
⑥、ACK 段
ACK 段用来确认接收是否正常,标准格式和扩展格式相同,ACK 段结构如图 66.1.3.6 所 示:
从图 66.1.3.7 可以看出,ACK 段由 ACK 槽(ACK Slot)和 ACK 界定符两部分组成。发送单 元的 ACK,发送 2 个隐性位,而接收到正确消息的单元在 ACK 槽(ACK Slot)发送显性位, 通知发送单元正常接收结束,这个过程叫发送 ACK/返回 ACK。发送 ACK 的是所有接收单元 中接收到正常消息的单元,所谓正常消息是指不含填充错误、格式错误、CRC 错误的消息,这 些接收单元既不处于总线关闭态也不处于休眠态的所有接收单元中。
⑦、帧结束
最后就是帧结束段,标准格式和扩展格式相同,帧结束段结构如图 66.1.3.7 所示:
从图 66.1.3.7 可以看出,帧结束段很简单,由 7 位隐性位构成。
1.3.2:遥控帧
接收单元向发送单元请求数据的时候就用遥控帧,遥控帧由 6 个段组成:
①、帧起始,表示数据帧开始的段。
②、仲裁段,表示该帧优先级的段。
③、控制段,表示数据的字节数及保留位的段。
④、CRC 段,检查帧的传输错误的段。
⑤、ACK 段,表示确认正常接收的段。
⑥、帧结束,表示数据帧结束的段。 遥控帧结构如图 66.1.3.8 所示:
从图 66.1.3.8 可以看出,遥控帧结构基本和数据帧一样,最主要的区别就是遥控帧没有数 据段。遥控帧的 RTR 位为隐性的,数据帧的 RTR 位为显性,因此可以通过 RTR 位来区分遥控 帧和没有数据的数据帧。遥控帧没有数据,因此 DLC 表示的是所请求的数据帧数据长度,遥控 帧的其他段参考数据帧的描述即可。
1.3.3:错误帧
当接收或发送消息出错的时候使用错误帧来通知,错误帧由错误标志和错误界定符两部分 组成,错误帧结构如图 66.1.3.9 所示:
错误标志有主动错误标志和被动错误标志两种,主动错误标志是 6 个显性位,被动错误标 志是 6 个隐性位,错误界定符由 8 个隐性位组成。
1.3.4:过载帧
接收单元尚未完成接收准备的话就会发送过载帧,过载帧由过载标志和过载界定符构成, 过载帧结构如图 66.1.3.10 所示:
过载标志由 6 个显性位组成,与主动错误标志相同,过载界定符由 8 个隐性位组成,与错 误帧中的错误界定符构成相同。
1.3.5:帧间隔
帧间隔用于分隔数据帧和遥控帧,数据帧和遥控帧可以通过插入帧间隔来将本帧与前面的 任何帧隔开,过载帧和错误帧前不能插入帧间隔,帧间隔结构如图 66.1.3.11 所示:
图 66.1.3.11 中间隔由 3 个隐性位构成,总线空闲为隐性电平,长度没有限制,本状态下表 示总线空闲,发送单元可以访问总线。延迟发送由 8 个隐性位构成,处于被动错误状态的单元 发送一个消息后的帧间隔中才会有延迟发送。
1.4:CAN 速率
CAN 总线以帧的形式发送数据,但是最终到总线上的就是“0”和“1”这样的二进制数据, 这里就涉及到了通信速率,也就是每秒钟发送多少位数据,前面说了 CAN2.0 最高速度为 1Mbps/S。对于 CAN 总线,一个位分为 4 段:
①、同步段(SS)
②、传播时间段(PTS)
③、相位缓冲段 1(PBS1)
④、相位缓冲段 2(PBS2)
这些段由 Tq(Time Quantum)组成,Tq 是 CAN 总线的最小时间单位。帧由位构成,一个位 由 4 个段构成,每个段又由若干个 Tq 组成,这个就是位时序。1 位由多少个 Tq 构成、每个段 又由多少个 Tq 构成等,可以任意设定位时序。通过设定位时序,多个单元可同时采样,也可 任意设定采样点。各段的作用和 Tq 数如图 66.1.4.1 所示:
1 个位的构成如图 66.1.4.2 所示:
图 66.1.4.2 一个位的构成
图 66.1.4.2 中的采样点是指读取总线电平,并将读到的电平作为位值的点。位置在 PBS1 结束处。根据这个位时序,我们就可以计算 CAN 通信的波特率了。具体计算方法,我们等下再 介绍,前面提到的 CAN 协议具有仲裁功能,下面我们来看看是如何实现的。 在总线空闲态,最先开始发送消息的单元获得发送权。 当多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性 电平最多的单元可继续发送。实现过程,如图 66.1.4.3 所示:
图 66.1.4.3 中,单元 1 和单元 2 同时开始向总线发送数据,开始部分他们的数据格式是一 样的,故无法区分优先级,直到 T 时刻,单元 1 输出隐性电平,而单元 2 输出显性电平,此时 单元 1 仲裁失利,立刻转入接收状态工作,不再与单元 2 竞争,而单元 2 则顺利获得总线使用 权,继续发送自己的数据。这就实现了仲裁,让连续发送显性电平多的单元获得总线使用权。 关于 CAN 协议就讲到这里,关于 CAN 协议更详细的内容请参考《CAN 入门教程》。
1.5:I.MX6ULL FlexCAN 简介
I.MX6ULL 带有 CAN 控制器外设,叫做 FlexCAN,FlexCAN 符合 CAN2.0B 协议。FlexCAN 完全符合CAN协议,支持标准格式和扩展格式,支持64个消息缓冲。I.MX6ULL自带的FlexCAN 模块特性如下:
①、支持 CAN2.0B 协议,数据帧和遥控帧支持标准和扩展两种格式,数据长度支持 0~8 字 节,可编程速度,最高 1Mbit/S。
②、灵活的消息邮箱,最高支持 8 个字节。
③、每个消息邮箱可以配置为接收或发送,都支持标准和扩展这两种格式的消息。
④、每个消息邮箱都有独立的接收掩码寄存器。
⑤、强大的接收 FIFO ID 过滤。
⑥、未使用的空间可以用作通用 RAM。
⑦、可编程的回测模式,用于进行自测。
⑧、可编程的优先级组合。 …… FlexCAN 支持四种模式:
正常模式(Normal)、冻结模式(Freeze)、仅监听模式(Listen-Only)和 回环模式(Loop-Back),另外还有两种低功耗模式:禁止模式(Disable)和停止模式(Stop)。
①、正常模式(Normal) 在正常模式下,FlexCAN 正常接收或发送消息帧,所有的 CAN 协议功能都使能。
②、冻结模式(Freeze) 当 MCR 寄存器的 FRZ 位置 1 的时候使能此模式,在此模式下无法进行帧的发送或接收, CAN 总线同步丢失。
③、仅监听模式(Listen-Onley) 当 CTRL 寄存器的 LOM 位置 1 的时候使能此模式,在此模式下帧发送被禁止,所有错误 计数器被冻结,CAN 控制器工作在被动错误模式,此时只会接收其他 CAN 单元发出的 ACK 消 息。
④、回环模式(Loop-Back) 当 CTRL 寄存器的 LPB 位置 1 的时候进入此模式,此模式下 FlexCAN 工作在内部回环模 式,一般用来进行自测。从模式下发送出来的数据流直接反馈给内部接收单元。 前面在讲解 CAN 协议的时候说过 CAN 位时序,FlexCAN 支持 CAN 协议的这些位时序, 控制寄存器 CTRL 用于设置这些位时序,CTRL 寄存器中的 PRESDIV、PROPSEG、PSEG1、 PSEG2 和 RJW 这 5 个位域用于设置 CAN 位时序。 PRESDIV 为 CAN 分频值,也即是设置 CAN 协议中的 Tq 值,公式如下:
fCANCLK 为 FlexCAN 模块时钟,这个根据时钟章节设置即可,设置好以后就是一个定值,因 此只需要修改 PRESDIV 即可修改 FlexCAN 的 Tq 频率值。
Tq 定了以后我们结合图 66.1.4.1 中的各个段来看一下如何设置 FlexCAN 的速率: SS:同步段(Synchronization Segment),在 I.MX6ULL 参考手册中叫做 SYNC_SEG,此段固 定为 1 个 Tq 长度,因此不需要我们去设置。 PTS:传播时间段(Propagatin Segment),FlexCAN 的 CTRL 寄存器中的 PROPSEG 位域设 置此段,可以设置为 0~7,对应 1~8 个 Tq。 PBS1:相位缓冲段 1(Phase Buffer Segment 1),FlexCAN 的 CRTL 寄存器中的 PSEG1 位域 设置此段,可以设置为 0~7,对应 1~8 个 Tq。 PBS2:相位缓冲段 2(Phase Buffer Segment 2),FlexCAN 的 CRTL 寄存器中的 PSEG2 位域 设置此段,可以设置为 1~7,对应 2~8 个 Tq。 SJW:再同步补偿宽度(reSynchronization Jump Width),FlexCAN 的 CRTL 寄存器中的 RJW 位域设置此段,可以设置 0~3,对应 1~4 个 Tq。 FlexCAN 的 CAN 位时序如图 66.1.5.1 所示
根据图 66.1.5.1 所示,SYNC+SEG+(PROP_SEG+PSEG1+2)+(PSEG2+1)就是总的 Tq,因此 FlexCAN 的波特率就是:
关于 I.MX6ULL 的 FlexCAN 控制器就讲解到这里,如果想更加详细的了解 FlexCAN,请 参考《I.MX6ULL 参考手册》的“Chapter 26 Flexible Controller Area Network(FLEXCAN)”章节。
2:硬件原理图分析
正点原子 I.MX6U-ALPHA 开发板 CAN 接口原理图如图 66.2.1 所示:
图 66.2.1 中 CAN1_TX 和 CAN1_RX 是 I.MX6ULL FlexCAN1 的发送和接收引脚,对应 I.MX6ULL 的 UART3_CTS 和 UART3_RTS 这两个引脚。TJA1050 是 CAN 收发器,通过 TJA1050 向外界提供 CAN_H 和 CAN_L 总线,R10 是一个 120 欧的端接匹配电阻。
3:实验程序编写
3.1:修改设备树
NXP 原厂提供的设备树已经配置好了 FlexCAN 的节点信息(FlexCAN1 和 FlexCAN2),但 是我们还是要来看一下如何配置 I.MX6ULL 的 CAN1 节点。首先看一下 I.MX6ULL 的 FlexCAN 设备树绑定文档,打开 Documentation/devicetree/bindings/net/can/ fsl-flexcan.txt,此文档描述了FlexCAN 节点下的相关属性信息,这里就不做介绍了,大家自行查阅。
3.1.1:FlexCAN1 引脚节点信息
首先肯定是 CAN1 引脚配置信息,打开 imx6ull-alientek-emmc.dts,找到如下所示内容:
1 pinctrl_flexcan1: flexcan1grp{
2 fsl,pins = <
3 MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX 0x1b020
4 MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX 0x1b020
5 >;
6 };
第 3 和第 4 行将 UART3_RTS 和 UART3_CTS 这两个引脚分别复用为 FlexCAN1 的 RX 和 TX,电气属性都设置为 0x1b020。
3.1.2:FlexCAN1 控制器节点信息
打开 imx6ull.dtsi 文件,找到名为“flexcan1”的节点,内容如下:
1 flexcan1: can@02090000 {
2 compatible = "fsl,imx6ul-flexcan", "fsl,imx6q-flexcan";
3 reg = <0x02090000 0x4000>;
4 interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
5 clocks = <&clks IMX6UL_CLK_CAN1_IPG>,
6 <&clks IMX6UL_CLK_CAN1_SERIAL>;
7 clock-names = "ipg", "per";
8 stop-mode = <&gpr 0x10 1 0x10 17>;
9 status = "disabled";
10 };
注意示例代码 66.3.1.2 中的 flexcan1 节点不需要我们修改,这里只是告诉大家 FlexCAN1 完整节点信息。根据第 2 行的 compatible 属性就可以找到 I.MX6ULL 的 FlexCAN 驱动源文件, 驱动文名为 drivers/net/can/flexcan.c。第 9 行的 status 属性为 disabled,所以 FlexCAN1 默认关闭 的。在 imx6ull-alientek-emmc.dts 中添加使能 FlexCAN1 的相关操作,找到如下所示代码:
1 &flexcan1 {
2 pinctrl-names = "default";
3 pinctrl-0 = <&pinctrl_flexcan1>;
4 xceiver-supply = <®_can_3v3>;
5 status = "okay";
6 };
第 3 行指定 FlexCAN1 所使用的 pinctrl 节点为 pinctrl_flecan1,也就是示例代码 66.3.1.1 中 的 pinctrl 节点。
第 4 行 xceiver-supply 属性指定 CAN 收发器的电压为 3.3V。
第 5 行将 flexcan1 节点的 status 属性改为“okay”,也就是使能 FlexCAN1。
3.1.3:关闭 FlexCAN2 相关节点
I.MX6ULL 带有两个 CAN 控制器:FlexCAN1 和 FlexCAN2,NXP 官方的 EVK 开发板这两个 CAN 接口都用到了,因此 NXP 官方的设备树将这两个 CAN 接口都使能了。但是,正点 原子的 I.MX6U-ALPHA 开发板将 FlexCAN2 的 IO 分配给了 ECSPI3,所以正点原子的 I.MX6U-ALPHA 开发板就不能使用 CAN2,否则的话 ECSPI3 外设就无法使用。关闭 FlexCAN2 节点很 简单,在 imx6ull-alientek-emmc.dts 文件中找到名为“flexcan2”的节点,然后将其屏蔽掉即可。 重新编译设备树,我们还需要配置 Linux 内核,使能内核里面的 FlexCAN 驱动。
3.2:使能 Linux 内核自带的 FlexCAN 驱动
NXP 官方提供的 linux 内核默认已经集成了 I.MX6ULL 的 FlexCAN 驱动,但是没有使能, 因此我们需要配置 Linux 内核,打开 FlexCAN 驱动,步骤如下:
3.2.1:使能 CAN 总线
首先打开 CAN 总线子系统,在 Linux 下 CAN 总线是作为网络子系统的,配置路径如下:
-> Networking support
-> <*> CAN bus subsystem support //打开 CAN 总线子系统
如图 66.3.2.1 所示:
3.2.2:使能 Freescale 系 CPU 的 FlexCAN 外设驱动
接着使能 Freescale 系 CPU 的 FlexCAN 外设驱动,配置路径如下:
-> Networking support
-> CAN bus subsystem support
-> CAN Device Drivers
-> Platform CAN drivers with Netlink support
-> <*> Support for Freescale FLEXCAN based chips //选中
配置如图 66.3.2.2 所示:
配置好以后重新编译内核,然后使用新的内核和设备树启动开发板。
4:FlexCAN 测试
4.1:检查 CAN 网卡设备是否存在
使用新编译的内核和设备树启动开发板,然后输入如下命令:
ifconfig -a //查看所有网卡
前面我们说了,Linux 系统中把 CAN 总线接口设备作为网络设备进行统一管理,因此如果 FlexCAN 驱动工作正常的话就会看到 CAN 对应的网卡接口,如图 66.4.1.1 所示:
从图 66.4.1.1 可以看出,有一个名为“can0”的网卡,这个就是 I.MX6U-ALPHA 开发板上 的 CAN1 接口对应的 can 网卡设备。如果使能了 I.MX6ULL 上的 FlexCAN2 的话也会出现一个 名为“can1”的 can 网卡设备。
4.2:移植 iproute2
在移植 ip 命令的时候必须先对根文件系统做个备份!防止操作失误导致系统启动失败!切 记!笔者的血泪经验教训!
busybox 自带的 ip 命令并不支持对 can 的操作,因此我们需要重新移植 ip 命令,也就是 iproute2,iproute2 源码下载地址为:https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/。这 里我们下载 4.4.0 版本的,笔者试过最新的版本,但是编译一直有问题。4.4.0 版本的 iproute2 已 经下载好放到了开发板光盘中,路径为:1、例程源码->7、第三方库源码-> iproute2-4.4.0.tar.gz。 将 iproute2-4.4.0.tar.gz 发送到 ubuntu 中并解压,命令如下:
tar -vxzf iproute2-4.4.0.tar.gz
解压完成以后会得到一个名为“iproute2-4.4.0”的目录,进入此目录中,打开 Makefile 并 修改。在 Makefile 中找到下面这行:
CC := gcc
改为
CC:=arm-linux-gnueabihf-gcc
修改完成以后如图 66.4.2.1 所示:
Makefile 修改完成以后直接使用“make”命令编译,编译成功以后就会在 iproute2 源码的 ip 目录下得到一个名为“ip”的命令,如图 66.4.2.2 所示:
以下操作请严格按照教程步骤来!否则可能会导致系统无法启动!
4.2.1:将交叉编译得到的 ip 拷贝到开发板中
首先将交叉编译到的 ip 命令拷贝到开发板中,先不要替换开发板根文件系统中原有的 ip 命 令!切记!切记!先拷贝到开发板根文件系统的其他目录里面,比如我这里就拷贝到 /lib/modules/4.1.15 这个目录里面,命令如下:
sudo cp ip /home/zuozhongkai/linux/nfs/test_rootfs/lib/modules/4.1.15/ -f
拷贝完成以后在开发板上先执行一下新的 ip 命令,查看一下版本号,命令如下:
cd lib/modules/4.1.15/
./ip -V //执行新的 ip 命令,查看版本号
如果新编译的 ip 命令运行正确的话就会打印出其版本号,如图 66.4.2.3 所示:
4.2.2:在开发板根文件系统中用新的 ip 命令替换原来的
注意,此步骤在开发板中执行!开发板根文件系统中原来的 ip 命令是 busybox 自带的,存 放在/sbin 目录下。接下来,我们使用新的 ip 命令替换原来的,在开发板中执行如下命令:
cd lib/modules/4.1.15/
cp ip /sbin/ip -f
拷贝完成以后将/lib/modules/4.1.15/目录下的 ip 命令删除掉,重启开发板,查看根文件系统 是否可以正常启动!如果正常启动的话输入如下命令查看 ip 命令版本号:
ip -V //查看 ip 命令版本号
结果如图 66.4.2.4 所示:
至此,iproute2 中的 ip 命令就已经移植好了,稍后的 can 测试中我们会使用 ip 命令来设置 can0 网卡的相关信息。
4.2.3:替换 ip 命令以后系统启动失败怎么办?
如果在替换 ip 命令的时候操作失误可能会导致开发板系统启动失败,如图 66.4.2.5 所示:
从图 66.4.2.5 可以看出,系统启动失败,提示“Object "it" is unknown, try "ip help".”,这是 因为 ip 命令替换错误导致的!所以说一定要严格按照本节教程讲解的步骤替换 ip 命令。遇到 图 66.4.2.5 中的错误以后解决方法很简单,把以前的 ip 命令替换回来就行了,这就是前面强烈 建议大家对根文件系统做个备份的原因!!!最简单的方法就是用备份的根文件系统重新做一遍!
4.3:移植 can-utils 工具
can0 网卡已经出现了,但是工作正不正常还不知道,必须要进行数据收发测试。这里我们 使用 can-utils 这个工具来对 can0 网卡进行测试,因此要先移植 can-utils 到我们的开发板根文件 系统中。can-utils 源码我们已经下载下来放到了开发板光盘中,路径为:1、例程源码->7、第三 方库源码-> can-utils-2020.02.04.tar.gz。 在 ubuntu 中新建一个名为“can-utils”的目录来存放 can-utils 的编译结果。然后将 can-utils 源码拷贝到 ubuntu 中并解压,命令如下:
tar -vxzf can-utils-2020.02.04.tar.gz //解压
解压完成以后得到一个名为“can-utils-2020.02.04”的目录,这个即使 can-utils 源码,进入 到此目录中,然后配置并编译,命令如下:
cd can-utils-2020.02.04 //进入 can-utils 源码目录
./autogen.sh //先执行 autogen.sh,生成配置文件 configure
./configure --target=arm-linux-gnueabihf --host=arm-linux-gnueabihf --
prefix=/home/zuozhongkai/linux/IMX6ULL/tool/can-utils --disable-static --enable-shared //配置
make //编译
make install
编译完成以后就会前面创建的“can-utils”目录下就会多出一个“bin”目录,此目录下保存 着 can-utils 的各种小工具,如图 66.4.3.1 所示:
将图 66.4.3.1 中的所有 can-utils 小工具全部拷贝到开发板根文件系统下的/usr/bin 目录下, 命令如下:
sudo cp bin/* /home/zuozhongkai/linux/nfs/rootfs/usr/bin/ -f
拷贝完成以后我们就可以使用这些小工具来测试 CAN 了。
4.4:CAN 通信测试
正点原子的 I.MX6U-ALPHA 开发板上只有一个 CAN 接口,因此我们还需要另外一个 CAN 设备,可以使用另一块 I.MX6U-ALPHA 开发板,或者 USB 转 CAN 设备,这里我两个都测试 一下。
4.4.1:两块 ALPHA 开发板连接测试
准备两块 ALPHA 开发板,然后将 CAN 接口连接起来,ALPHA 开发板上 CAN 接线端子 如图 66.4.4.1 所示:
①、收发测试
首先使用 ip 命令设置两个开发板的 CAN 接口,首先设置 CAN 接口的速度,输入如下所示 命令:
ip link set can0 type can bitrate 500000
上述命令设置 can0 速度为 500Kbit/S,两个 CAN 设备的速度要设置为一样的!速度设置好 以后打开 can0 网卡,命令如下:
ifconfig can0 up //打开 can0
can0 打开以后就可以使用 can-utils 里面的小工具进行数据收发测试了。一个开发板用来接 收数据,一个用来发送数据,接收数据的开发板使用 candump 命令,输入如下命令:
candump can0 //接收数据
发送数据的开发板使用 cansend 命令向接收单元发送 8 个字节的数据:0X11、0X22、0X33、 0X44、0X55、0X66、0X77、0X88。输入如下命令:
cansend can0 5A1#11.22.33.44.55.66.77.88
cansend 命令用于发送 can 数据,“5A1”是帧 ID,“#”号后面的“11.22.33.44.55.66.77.88” 就是要发送的数据,十六进制。CAN2.0 一次最多发送 8 个字节的数据,8 个字节的数据之间用 “.”隔开。
如果CAN工作正常的话接收端就会接收到上面发送过来的这8个字节的数据,如图66.4.4.2 所示:
从图 66.4.4.2 可以看出,接收端的 can0 接口接收到了 8 个字节的数据,帧 ID 为 5A1,说 明 CAN 驱动工作正常。 如果要关闭 can0 的话输入如下命令:
ifconfig can0 down
②、回环测试
如果要在一个板子上进行 CAN 回环测试,按照如下命令设置 CAN:
ifconfig can0 down //如果 can0 已经打开了,先关闭
ip link set can0 type can bitrate 500000 loopback on //开启回环测试
ifconfig can0 up //重新打开 can0
candump can0 & //candump 后台接收数据
cansend can0 5A1#11.22.33.44.55.66.77.88 //cansend 发送数据
如果回环测试成功的话那么开发板就会收到发送给自己的数据,如图 66.4.4.3 所示:
4.4.2:USB 转 CAN 卡测试
接下来我们使用一个 USB 转 CAN 卡与正点原子的 I.MX6U-ALPHA 开发板进行数据收发 测试,这里我使用的是周立功出品的 USBCAN 设备,型号为“USBCAN-I+”,如图 66.4.4.4 所 示:
首先设置开发板的 can0 接口,速度为 500Kbit/S,命令如下:
ip link set can0 type can bitrate 500000 //设置 can0,速率 500Kbit
ifconfig can0 up //打开 can0
candump can0 & //candump 后台接收数据
从图 66.4.4.5 可以看出,USBCAN 发送了 5 帧数据帧,帧类型为标准帧,这 5 帧数据都是 一样的,帧 ID 分别为 0~4。开发板 CAN 接口工作正常的话就会接收到这 5 帧数据,接收到的 数据如图 66.4.4.6 所示:
从图 66.4.4.6 可以看出,开发板 can0 接口接收到了 5 帧数据,和 USBCAN 发送的一致。 也可以通过开发板向 USBCAN 发送数据,输入如下命令发送数据:
cansend can0 5A1#11.22.33.44.55.66.77.88
USBCAN 接收到数据,如图 66.4.4.7 所示:
关于 CAN 驱动就讲解到这里,如果要编写 CAN 总线应用的话就直接使用 Linux 提供的 SocketCAN 接口,使用方法类似网络通信,本教程不讲解应用编程。