目录
- CAN 协议简析
- 何为CAN
- CAN 电气属性
- 显隐性电平
- 接线
- 端接电阻
- 速度距离
- CAN 协议
- 1、数据帧
- 2、遥控帧
- 3、错误帧
- 4、过载帧
- 5、帧间隔
- CAN 速率
- I.MX6ULL FlexCAN 简介
- 硬件原理图分析
- 实验程序编写
- 修改设备树
- 使能Linux 内核自带的FlexCAN 驱动
- FlexCAN 测试
- 检查CAN 网卡设备是否存在
- 移植iproute2
- 移植can-utils 工具
- CAN 通信测试
CAN 是目前应用非常广泛的现场总线之一,主要应用于汽车电子和工业领域,尤其是汽车领域,汽车上大量的传感器与模块都是通过CAN 总线连接起来的。CAN 总线目前是自动化领域发展的热点技术之一,由于其高可靠性,CAN 总线目前广泛的应用于工业自动化、船舶、汽车、医疗和工业设备等方面。I.MX6ULL 自带了CAN 外设,因此可以开发CAN 相关的设备,本章我们就来学习一下如何驱动I.MX6U-ALPHA 开发板上的CAN 接口。
CAN 协议简析
有关CAN 协议详细内容请参考开发板资料里面由瑞萨电子编写的《CAN 入门教程》,路径为:4、参考资料->CAN 入门教程.pdf,本小节参考自此教程。
何为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 总线是可同时连接多个单元的总线。可连接的单元总数理论上是没有限制的。但实际上可连接的单元数受总线上的时间延迟及电气负载的限制。降低通信速度,可连接的单元数增加;提高通信速度,则可连接的单元数减少。
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 传输速度和总线距离有关,总线距离越短,传输速度越快。
CAN 协议
通过CAN 总线传输数据是需要按照一定协议进行的,CAN 协议提供了5 种帧格式来传输数据:数据帧、遥控帧、错误帧、过载帧和帧间隔。其中数据帧和遥控帧有标准格式和扩展格式两种,标准格式有11 位标识符(ID),扩展格式有29 个标识符(ID)。这5 中帧的用途见表66.1.3.1:
帧类型 | 帧用途 |
---|---|
数据帧 | 用于CAN节点单元之间进行数据传输的帧 |
遥控帧 | 用于接收单元向具有相同ID 的发送单元请求数据的帧 |
错误帧 | 用于当检测出错误时向其它单元通知错误的帧 |
过载帧 | 用于接收单元通知其尚未做好接收准备的帧 |
间隔帧 | 用于将数据帧及遥控帧与前面的帧分离开来的帧 |
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 位隐性位构成。
2、遥控帧
接收单元向发送单元请求数据的时候就用遥控帧,遥控帧由6 个段组成:
①、帧起始,表示数据帧开始的段。
②、仲裁段,表示该帧优先级的段。
③、控制段,表示数据的字节数及保留位的段。
④、CRC 段,检查帧的传输错误的段。
⑤、ACK 段,表示确认正常接收的段。
⑥、帧结束,表示数据帧结束的段。
遥控帧结构如图66.1.3.8 所示:
从图66.1.3.8 可以看出,遥控帧结构基本和数据帧一样,最主要的区别就是遥控帧没有数据段。遥控帧的RTR 位为隐性的,数据帧的RTR 位为显性,因此可以通过RTR 位来区分遥控帧和没有数据的数据帧。遥控帧没有数据,因此DLC 表示的是所请求的数据帧数据长度,遥控帧的其他段参考数据帧的描述即可。
3、错误帧
当接收或发送消息出错的时候使用错误帧来通知,错误帧由错误标志和错误界定符两部分组成,错误帧结构如图66.1.3.9 所示:
错误标志有主动错误标志和被动错误标志两种,主动错误标志是6 个显性位,被动错误标志是6 个隐性位,错误界定符由8 个隐性位组成。
4、过载帧
接收单元尚未完成接收准备的话就会发送过载帧,过载帧由过载标志和过载界定符构成,过载帧结构如图66.1.3.10 所示:
过载标志由6 个显性位组成,与主动错误标志相同,过载界定符由8 个隐性位组成,与错误帧中的错误界定符构成相同。
5、帧间隔
帧间隔用于分隔数据帧和遥控帧,数据帧和遥控帧可以通过插入帧间隔来将本帧与前面的任何帧隔开,过载帧和错误帧前不能插入帧间隔,帧间隔结构如图66.1.3.11 所示:
图66.1.3.11 中间隔由3 个隐性位构成,总线空闲为隐性电平,长度没有限制,本状态下表示总线空闲,发送单元可以访问总线。延迟发送由8 个隐性位构成,处于被动错误状态的单元发送一个消息后的帧间隔中才会有延迟发送。
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 中的采样点是指读取总线电平,并将读到的电平作为位值的点。位置在PBS1结束处。根据这个位时序,我们就可以计算CAN 通信的波特率了。具体计算方法,我们等下再介绍,前面提到的CAN 协议具有仲裁功能,下面我们来看看是如何实现的。
在总线空闲态,最先开始发送消息的单元获得发送权。
当多个单元同时开始发送时,各发送单元从仲裁段的第一位开始进行仲裁。连续输出显性电平最多的单元可继续发送。实现过程,如图66.1.4.3 所示:
图66.1.4.3 中,单元1 和单元2 同时开始向总线发送数据,开始部分他们的数据格式是一样的,故无法区分优先级,直到T 时刻,单元1 输出隐性电平,而单元2 输出显性电平,此时单元1 仲裁失利,立刻转入接收状态工作,不再与单元2 竞争,而单元2 则顺利获得总线使用权,继续发送自己的数据。这就实现了仲裁,让连续发送显性电平多的单元获得总线使用权。
关于CAN 协议就讲到这里,关于CAN 协议更详细的内容请参考《CAN 入门教程》。
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)”章节。
硬件原理图分析
正点原子I.MX6U-ALPHA 开发板CAN 接口原理图如图66.2.1 所示:
图66.2.1 中TJA1050 是CAN 收发器,通过TJA1050向外界提供CAN_H 和CAN_L 总线,R10 是一个120 欧的端接匹配电阻;
CAN1_TX 和CAN1_RX 是I.MX6ULL FlexCAN1 的发送和接收引脚,对应I.MX6ULL 的UART3_CTS 和UART3_RTS 这两个引脚。。
实验程序编写
修改设备树
NXP 原厂提供的设备树已经配置好了FlexCAN 的节点信息(FlexCAN1 和FlexCAN2),但是我们还是要来看一下如何配置I.MX6ULL 的CAN1 节点。首先看一下I.MX6ULL 的FlexCAN设备树绑定文档,打开Documentation/devicetree/bindings/net/can/ fsl-flexcan.txt,此文档描述了FlexCAN 节点下的相关属性信息,这里就不做介绍了,大家自行查阅。
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。
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、关闭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 驱动。
使能Linux 内核自带的FlexCAN 驱动
NXP 官方提供的linux内核默认已经集成了I.MX6ULL 的FlexCAN 驱动,但是没有使能,因此我们需要配置Linux 内核,打开FlexCAN 驱动,步骤如下:
1、使能CAN 总线
首先打开CAN 总线子系统,在Linux 下CAN 总线是作为网络子系统的,配置路径如下:
-> Networking support-> <*> CAN bus subsystem support //打开CAN 总线子系统
如图66.3.2.1 所示:
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 所示:
配置好以后重新编译内核,然后使用新的内核和设备树启动开发板。
FlexCAN 测试
检查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 网卡设备。
移植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 所示:
以下操作请严格按照教程步骤来!否则可能会导致系统无法启动!
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 所示:
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 网卡的相关信息。
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 命令替换回来就行了,这就是前面强烈建议大家对根文件系统做个备份的原因!!!最简单的方法就是用备份的根文件系统重新做一遍!
移植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 了。
CAN 通信测试
正点原子的I.MX6U-ALPHA 开发板上只有一个CAN 接口,因此我们还需要另外一个CAN设备,可以使用另一块I.MX6U-ALPHA 开发板,或者USB 转CAN 设备,这里我两个都测试一下。
1、两块ALPHA 开发板连接测试
准备两块ALPHA 开发板,然后将CAN 接口连接起来,ALPHA 开发板上CAN 接线端子如图66.4.4.1 所示:
将两个开发板的CAN 接口连接起来,注意,CAN_H 接CAN_H,CAN_L 接CAN_L!
①、收发测试
首先使用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 所示:
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 后台接收数据
按照USBCAN 说明手册设置好USB CAN 卡,速度设置为500Kbit,首先通过USBCAN 向ALPHA 发送数据,发送的数据如图66.4.4.5 所示:
从图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 接口,使用方法类似网络通信,本教程不讲解应用编程。