一、CAN的发展
1.经典CAN
1986年2月,Robert Bosch公司在 SAE(汽车工程协会)大会上介绍了一种新型的串行总线––CAN控制器局域网,那是CAN诞生的时刻。今天,在欧洲几乎每一辆新客车均装配有 CAN局域网。同样,CAN也用于其他类型的交通工具,从火车到轮船或者用于工业控制。 CAN已经成为全球范围内最重要的总线之一甚至领导着串行总线。
在底特律的汽车工程协会大会上,由 Bosch 公司研究的新总线系统被称为“汽车串行控制器局域网”。Uwe Kiencke、Siegfried Dais 和MartinLitschel 分别介绍了这种多主网络方案。此方案基于非破坏性的仲裁机制,能够确保高优先级报文的无延迟传输。并且,不需要在总线上设置主控制器。此外CAN 之父——上述几位教授和 Bosch 公司的 Wolfgang Borst、Wolfgang Botzenhard、Otto Karl、Helmut Schelling、Jan Unruh 已经实现了数种在 CAN 中的错误检测机制。该错误检测也包括自动断开故障节点功能,以确保能继续进行剩余节点之间的通讯。 传输的报文并非根据报文发送器/接收器的节点地址识别(几乎其它的总线都是如此),而是根据报文的内容识别。同时,用于识别报文的标识符也规定了该报文在系统中的优先级。
当关于这种革新的通讯方案的大部分文字内容制定之后,于 1987 年中期,Intel 提前计划 2 个月交付了首枚 CAN 控制器:82526,这是 CAN 方案首次通过硬件实现。仅仅用了四年的时间,设想就变成了现实。不久之后, Philips 半导体推出了82C200。
这两枚最先的 CAN 控制器在验收滤波和报文控制方面有许多不同。一方面,由 Intel 主推的 FullCAN 比由 Philips 主推的 BasicCAN 占用较少的 CPU 载荷;另一方面, FullCAN器件所能接收的报文数目相对受到限制,BasicCAN 控制器仅需较少的硅晶体。今天的 CAN 控制器中,后辈们在同一模块中的验收滤波和报文控制方面仍有相当的不同,制造出 BasicCAN 和 FullCAN 两大阵营。
2.时间触发TTCAN
传统的CAN是基于事件触发的,信息传输时间的不确定性和优先级反转是它固有的缺陷。当总线上传输消息频率不高时,这些缺陷相对影响较小;但随着发送频率的不断增加,性能会急剧下降。
为了满足汽车控制对实时性和传输消息密度不断增长的需要,改善CAN总线的实时性能非常必要。于是,传统CAN与时间触发机制相结合产生了TTCAN(Time-Triggered CAN),ISO11898-4己包含了TTCAN。 TTCAN总线和传统CAN总线系统的区别是:总线上不同的消息定义了不同的时间槽(Timer Slot)。
3.高速的CAN FD
2011年初,通用汽车和博世开始着手开发一些有关提高吞吐量的CAN协议。当将越来越多的软件包下载到电子控制单元(ECU)时,汽车行业尤其受苦。高性能通信系统必须缩短这项耗时的任务。通过引入第二个比特率来提高CAN传输速度的想法并不新鲜。自2000年初以来,已有几位学者发表了研究方法。但是,没有一个研究者能够说服汽车制造商。博世与其他CAN专家合作,预先开发了CAN FD规范,该规范于2012年在德国哈姆巴赫城堡举行的第13届国际CAN会议上正式推出。
4.更高速CAN XL
2020年的第17届国际CAN大会(ICC)上,第三代CAN通信技术CAN XL将启动。
CAN XL提供一个最大2048字节的数据字段(例如IP(Internet协议),甚至可以传输完整的以太网帧)。11位优先级字段可由网络层用于寻址和指示数据字段的内容。此外,CAN XL协议为使用的下一个更高协议提供8位指示符,其嵌入式层设置参数对于其他高层协议也很有帮助,以简化多协议堆栈。 CAN XL帧通过两个CRC(循环冗余校验)进行保护,其Hamming距离为6,这意味着可以检测到五个随机分布的比特错误。
CAN XL是一种高度可扩展的通信技术,涉及比特率和数据字段的长度。物理层仍在开发中,目标是实现高达10+ Mbit / s的比特率。 CAN XL针对面向区域的异构网络体系结构进行了优化。该方法以最优的长度满足未来车载网络的要求。汽车工业试图减少布线,以最小化重量,或者换句话说,是限制能耗。
CAN-XL与CAN-FD一样具有两个比特率相位。在仲裁阶段,经典CAN和CAN FD一样,比特率被限制为1 Mbit / s;在数据阶段,由于只有一个节点正在传输,因此可以提高比特率。
二、CAN的特点
1.串行异步通信
串行和并行的区别就是一次性发送的位数;并行是把字符编码的各位(比特)同时传输,而串行则是将组成字符的各位一个一个地发往线路。
下图显示,上面的一次性可以发出三个Bit,而下面一次性只能发一个Bit。
异步通信,总线里并没有时钟;这个很好理解区分。举一个代表,SPI是串行同步通信,发送方和接收方共享一个时钟。而CAN里没有时钟,所以是异步。
2.优先仲裁功能
多个控制模块通过CAN控制器挂到CAN-bus上,形成多主机局部网络;网络通信重要的就是总线的使用权,谁使用总线才可以通信。那么总线总裁是一个很重要的功能,决定着哪个模块拥有总线使用权;必须要有相应的总裁机制。其中CAN的总裁机制十分巧妙,是根据仲裁段的标识符决定接收或屏蔽该报文。
实现原理:采用逻辑与功能,0&0=0,0&1=0,1&0=0,1&1=1。在仲裁段里连续判断发送的位和采集的位是否一致;一致说明当前时刻是本节点优先级更高,不一致则说明是其他节点优先级高,直接退出争夺总线使用权,等待下次。通过上面的逻辑与功能,可以发现0越多,那么优先级越高。参考下面例子:
节点 | 总线状态 | 继续 | 仲裁 BitA | 仲裁Bit9 | 仲裁 Bit8 | 仲裁Bit7 | 仲裁 Bit6 | 仲裁Bit5 | 仲裁 Bit4 | 仲裁Bit3 | 仲裁Bit2 | 仲裁Bit1 | 仲裁Bit0 |
总线值 | 0/1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | |
A | 0 | 否 | |||||||||||
B | 0 | 否 | |||||||||||
C | 1 | 是 | 0 | 0 | 0 | 0 | 1 | ||||||
D | 1 | 是 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 |
E | 1 | 是 | 0 | 1 | |||||||||
F | 1 | 是 | 1 |
其中只有节点D获取总线控制权,优先发送节点D,CANID是0x01D。
第二优先级是节点C,CANID是0x040。
第三优先级是节点E,CANID是0x100。
第四优先级是节点F,CANID是0x400。
所以CANID越小,优先级越大,仲裁级别高。
3.抗干扰能力强
通过CANH、CANL双线之间的差分信号传递数据,可以有效抵抗电磁干扰。
简单地说,干扰磁场会改变两根线的电压,但对两根线的作用基本相同,那么两根线的压差就不会变,还是干扰之前的值。
4.可靠检错机制
这检错校验机制在CAN控制器里实现的,通过分析CAN报文的组成部分,可以看到有一个CRC校验数据,通过CRC值来判定数据在传输过程中有无丢失。下图是标准帧的格式,其中CRC值共占用了15个Bit,校验发送过来的数据。
名字 | SOF | CANID | RTR | IDE | R0 | DLC | DATA | CRC值 | CRC 界定符 | ACK值 | ACK 界定符 | EOF |
Bit位 | 0 | 1-11 | 12 | 13 | 14 | 15-18 | 19-82 | 83-97 | 98 | 99 | 100 | 101-107 |
长度 | 1 | 11 | 1 | 1 | 1 | 4 | 64 | 15 | 1 | 1 | 1 | 7 |
显隐性 | 显 | 隐 | 显 | 显 | 隐 | 隐 | 隐 |
由以下部分组成,仲裁领域、控制领域、 数据字段、CRC领域、ACK字段;
如果想要干扰CAN报文,也可以从以下入手;干扰填充错误、位错误、ACK响应错误、界定符错误。本来此时刻是1,干扰设备强行发出0,两者碰撞结局是CAN线上是0,从而达到干扰。不能干扰Data数据域,数据具体是0还是1无从判断,其余都是固定的格式。
CAN显性超时:当TXD一直是显性(输出逻辑电平0)时,会一直占用CAN总线,导致其他节点无法使用CAN网络。因此收发器要有最大规定时间发出显性。规范要求最多连续发出11个显性位。
5.自动重发机制
发送的信息遭到破坏后,可自动重发。这里使用了CAN总线应答的机制,CAN的发送是个双向互动过程,发送节点在发送数据的同时会对总线上数据进行回读以及ACK场的判定;接收节点在发送节点发送过程中需及时确认报文正确性并令总线上ACK位置 “显性”,以告知发送节点数据正常接收;
6.自动退出功能
节点在错误严重的情况下具有自动退出总线的功能;
7.广播机制
报文不包含源地址或目标地址,仅用标志符来指示功能信息、优先级信息。接收的标识符只要符合设定,都会接收数据。
三、CAN的组成
CAN全称是控制器局部网络,既是一个通信协议,有物理媒介,也有一些概念名词;例如CAN FD、CANID、收发器等等,很多人都容易搞混淆。就像串口、RS485、RS422之间的关系,初学者都很容易混淆。
CAN主要有CAN总线、CAN收发器、CAN控制器三个物理媒介组成。其中,总线和收发器都是肉眼可见的,控制器都是处于芯片内部,属于集成电路,肉眼无法看到罢了。
1.CAN总线
CAN总线是一个使用非归零(NRZ)编码的两线制差分总线,由两根双绞线组成而成。
1.1.显隐性
CAN总线是根据差分电压来传递数据的;这符合大多数串口通信。其中两根线分别是CAN H、CAN L,其中正常情况下CAN H的电压有2.5V、4V两种情况;CAN L有2.5V、1.5V两种情况。
但CAN总线只有两种状态:显性、隐性。
个人脑补理解:显性是指总线处于被控制状态,隐性是指总线处于空闲状态,这个跟1==True、0==False一样的理解。控制状态下需要设置两根线有两个电压水平,消耗更多能量;而隐性状态下只需要让两根线保持一个电压即可,消耗能量较少;因为消耗更多能量肯定不是常有现象,所以默认状态设置为隐性。
显性是控制状态,隐性是空闲状态,又是怎么和逻辑0、1关联上呢?常理上都认为1代表控制,0代表空闲。这里用到了上面仲裁的原理,0和1之间的优先级,0比1优先级更高,那么0就代表着控制,1就代表了空闲。
显性--控制状态--有压差--能量高--优先级高--逻辑0
隐性--空闲状态--无压差--能量低--优先级低--逻辑1
状态 | 隐性状态 | 显性状态 |
CAN H电压 | 2.5V | 3.5V |
CAN L电压 | 2.5V | 1.5V |
差分电压 | 0V | 2.5V |
逻辑数值 | 1 | 0 |
排查问题时可以用示波器查看CANH、CANL之间的压差,无数据压差为0,有数据压差2.5V左右。
1.2.波特率
串口通信的属性之一,双方约定好发送数据的速度,才能及时有效地接收数据。
CAN的波特率常用500Kbit/s,即一秒发送500*1000个Bit,那么一个Bit就用2us,这个2us的时间就是发送接收一个位的时间,简称位时间。不同的波特率就有不同的位时间。
1.3.采样率
当发送方在一个位时间里发送了Bit1,那么接收方什么时候接收1,也就是采集这个电压?是在2us里的前半部分还是后半部分?这就涉及到了采样率。
一个位时间又分成四部分:同步段(SS)、传播时间段(PTS)、相位缓冲段 1(PBS1)、相位缓冲段 2(PBS2)。采样率计算公式= ( 1 + PBS1) / (1 + PBS1+ PBS2)。
2.CAN收发器
CAN收发器是什么?为什么会有这个东西?
下图是一个CAN收发器的原理图,右边连接着外部的CAN总线;分别是CANH、CANL。左边连接着CAN控制器。承担着转换信号的作用,把接收过来的差分信号转成单端信号,并通过CAN RX线路传给CAN控制器。反之亦然。
个人脑补:收发器负责处理(Tx、Rx)逻辑数和总线电压(CANH、CANL)之间的转换。将总线的显性状态转成0、隐性状态转换为1。
2.1.TJA1145
在收发器里,使用较多的就是TJA1145,具有CAN局部唤醒功能。大白话就是可以被指定的帧唤醒。
硬件功能:具有本地Wake唤醒引脚、具有INH输出引脚、具有SPI通信通道、常规的CANH和CANL。INH:由TJA1145输出,可以控制主芯片电源。SPI:负责主芯片和TJA1145通信,主要用途由主芯片轮询控制TJA1145状态、TJA1145反馈唤醒状态。
主要配置:怎么让TJA1145进入休眠状态、怎么唤醒TJA1145。
唤醒方式有本地唤醒、CAN唤醒。本地唤醒包括上升沿、下降沿触发;CAN唤醒有两种,一个是无差别唤醒,只要是CAN帧就会唤醒;一个是局域网唤醒,只能是指定内容的帧才能唤醒。其中局域网唤醒功能需要使能,默认是无差别唤醒。
2.2.进入休眠模式
TJA1145想要进入休眠模式必须至少要有一个唤醒事件,要么有CAN唤醒,要么有本地唤醒。如果没有这两个,那么是无法正常进入休眠模式的。下面是进入休眠模式的条件:
- 至少一个常规唤醒事件
- 当前无唤醒事件
- 事件状态位全部清除
注:所以事件寄存器都是可读可写;写0无效,写1清除,读是正常读;
2.3.特定帧唤醒
想实现特定帧唤醒,首先正确配置好要唤醒的特定帧,其次能正常进入休眠模式下。而配置唤醒帧的步骤如下:
- 使能常规唤醒里的CAN wake-up:CWE = 1
- 使能Can选择性唤醒功能:CPNC=1
- 配置Can特定帧的格式:例如ID、DLC和Data。
- 配置正确参数标志位:PNCOK=1
2.4.注意事项
可以屏蔽非预期的CAN FD帧唤醒
写寄存器的时候需要解锁、上锁
Vcc、Vio欠压会让TJA1145强制休眠
策略如下:
- 清除所有捕捉事件;
- 使能CAN唤醒和本地唤醒;
- 关闭局域网唤醒功能,为了立即被唤醒;
- 局域网配置位清除;
3.CAN控制器
上面提到的Inter制作了82526控制器和Philips 半导体推出了82C200控制器,这些就是CAN的控制器,本质上是由与或非等电路组成的集成电路。同时也在滤波上延申出两个方向,那就是Basic CAN、Full CAN,这个后面再做解释。
CAN控制器里有很多的寄存器,包括状态寄存器、波特率寄存器、发送使能寄存器等等,这里面就包含了我们平常听到的名词。在介绍CAN控制器之前,先介绍下芯片里常见的IP概念。
3.1.M_CAN IP
芯片IP 核(Intellectual Property):是具有知识产权核的集成电路芯核的总称,是芯片设计环节中逐步分离出来的经过反复验证过的、具有特定功能的、可以重复使用的、包含特定核心元素的(指令集、功能描述、代码等)集成电路设计宏模块(逻辑或功能单元),可以理解为部分可重复使用的“芯片设计模块”,如 AHB、APB、CAN、SPI、I2C、MIPI、USB、UART内核等,其作用就是在芯片设计环节中降低冗余设计成本,降低错误发生的风险,提高芯片设计效率。根据不同的IP内核,可以实现不同的CAN功能;当前使用比较多的CAN IP内核就是M_CAN。
这个是由博世开发的一个IP核,博世CAN IP可以作为一个独立的CAN控制器,可集成于ASIC或FPGA芯片内部。它支持经典的CAN和CAN FD(具有灵活数据速率)。符合ISO11898-1:2015标准。需要额外的收发器硬件来连接到CAN物理层。报文可存储于模块外部单口或双口RAM,它通过通用主接口与M_CAN相连。根据所选择的集成方式,多个M_CAN控制器可以共享同一个报文RAM,主机CPU通过32位通用接口连接;下面是M_CAN IP的特点。
- 支持符合ISO 11898-1:2015标准的经典CAN和CAN FD
- 最长支持64字节的有效数据,可以更快地传输大数据字段
- Support as CAN FD Light Commander:
- Standardization published in CiA 604-1: CAN FD Light Protocol for responder nodes
- > More information about CAN FD Light
- 多个M_CAN模块可以访问一个共享存储器
- 可连接到8/16/32位通用CPU接口的客户特定主机CPU上
- 比特率最高支持8 Mbit/s,取决于应用和使用的收发器
- 使用17/21位CRC(CAN FD)或15位CRC(CAN)进行安全通信
- M_TTCAN还支持符合ISO 11898-4的时间触发CAN的实时应用。
3.2.TI_MCAN
TI的280039C和英飞凌的TriCore377这两款芯片都是基于博世的MCAN IP进行开发的,所以这两款芯片上关于MCAN操作基本都是一致的,在芯片手册里的介绍布局都差不多,具体可以参考芯片手册(官网直接下载),主要介绍了操作模式、接收处理、发送处理、FIFO通知处理、Message RAM处理。后面的介绍是TI基于M_CAN内核开发的MCAN。
MCAN模块的内部组成有:CAN核心、消息处理、模块接口、RAM接口、RAM内存。
输入部分有:两个时钟、时钟请求停止位、复位请求位、中断请求、CPU总线。
输出部分有:Rx、Tx。
CAN核心:CAN核心由CAN协议控制器和Rx/Tx移位寄存器组成。它处理所有的ISO 11898-1:2015协议功能,并支持11位和29位标识符。
Message Handler:消息处理是一个状态机,控制着移位寄存器和RAM之间的数据传输;处理接收过滤功能和生成中断。
Register and Message Object Access:寄存器和消息对象访问,通过对消息对象的间接访问来提供数据一致性。
Message RAM:属于内存的一部分,是TI官方给MCAN配置的专属内存区域,主要存放接收来的数据和将要发送的数据。数据具有安全保密性,所以用户无法直接对此RAM区域进行操作。
注:此块RAM区域也可以当作普通RAM给用户使用。
RAM Interface:RAM的对外接口,用户只能通过此接口才读取RAM数据或者写入RAM数据。
模块接口:用户的软件可以通过一个32位外围总线接口访问MCAN模块的寄存器。
扩展接口:所有选定的内部状态和控制信号都被路由到这个接口。
Tx、RX:外接CAN收发器。
Interrupt:MCAN模块向中断控制器请求中断接口。
CLK:为MCAN模块提供两个时钟:外设同步时钟(CAN_ICLK)和外设异步时钟(MCAN_FCLK)。
CLK STOP:请求时钟停止恢复位,让MCAN处于休眠、工作状态等。
3.3.主要功能
- 支持CANFD,最多64个字节
- 专用发送缓冲区,最多32个
- 可配置发送FIFO,最多32个元素
- 可配置发送队列,最多32个元素
- 可配置发送事件FIFO,最多32个元素
- 最多64个专用接收区缓冲区
- 两个可配置的接收FIFO,每个最多有64个元素
- 最多有128个过滤器
- 回环、中断、ECC、时钟停止与唤醒支持
- 时间戳计数器
通过上面介绍,MCAN模块的RAM内存很重要,是实现功能的主要载体。MCAN的内存大小是2048KByte,用于存放过滤器、Rx Buff、Rx FIFO0\1、TxBuff、TxEventFIFO。好奇的是为什么过滤器非要放在RAM里,而不是做成寄存器?这样不是更容易理解过滤器吗。
过滤器:可以接收指定标识符数据,并存放在相应区域。
RxBuff,如果过滤器的配置是存放在Rx Buff里,那么New Data寄存器里就会有相应的位置一,可以在中断或者轮询检查。
RxFIFO,如果过滤器的配置是存放在Rx FIFO里,同样检查FIFO Level,判断是否小于水印值来读取数据。FIFO当数据写满的时候,有覆盖、停止写入两种处理。
发送事件FIFO,这个存放发送后证明数据,用于发送确认功能。
TxBuff,可以配置发送的格式:CAN FD还是经典CAN、速率是否可变、是否存储TxEvent、消息标志等等。发送缓冲区的数量是在TXBC里进行配置,后面直接根据发送缓冲区的下标进行使用;当往发送缓冲区的RAM里写好了数据,需要请求发送位置一。每次都是往RAM里写数据,所以写的数据可以是任何,那么一个缓冲区可以发送多次使用、发送多个不用ID数据。
TxFIFO和TxQueue不经常用,暂时略过。
3.4.过滤器
RAM的第一个内容就是过滤器,当接收到一帧报文的时候,控制器就会在过滤器的内存上寻址,只要找到符合条件的过滤器,就会把数据存放在过滤器要求的位置里。接收过滤器可以有1-128个,每个过滤器都有三种过滤方案:范围过滤、特殊ID过滤、经典位过滤,可以把数据存放在专属缓存区或者FIFO0、1里面。所以自由度很高,可以配合使用满足需求。
过滤器由四个部分组成,分别是SFT、SFEC、SFID1、SFID2。SFT指定过滤方式,SFEC指定存储位置。SFID1、2就是Filter ID1、2,但是这两个在不同的过滤、存储配置下,代表了不同的意思。
如果配置数据存放在Rx Buff,过滤方式则无效,系统默认选择经典过滤,ID1就是必须匹配的标识符,没有掩码可以使用。SFID2的前五位Bit是存放专属缓存区的偏移量,也就是Rx Buff的下标。配置数据:SFEC=0x7;SFID1=过滤ID;SFID2=RxBuffIndex;然后将这个过滤器写进RAM里,写进RAM的位置下标(StdFilterIndex)建议跟RxBuffIndex一致,
如果存放在FIFO里,三种过滤方式都支持,SFID1、2都是过滤ID。
如何配置?参考下图:
过滤器0是经典过滤,它接收的数据存放在RxBuff0里,因为SFID2指定存放在下标为0的RxBuff里。
过滤器1也是如此,数据存放在RxBuff1里,SFID2指定存放在下标为1。
过滤器2是接收FilterID1到FilterID2之间的ID,并存放在FIFO0里。
过滤器3是接收FilterID1和Filter2两个ID,并存放在FIFO1里。
过滤器4是拒绝FilterID1到FilterID2之间的ID。
3.5.发送事件
当发送一帧报文后,需要给上层发送CanIf_Comfirmation,因此需要用到发送存储事件。按照之前的控制器,都是有发送成功中断的,在中断里进行处理,但增大了中断使用率。现在的MCAN控制器每当成功发送一帧后,可以自主选择是否存放发送事件FIFO里,然后再轮询里读取发送成功的数据,再进行相应的处理。
上面提到这个存放TxEventFIFO里是可以配置的,在Tx Buff Element里的EFC置1则存储。同时存放的数据也很多,包含标识符ID、时间戳、消息标志(MM)等等。具体数据参数芯片手册里的介绍。
从TxEventFIFO里读出数据后,需要把读出来的GetIndex写入Acknowledge寄存器里。
3.6.中断
MCAN本身有很多的中断源,一共有30个。这30个中断共用两跟中断线,中断线连接着中断处理器。
中断信号有很多,主要有BusOff中断、Rx Buff接收到新数据中断、Rx FIFO接收到新数据中断、Rx FIFO到达水印中断、Rx FIFO满中断、Tx Buff发送成功中断、Tx Buff取消发送成功中断、TxEventFIFO有新数据接收、TxEventFIFO到达水印、TxEventFIFO满中断。
其中发送成功中断(TC)需要使能TxBTIE里的位,可以使能32个Buff里的任意。
四、CAN的开发
此部分参考Specification of CAN Driver AUTOSAR Release 4.2.2版本,学习CAN的规范设计,掌握稳定的底层架构。 开发不仅涉及到CAN控制器的配置,也涉及到如何实时有效处理各种事件;中断处理、溢出处理、超时处理、状态处理等等。
路线:
1、研究4.2.2的规范文档,明白CAN的数据类型、接口名称、与其他模块的关联调度、错误处理、CanConfig架构;
2、使用EB配置CAN;
3、研究CAN代码;
1.名词介绍
缩写 | 描述 |
CAN Hardware Unit | 一个CAN硬件单元可以由一个或多个CAN控制器组成 |
CAN Controller | 一个CAN控制器只服务于一个物理通道 |
CAN Hardware Object | 一个CAN硬件对象可以理解为一个PDU缓存区,PDU缓存区位于CAN硬件单元的RAM区 |
HOH | Hardware Object Handle 硬件对象句柄:硬件发送句柄+硬件接收句柄 |
HTH | Hardware Transmit Handle 硬件发送句柄,包含一个或多个CAN Object |
HRH | Hardware Receive Handle 硬件接收句柄,仅包含一个CAN Object |
CAN L-PDU |
Can Protocol Data Unit
协议数据单元,包含一个标识符ID、一个DLC、一个数据SUD,此部分只针对CanDriver。
|
CAN L-SDU | CAN Service Data Unit。 是L-PDU发送里的数据。这个只针对CAN IF的上层。 |
有一说一,这些概念是很难搞懂的,需要慢慢理解。首先CAN Controller很容易理解,对应着一个物理通道,也就是一个TX和RX组成的节点。我们都知道CAN控制器里有RAM内存,用于存放发送、接收的CAN ID、DLC、Data三个数据。在不同的架构对这些RAM有着不同的处理,像Basic CAN就是把多个RAM集中在一起管理,同时用于发送或接收。而Full CAN是管理单个RAM,专门用于接收或者发送。管理一个RAM和多个RAM有以下区别:
多个RAM可以接收多个任意的ID报文,可以都一样,也可以都不一样。但是接收了第一个报文之后,不能立即做出处理,要等多个RAM都接收到才行;所以处理速度慢。但是可以接收多个相同ID的报文,具有缓冲作用!
单个RAM只要接收指定ID报文,就可以立即做出动作,处理速度快。只能接收一次数据,没有缓冲区作用。
上面单个RAM存放一个ID、一个DLC、一个Data,官方称之为L-PDU。对于接收,一个L-PDU就是一个HRH;对于发送,一个或多个L-PDU是一个HTH。HRH+HTH为Hardware Object,是由多个L-PDU组成的。
硬件对象除了ID、DLC、SDU三个数据,还有其他的配置参数;例如CanHandleType、CanIdType、CanObjectId、CanObjectType、CanHwFilter等等。这几个有些是配置寄存器的参数,有的是为了方便管理的ObjectId概念。共同组成了CAN Driver里的最小单元!
2.功能规范
CAN模块应该使用OScounter计数,防止硬件不会在预期的时间内做出反应(硬件故障),以防止无穷无尽的循环。同时CAN模块的上锁时间要小于主函数周期。超时处理方法:定义一个变量,获取当前OSCounter1;判断处理时刻的OSCounter2是否超过OSCounter1+设定值。
Can模块有一个非常简单的状态机,有两个状态:CAN_UNINIT和CAN_READY;
CAN控制器有四种状态:Uninit、Stopped、Start、Sleep。
CAN模块要有几个必要的接口,CAN_Init、CAN_SetBaudrate等等
CAN模块的状态被两个外部事件改变:Busoff、WakeUp。这些事件通过中断或通过在Can_MainFunction_BusOff或Can_MainFunction_Wakeup中轮询的状态位来表示。
CAN的状态机跳转条件:默认Stopped
支持CAN FD。
3.API接口
API的接口名称都是固定不变的,但是里面的实现方法都是根据具体的CAN控制器开发的;这个也是MCAL的优势,方便平台移植。那具体的实现代码大多数都是工具生成,但是也要能看懂才行。下面列举了规范里所要求的接口函数。
3.1.Can_Init()
包含全局初始化、内核初始化;全局初始化里实现CAN控制器外部之间的功能初始化,包括时钟、中断!内核初始化实现CAN的全局变量初始化、轮询CAN控制器初始化。CAN控制器初始化包括中断线选择、进入初始化模式、设置配置改变使能、设置波特率、设置CAN ID Filer、设置RxMsgObj的参数(FIFO的水印等)、设置TxEvent参数、BusOff处理模式、设置CAN停止模式、设置CAN全局状态。
3.2.Can_DeInit()
反初始化
3.3.Can_SetBaudrate()
设置波特率
3.4.Can_CheckBaudrate()
改变波特率
3.5.Can_SetControllerMode()
设置CAN控制器状态,在Uninit、Stopped、Start、Sleep跳转。如果控制器不支持Sleep模式,就直接Stopped。
3.6.Can_SetIcomConfiguration()
公共配置参数
3.7.Can_GetVersionInfo()
获取版本信息
3.8.Can_EnableControllerInterrupts()
直接使能中断使能寄存器里响应的位,这个使能无关CAN寄存器是否初始化、全局中断是否开启、CAN中断线是否使能。大多数使能BusOff Interrupt、TxEvent Interrupt、DedicatedBuffs Interrupt、FIFO0Watermark Interrupt、FIFOFull Interrupt。
3.9.Can_DisableControllerInterrupts()
禁止中断
3.10.Can_CheckWakeup()
检查唤醒
3.11.Can_Write()
函数里主要判断状态、获取控制器下标、HTH下标等等;内联一个发送Object函数,它主要操作发送具体的数据和功能;根据配置参数选择CAN FD、是否产生TxEvent、数据长度、数据帧的格式、记录MassageMarker、请求发送位。
3.12.Can_MainFunction_Write()
判断是否是Polling,处理发送事件,读取Event的MM、Get Index;写入Acknowledge,并引用CanIf_TxConfirmation。
3.13.Can_MainFunction_Read()
判断是否是Polling,轮询模式下,一直读取FIFO的Fill Level、NewData位。如果有数据,读取出来,并引用CanIf_RxIndication()。
3.14.Can_MainFunction_BusOff()
判断是否是Polling,检查CAN是否处于BusOff状态,是即取消所有发送请求位,设置CAN状态为Stopped,并引用CanIf_ControllerBusOff()。
3.15.Can_MainFunction_Wakeup()
检查是否支持Wakeup功能,获取CAN数据,判断是否有唤醒报文,有则上传CanIf。
这里的休眠是指功能的休眠,并非掉电休眠,整个芯片还是在电工作的。
3.16.Can_MainFunction_Mode()
掌管CAN的模式、状态机跳转。Uninit、Stopped、Start、Sleep。动不动就Stopped
下面是非标准的函数,但是建议有,便于理解
3.17.Can_IsrBusOffHandler()
BusOff中断服务函数,被CAN的总中断服务函数引用。Bus Off触发的中断,读取中断状态寄存器里的BO位进行数据处理。引用CanIf_ControllerBusOff()。
3.18.Can_IsrReveiveHandler()
接收专属缓冲区的中断服务函数,被CAN的总中断服务函数引用。专属Buff接收到数据触发的中断,根据New Data进行处理数据
3.19.Can_IsrRxFIFOHandler()
FIFO的中断服务函数,被CAN的总中断服务函数引用。FIFO状态到达水印或者溢出触发的中断,也可以是FIFO进入新数据触发中断。
3.20.Can_IsrTransmitHandler()
发送处理中断服务函数,被CAN的总中断服务函数引用。可以是发送成功触发的中断,也可以是发送事件的中断。发送事件需要将读取的GetIndex写入Acknowledge。
4.EB配置
CAN配置分为常规配置、参数配置两部分,常规配置都是一些属性类的参数;参数配置包含了CanController配置和CanHardwareObject配置。通过上面的概念可以很轻松地理解这两个!
CanController配置包含了接收、发送、BusOff中断还是轮询的处理方式、寄存器基地址、波特率设置和唤醒功能。
CanHardwareObject包含了处理类型(Full、Basic)、Object类型(发送、接收)、CanId类型(标准、扩展)、HwFilter(过滤ID、Mask)、隶属哪个控制器。
4.1.CanGeneral
常规配置:这部分主要是错误检查、主函数的周期、超时时间配置,具体看下图!
4.2.CanController
CanController的配置参数不是很多,其中CanControllerId是控制器下标,当有多个控制器时,使用下标来区分;CanControllerBaseAddress是MCMCAN模块的起始地址;CanControllerBaudrateConfig这个参数决定着CanController波特率,并且也决定着是否使能CAN FD的功能。
CanControllerBaudrateConfig:有General、CanControllerFdBaudrateConfig组成。前者决定经典CAN的波特率;后者决定CANFD的波特率,设置参数即按照参数使能FD、配置波特率,不设置参数即关闭FD。
4.3.CanHardwareObject
这个是重中之重,CanHardwareObject里主要看General、CanHwFilter两部分。
CanHandleType:设置处理方式,是Full还是Basic。CanObjectType:是发送还是接收。CanIdType:标准帧还是扩展帧。ObjectIdType:是区分多个Object的下标,很重要。CanControllerRef:是指当前Object隶属哪个控制器。
CanHwObjectCount:用于实现一个HOH的硬件对象数量。在HRH的情况下,这个参数定义了硬件FIFO中的元素数量或阴影缓冲区的数量,在HTH的情况下,它定义了用于多路传输或用于FullCAN HTH的硬件FIFO的硬件对象数量。
CanHwFIFOThreshold:basic处理方式下接收FIFO触发中断的水印值。
CanHwFliter:硬件过滤,有Code和Mask两部分组成;用于过滤CANID。
5.代码架构
EB生成的代码粗涩难懂,全是结构体指针入参,很多的宏定义开关,变量过多,又要支持多核操作(给每个内核申请数组,存放数据),太难看了。其中结构体配置参数是总结了EB里的所有配置,哎,也不是很好看,下面是我自己手写的精简版代码,概括了EB配置的选项。
CanConfig:包含了CanController、CanHardwareObject、HOHConfig三个指针。HOHConfig包含了发送、接收Object的个数和下标。
下图是官方Autosar给的配置参数大纲图:大体上跟EB上一致;后面的每个配置请参考官方文档,写的很详细。
五、CAN的使用
CAN的应用有很多,涉及在汽车、医疗、工业等等;根本还是在8个、64个字节处理数据,处理多了就会诞生不少标准协议,例如汽车领域的诊断、标定功能;
1.XCP
XCP是一种标定的协议,这里介绍是基于XCP调试的方法。
最近经常遇到程序卡住、死机的现象,又因为控制器已经装车了,导致无法使用调试器在线调试,无法快速分析问题。所以就想着另辟蹊径,能不能通过CAN线路来调试CPU及其寄存器。这样就可以实时定位程序,知道程序如何工作的;同时也可以监控其他系统数据,十分方便快捷。
在网上查到可以使用VX1000设备,基于XCP协议对芯片调试。这种解决方案需要在硬件上嵌入一个POD芯片;通过这个POD芯片把数据上传给VX1000设备,再传递给PC端。似乎可行,又似乎多此一举。因为POD芯片也是需要接口才能连接上VX1000的,既然都增加了一个接口,这个接口直接是仿真调试口又如何?
当前大多数的控制器只有两路CAN对外通信,分别是整车CAN、标定CAN。标定CAN使用率没有整车CAN高,所以可以基于标定CAN对外上传CPU等信息。
这种方法算是伪debug,因为只能按照协议来查看变量、修改变量,没有其他在线调试的功能。所以这个的必要性有待商榷,算是个可行的方法。
2.UDS诊断
这个内容算是入门知识了,UDS诊断功能挺简单的,根据协议来发送读取报文数据。
3.私有协议
每个人都可以在8个字节上做一些协议处理,双方约定好即可。