本文主要介绍Infineon Aurix2G TC3XX系列芯片CAN模块硬件原理,以及MCAL相关配置,和代码示例实现。
1 模块介绍
CAN总线是一种广泛应用于汽车、工业控制和其他领域的串行通信协议。CAN总线是Controller Area Network的缩写,最初由德国的Bosch公司开发,用于汽车电子系统之间的通信。CAN总线具有高可靠性、抗干扰能力强和实时性好等特点,因此被广泛应用于需要可靠数据传输的领域。
CAN 2.0B协议中的CAN最多支持29位ID,但是网络架构中使用的一般是11位的标准帧ID。下面是标准CAN FD帧数据结构:
关于CAN协议相关的内容,本文不作阐述,建议读者自行查阅资料,以便更好地理解本文中的CAN硬件原理。
Aurix2G TC3XX系列的CAN模块称为MCMCAN,集成的是Bosch的M_CAN内核,最多集成了3个CAN Module,每个CAN Module包含4个CAN节点(M_CAN)。支持ISO 11898-1&-4协议,支持SAE1939协议,支持最高单帧64字节的CANFD传输,支持5Mbit/s的波特率,且在时钟高达80MHz的情况下可扩展至8Mbit/s。
2 功能介绍
2.1 CAN硬件框架
这里我们首先介绍下车载CAN网络在控制器级别的硬件框架,下图是控制器端的结构示意图。
在CAN控制器节点中,一般MCU中集成了CAN控制器,同时节点配备板载CAN信号收发器,也就是Can Transceiver,CAN控制器和CAN Transceiver之间通过TX和RX进行数据交互。MCU通过IO控制Transeiver的状态,以及状态回读。
Transceiver则通过CAN_H和CAN_L连接到整车的CAN网络上,通过差分信号进行数据交互。
另外对于具备休眠唤醒的Transceiver,存在一些电源控制连接,此处就不展开说明了。
2.2 CAN时钟
作为通信模块,我们先来看CAN模块时钟相关连接。
TC3XX CAN模块有两路主时钟源,来自系统的CCU模块。其中fMCANH是CAN模块主时钟,决定CAN模块工作及CAN RAM访问速度,通过CCUCON5.MCANHDIV来进行配置;fMCAN是CAN模块时钟,用来配置CAN的波特率,必须小于fMCANH,通过CCUCON1.MCANDIV来进行配置。
在每个CAN Module内部,fMCANH连接fSYN,fMCAN连接fASYN,和其他外设模块一样,CAN模块时钟可通过时钟控制寄存器(CLC)关闭。
然后CAN模块内部每个Node的时钟都可以通过MCR.CLKSELi进行独立控制,此处不分频。
fASYN作为CAN总线波特率的基准时钟,推荐配置位80, 40, 20 MHz,以与节点波特率取整倍数。
2.3 波特率及采样点
波特率及采样点的设置涉及到同步段Sync_Seg、传播段Prop_Seg、相位缓冲段Phase_Seg等。
fASYN时钟到达CAN模块之后,通过设置DBTP.DBRP进行分频,得到CAN时钟。
波特率的计算公式为:
采样点的计算公式为:
M_CAN中,DBTP.DTSEG1等于传播段、相位缓冲段1长度的和减1(无需分开配置),DBTP.DTSEG2等于相位缓冲段2的长度减1。DBTP.DSJW等于同步跳转宽度减1。同步段为固定值1。
2.4 MCMCAN总览
TC3XX中一个CAN Module包含4个M_CAN Node,其芯片框图如下图所示:
从图中我们可以看到每个CAN Module有一块公有的RAM,称为Message RAM。因为CAN模块需要一块额外的RAM用于数据的收发和控制等,这个是由芯片厂商来实现的,比如在TC3XX系列中,Message RAM就集成在CAN模块外设地址起始位置。每个CAN Node有Host IF和Memory IF与主机(CPU)相连,同时通过TX/RX与外部进行信号交互。
然后我们把CAN Node展开,该部分为Bosch IP内核,每个M_CAN Node的框架如下图所示:
从图中可以看到,CAN模块作为从机通过Host IF接口接入到芯片内部的Host(TC3XX中即CPU),Host通过控制CAN模块的寄存器来进行控制交互。CAN模块还作为主机通过Memory IF接口接入到Message RAM,用于存取传输数据。
CAN Core
CAN协议内核控制器,接收、发送移位寄存器,支持ISO 11898-1:2015协议功能,支持11位和29位CAN ID。
Sync
用于在CAN Core和Host之间进行时钟同步。
Clk
时钟管理模块。
Cfg&Ctrl
CAN Core及相关模块的控制和配置位。
Interrupt & Timestamp
中断控制和16位CAN位时间计数器用于接收和发送时间戳的生成。
Tx Handler
控制从Message RAM到CAN Core的消息传输。最多可配置32个Tx Buffers用于传输。Tx缓冲区可以用作专用Tx Buffer、Tx FIFO, Tx Queue的一部分,或作为它们的组合。一个Tx事件FIFO存储Tx时间戳和相应的消息ID。M_CAN还支持发送取消。
Rx Handler
控制从CAN Core到Message RAM的接收消息的传输。Rx处理程序支持两个Rx FIFO,每个都是可配置的大小,以及多达64个专用的Rx Buffer,用于存储已通过接受过滤的所有消息。一个专用的Rx Buffer,用于仅存储具有特定标识符的消息。Rx时间戳与每条消息一起存储。最多可为11位ID定义128个过滤器,最多可为29位ID定义64个过滤器 。
Generic Slave Interface
将M_CAN连接到客户指定的主机CPU。通用从属接口能够连接到8/16/32位总线,以支持广泛的互连结构。
Generic Master Interface
将M_CAN访问连接到外部32位Message RAM。最大Message RAM 大小为16K*32bit。单个M_CAN最多可以使用4.25K*32bit。
Extension Interface
中断寄存器IR的所有标志以及选定的内部状态和控制信号都路由到这个接口。该接口用于M_CAN与模块外部中断单元或其他模块外部组件的连接。这些信号的连接是可选的。
2.5 Message RAM
Message RAM,也就是CAN RAM,这里我们先介绍CAN RAM在内存中的结构,以方便读者理解CAN模块的收发逻辑。(TC3XX系列中一个CAN Module的4个Node共享一块RAM)
CAN RAM是32位宽格式,用于存储CAN的接收过滤配置、收发数据。其在内存中的结构如下:
图中可以看出,CAN RAM被划分为多个块,每个块都有特定的寄存器指示其相对于CAN RAM的地址偏移。比如Tx Buffers块的绝对地址等于CAN RAM StartAddr+TXBC.TBSA。
CAN RAM中每个块都有自己的数据格式定义,CAN手册中有详细说明,下面我们会以11-bit Filter和Tx Buffers举例说明。
另外需要注意的是,TC3XX中每个CAN Module中的4个CAN Node是共用一块CAN RAM的,因此在资源数量分配时,如果控制器需要的CAN节点数量没有超过CAN Module数量时,尽量使用不同CAN Module中的Node。
2.5.1 Standard Message ID Filter Element
我们知道,CAN ID有11bit的标准ID,还有29bit的扩展型ID,因此CAN模块的ID过滤器有两种。Standard Message ID Filter Element,即上图中的11-bit Filter。
一个标准过滤器(Filter Element)占一个Word(4字节),我们可以通过寄存器SIDFC.FLSSA获取过滤器区域在CAN RAM中的相对地址偏移,通过SIDFC.LSS获取过滤器的数量。(SIDFC.FLSSA在2~15位,低位需要扩展两个bit的0)
标准过滤器的结构如下:
SFT:Standard Message ID Filter Element,标准过滤器过滤类型
00= 范围过滤,SFID1到SFID2之间 (SFID2 ≥ SFID1)
01= 双ID过滤,SFID1或SFID2
10= 经典过滤,SFID1 = filter, SFID2 = mask
11= 过滤器关闭
SFEC:Standard Filter Element Configuration,标准过滤器配置,所有过滤器都会被用于接收帧的处理,直到第一个过滤器与之匹配,或者达到过滤器末端。如果SFE=111b,则SFT无视,该帧直接存储到Rx Buffer中;
SFID:Standard Filter ID 1,标准过滤器ID1,在Rx Buffer、同步报文、Debug报文下,ID与之相等的帧就会过滤成功,被存储到Rx Buffer中;
SSYNC:Standard Sync Message,标准同步帧,用于标记是否使能时间戳;
SFID2:Standard Filter ID 2,标准过滤器ID2,该ID在SFEC定义的特殊匹配模式下配合SFID1使用;另外其中SFID[5:0]指示该过滤器引用的Rx Buffer(SFEC为111b时有效);
当我们使用FULL CAN类型的接收帧时,配置SFEC为111b,配置SFID1为目标帧的ID,即可进行接收。
比如这里我使用的CAN RAM地址为0xF0200000,过滤器地址偏移为0,过滤器数量为3,则前3个Word就是我对应使用的3个过滤器,通过上述位域转换可知,分别对应ID为0x111、0x222和0xC,对应的Rx Buffer索引分别为0、1、3。
2.5.2 Tx Buffer Element
Tx Buffer用于处理CAN数据的发送,CPU通过将用户的待发送数据复制到Tx Buffer中,操作CAN发送寄存器,随后CAN模块就从CAN RAM的Tx Buffer中读取数据进行发送。Tx Buffer可用于特定帧Buffer、Tx FIFO以及Tx Queue。
Tx Buffer的数据位宽不是固定的,取决于数据宽度。通过TXBC.TBSA获取Tx Buffer在CAN RAM中的相对地址偏移,通过TXBC.NDTB获取Buffer的数量。
每个Tx Buffer包括两个Word的头和若干数据组成,每个CAN Node的数据长度由TXESC.TBDS获取指定,比如CAN FD一般数据为64字节。其结构如下:
篇幅原因就不展开介绍每个位域了,读者可自行查阅手册。通过Tx buffer,完成了CPU与M_CAN之间的数据交互协议,CPU填写Tx Buffer的头部信息,包括CAN ID、DLC等,以及数据内容,然后操作寄存器进行,CAN模块按照Tx Buffer中的信息和数据进行发送。
假设我们配置数据宽度为64字节,则第n个TxBuffer的内存中的绝对地址为 CanRamStartAddr+TXBC.TBSA+n*(8+64)。
同上我这里的CAN RAM基址为0xF0200000,TXBC.TBSA=0x57,左移两位补齐得到0x15C。
所以0xF020015C就是我使用的第一个Tx Buffer,通过解析得知其发送ID为0x123(T0[28:18]),DLC为8,数据内容为{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }。
2.6 Operation Modes操作模式
2.6.1 初始化
软件需要设置CCCR.INIT,并设置CCCR.CCE(M_CAN配置寄存器仅当该位置位时才可访问),然后开始初始化,此时CAN模块停止收发,错误计数保持不变。然后通过软件配置各项寄存器,以及CAN RAM初始化。
完成寄存器配置后将CCCR.INIT位清除,CCCR.CCE会自动随之清除,以完成硬件配置。
2.6.2 普通模式
当完成寄存器和CAN RAM的配置后,CAN模块会自动与外部收发器进行同步,进入普通工作模式。
对于接收帧的过滤器和Rx Buffer、FIFO等,是在初始化阶段设置的。CAN模块在工作模式下如果收到与之匹配的CAN报文,就会保存到Rx Buffer或者FIFO中。
而发送帧报文的Tx Buffer则是在发送时更新的。
2.6.3 CANFD模式
CANFD(Controller Area Network Flexible Data Rate)模式中有两种变种,一种是常规的CANFD发送模式(BRS==1),即报文中的控制段、数据段、CRC段以较高的波特率进行传输,而帧开头和结尾以普通速度进行传输。另外一种则是所有段都按照普通波特率进行传输。
2.6.4 第二采样点 Transmitter Delay Compensation Measurement
我们知道CAN总线节点在发送过程中,是要对输入信号进行回采的,以进行总线仲裁以及错误判断。如果在一定时间内没有回采到预期值,则会出现位错误。该时间阈值取决于CAN时钟频率。
当使用CANFD时,且配置了较高频率的时钟,就会导致该延时阈值较短,也就是需要硬件在更短的时间进行回读,但硬件的延时相对较为固定,这个时候就容易误报位错误。也就是实际该帧发送正常,但是硬件回读时间大于阈值。
M_CAN针对该特性提供了发送采样延时补偿,也就是我们常说的第二采样点。通过硬件来放宽回读的间隔,且该特性使能后由硬件自动标定,能够对不同时钟频率进行自适应。
2.6.5 受限操作模式Restricted Operation Mode
当总线出现错误或负载过高时,比如发送错误计数ECR.TEC达到一定次数,表示无法往总线发送报文,CAN控制器会进入受限模式。在受限模式下CAN模块停止发送报文,进入监听模式,直到总线空闲,之后CAN模块会重新与总线同步。
Host可以通过设置CCCR.ASM寄存器主动进入受限操作模式。当CAN模块主动或被动进入受限模式,需要清除CCCR.ASM以进行恢复。
2.6.6 总线侦听模式Bus Monitoring Mode
M_CAN模块可以通过设置CCCR.MON进入侦听模式,在侦听模式下,CAN模块的发送被切断,只侦听总线上的报文。
2.6.7 休眠模式Power Down (Sleep Mode)
M_CAN支持硬件休眠模式,通过设置CCCR.CSR寄存器,使CAN模块进入休眠模式。当所有等待发送的报文完成发送,M_CAN会自行设置CCCR.INIT来阻止后续报文的发送,此时M_CAN通过设置CCCR.CSA表征其已经准备好进入休眠模式了,然后Host可以关闭CAN模块时钟。
要退出休眠模式,首先也要启动M_CAN时钟,然后清除CCCR.CSR寄存器。同样M_CAN通过清除CCCR.CSA来表征自己退出休眠模式,然后Host可以通过设置CCCR.INIT,并设置寄存器以重启CAN模块。
2.6.8 Test Mode测试模式
M_CAN模块支持测试模式,通过先将CCCR.TEST寄存器置位来开启。
测试模式有两种,一种是External Loop Back Mode,即外回环模式,通过设置TEST.LBCK为1来实现。在该模式下,CAN模块切断了外界的接收连接,将自己发送的报文视为接收报文,以进行CAN回环测试。在该模式下,CAN忽略总线应答错误。
另外一种是Internal Loop Back Mode,即内回环模式,除了TEST.LBCK,还需要设置CCCR.MON,区别在于该模式下CAN模块的发送连接也被切断,也就是测试模式和侦听模式的组合。
2.7 时间戳功能
M_CAN模块提供了一个内部16位的循环计时器,并且具备一个4位的分频寄存器TSCC.TCP。可通过TSCV.TSC寄存器读取计时器的值。当计时器回滚时,中断标志位IR.TSW置位。
在接收、发送报文的开始时刻,计时器的值会被保存到Rx Buffer、Rx FIFO、Tx Event FIFO的时间戳段中,以实现计时功能。
2.8 接收流程Rx Handling
Rx Handler控制接收过滤,Rx Buffers和两个Rx FIFO接收消息的传输,以及Rx FIFO的Put和Get索引。
2.8.1 接收过滤 Acceptance Filtering
前文提到,M_CAN提供两套过滤器,分别用于对标准CAN ID和扩展CAN ID进行ID过滤。这些过滤器可以被分配到Rx Buffer、Rx FIFO1、Rx FIFO2(通过过滤器中字段进行配置)。当收到一帧报文时,会从对应过滤器列表从头到尾进行匹配。当出现匹配过滤器时,后续的过滤器就不会再执行匹配。
值得一提的是,不同于发送报文,接收过滤器是在初始化阶段由Host配置好的,当初始化完成之后M_CAN按照指定的配置进行接收过滤。
过滤器主要包括以下特性:
支持以下三种过滤模式:
范围过滤(from - to -)
一个或者两个特定ID过滤
经典的按位掩码过滤
过滤器可以配置为接收过滤或者拒绝过滤;
每个过滤器可以独立使能;
过滤器按照顺序依次匹配,出现第一个匹配的过滤器即停止后续过滤。
相关的寄存器包括全局过滤配置寄存器(Global Filter Configuration,GFC),标准ID过滤器配置寄存器(Standard ID Filter Configuration,SIDFC),扩展ID过滤器配置寄存器(Extended ID Filter Configuration,XIDFC),扩展ID&掩码寄存器(Extended ID AND Mask,XIDAM)。
当过滤器与接收报文匹配上时,根据CAN RAM中过滤器的配置(SFEC/EFEC),执行相应的操作:
将接收帧存储到FIFO0或者FIFO1;
将接收帧存储到Rx Buffer;
将接收帧存储到Rx Buffer并在过滤器事件pin上产生信号;
拒绝该帧;
设置高优先级中断标志位IR.HPM;
设置高优先级中断标志位IR.HPM,并将接收帧存储到FIFO0或者FIFO1
当一帧报文到达CAN模块的时候,过滤器的工作流如下图所示(以标准ID帧为例):
从图中可以看出,当一帧11bit ID标准帧到达时,如果不是远程帧且接收过滤器使能了,就会进入过滤器匹配环节。如果没有与之匹配的ID,且配置模式不接收非匹配帧(一般不对非预期帧进行处理),该帧就会被丢弃。如果过滤器中有与之匹配的ID,且所引用的存储空间可用(Rx Buffer或者FIFO),则进行帧存储。
2.8.2 Rx FIFO
我们知道,在AUTOSAR协议中, CAN报文类型在接口层分为FULL CAN和BASIC CAN,FULL CAN表示该报文的处理独占一个硬件资源,也就是Rx Buffer;而BASIC CAN则表示多个接收帧需要共用一个硬件FIFO,并且相同ID的报文可以在FIFO中存储多次,这个FIFO在硬件上就是我们要介绍的M_CAN的Rx FIFO。
每个M_CAN节点有两个Rx FIFO,每个FIFO最多可处理64帧报文。分别通过RXF0C和RXF1C寄存器来进行Rx FIFO的配置。初始化阶段我们通过RXFnC.FnSA配置该FIFO在CAN RAM中的相对地址偏移,通过RXFnC.FnS配置该FIFO的尺寸,也就是最多容纳的报文数量。通过RXFnC.FnWM配置该FIFO的水位线。
当过滤器中的SFEC/EFEC字段指定过滤器的动作为存储到RX FIFO中,在接收帧与过滤器匹配时,就会被存储到指定的RX FIFO中。
RX FIFO的设计采用的是典型的带水位线的Ring Buffer模型。
该模型的状态由M_CAN模块维护,Host可以通过RXFnS寄存器访问。RX FIFO有两个索引,一个是Put索引RXFnS.FnPI,接收到报文后从该位置进行存储,然后将Put索引累加。另一个是Get索引RXFnS.FnGI,Host从该位置开始进行报文读取。还有一个填充指示位RXFnS.FnFL,用来表征当前FIFO里已经有多少报文了。当FIFO满了时(Get索引等于Put索引),FIFO溢出标志位RXFnS.FnF会置位,同时发送IR.RFnF中断信号。
前面提到通过RXFnC.FnWM配置该FIFO的水位线,它的作用是当FIFO中存储的报文数量达到水位线时,产生FIFO中断,即IR.RFnW信号,以促使Host进行接收报文处理。
RX FIFO在CAN RAM中的相对地址偏移分别为RXF0C.F0SA和RXF1C.F1SA。与Tx Buffer形式相同,每个Rx FIFO包含3个Word的头和特定长度的数据,数据尺寸由RXFnC.FnDS决定。
Rx FIFO有两种工作模式,通过操作RXFnC.FnOM来控制。当RXFnC.FnOM=0时,Rx FIFO配置为默认的Block模式,该模式下,如果FIFO满了,将不再接收任何报文。当RXFnC.FnOM=1时,Rx FIFO配置为覆写模式,在该模式下如果FIFO满了,新到的报文将覆盖最旧的一帧报文,并且将两个索引都累加。
2.8.3 Rx Buffer
当我们配置接收帧为FULL CAN时,也就给该帧配置了一个专属的Rx Buffer,用于该帧的报文接收。每个M_CAN最多可配置64个Rx Buffer,其在CAN RAM中的相对地址偏移由RXBC.RBSA指定,Rx Buffer的格式与Rx FIFO完全相同,每个Rx Buffer包含3个Word的头和特定长度的数据,数据尺寸由RXBC.RBDS决定。
在过滤器ID匹配成功时,且过滤器中的SFEC/EFEC为111b(表示帧存储到Rx Buffer中),且SFID2/EFID2[10:9]为0(非Debug帧),则CAN模块将该报文存储到指定的Rx Buffer中,其中Rx Buffer的索引由过滤器中SFID2/EFID2[5:0]位域指定。同时中断标志位IR.DRX (Message stored in Dedicated Rx Buffer)置位,这也就是我们常说的CAN接收中断。
除此之外,接收完成之后,对应的New Data Flag寄存器NDAT1或NDAT2中的位会置位(每个Buffer一个位),在该位被清除前,该Rx Buffer将拒绝数据接收,同时对应的过滤器也停止进行过滤,但是位于该过滤器后面的其他过滤器可以继续对该帧,也就是说该帧可以被存储到其他Rx Buffer或者FIFO中。用户可以通过对该位写1进行清除。
接收的处理流程如下:
清除中断标志位IR.DRX;
读取New Data Flag寄存器确定需要处理的Buffer;
从CAN RAM中读取数据;
清除处理好的Buffer的New Data Flag。
2.9 发送流程 Tx Handling
Tx Handler处理专用Tx Buffers、Tx FIFO和Tx Queue的传输请求。它负责传输报文到到CAN Core,管理Put和Get索引, 以及Tx Event FIFO的传输。不同于Rx Buffer和Rx FIFO有各自的独立资源,在发送端专用Tx Buffer和Tx FIFO、Tx Queue共用32个Tx Buffer。
CAN模块在发送端可以发出三类报文:普通报文、非变速CANFD报文、变速CANFD报文,受节点的CCCR寄存器和每个Tx Buffer内部的配置影响,参照下表。
Tx Handler在每次发送Buffer请求等待寄存器(Tx Buffer Request Pending register,TXBRP)更新时执行依次扫描,然后在CAN RAM中寻找优先级最高(CANID最小的Tx Buffer)的等待中的Tx Buffer开始发送。而TXBRP是在每次有一帧发送完成,或者有用户通过写发送发送Buffer添加请求寄存器(Tx Buffer Add Request register, TXBAR)时更新。也就是说,当发送完一帧,或者用户添加发送请求,Tx Handler就会开始执行发送扫描,寻找优先级高的Tx Buffer然后发送。
2.9.1 发送暂停
CAN总线是无主式通讯,仲裁的依据是CANID。但如果具有高优先级ID的控制器以较高的频率持续发送报文,持有低优先级ID的控制器便无法将报文发出。因此CAN控制器存在一个发送暂停的功能,通过将CCCR.TXP置位来使能。使能之后,该控制器在完成每帧发送之后,会进行两个bit的暂停,以保证低优先级ID的报文能够发送到总线上。
2.9.2 Tx Buffer
每个M_CAN最多可配置32个Tx Buffer,其在CAN RAM中的相对地址偏移由TXBC.TBSA指定,每个Tx Buffer包括两个Word的头和若干数据组成,每个CAN Node的数据长度由TXESC.TBDS获取指定,比如CAN FD一般数据为64字节。Tx Buffer可以用作给特定帧的专有Buffer,也可以组成Tx FIFO、Tx Queue,更可以组成Tx Buffer与FIFO/Queue的混合模式,这种使用较少本文就不加以赘述。但是FIFO和Tx Queue是二选一存在的。
专有Tx Buffer是完全由Host来控制的,每个Tx Buffer指定专有的CAN ID。和接收一样,专有Tx Buffer对应配置中的FULL CAN。以防多个Tx Buffer具有相同的CAN ID,因此Tx Buffer的发送顺序是按照Buffer的序号进行的,低序号的Tx Buffer具有优先发送权,一般也将较小ID的报文分配给靠前的Tx Buffer。每个Tx Buffer都可以通过写TXBAR寄存器中的关联位单独进行发送请求添加。
2.9.3 Tx FIFO
当我们把TXBC.TFQM配置为0,并通过TXBC.TFQS配置一定数量的Tx Buffer用作FIFO,就可以使用Tx FIFO模式进行报文发送,并允许同一个ID的报文多次添加到FIFO中。FIFO的结构同样类似Rx FIFO,有一个Get索引TXFQS.TFGI,和一个Put索引TXFQS.TFQPI,用来指示头和尾。用TXFQS.TFFL来指示当前Buffer空闲数量。
当Host执行发送请求时,Put索引进行累加,当Tx Handler执行发送时,Get索引进行累加。当FIFO满了以后,TXFQS.TFQF置位。
2.9.4 Tx Queue
当我们把TXBC.TFQM配置为1,并通过TXBC.TFQS配置一定数量的Tx Buffer用作Queue,就使用了Tx Queue模式。Queue中的报文从ID小的开始执行发送。当Queue中出现相同ID的Buffer,则先从Buffer序号小的发送。Tx Queue只有一个Put索引TXFQS.TFQPI ,用于指示Queue中序号最小的可用Buffer。
当新的发送请求发送到Tx Queue中,Put索引会自动指向下一个Queue中序号最小的可用Buffer。当Queue满了时(TXFQS.TFQF),Put索引成为无效值,并且后续报文无法添加到Queue中,直到一个报文发出去或者有报文被取消。
2.9.5 发送取消 Transmit Cancellation
M_CAN支持发送取消功能,该特性是专门为AUTOSAR中网关应用程序设计的。为了取消Tx Buffer或者Tx Queue中的pending报文的发送,Host需要向发送Buffer取消请求寄存器(Tx Buffer Cancellation Request register,TXBCR)中的相关位CRn写1。Tx FIFO中的报文无法取消。
取消成功后,TXBCF中的相应位CFn会置位。
如果一帧已经在发送流程中了,如果最终没有取消成功,那么TXBCF和TXBTO中的相应位都会置位,如果取消成功,那么只有TXBCF中相应位置位。
2.9.6 发送事件FIFO Tx Event FIFO
为了支持发送事件处理,M_CAN维护了一套Tx Event FIFO机制。在CAN RAM设置了一块内容,专门保存CAN发送事件的信息。当CAN模块往总线上发送一帧报文之后,报文ID、Message Marker、时间戳等信息就会被保存到Tx Event FIFO中。
这么做的目的是把CAN发送处理和发送事件信息处理分开,好处是当一帧报文发送完成之后,Tx Buffer能够立刻给下一帧使用,尤其是在Tx Queue模式下。
当出现新的Tx Event之后,触发中断标志位IR.TEFN,表示专有Tx Buffer、Tx FIFO有发送完成,一般将该信号用作CAN发送中断。
Tx Event FIFO满了之后会触发中断标志位IR.TEFF。后续的事件便无法继续保存,直到下一次读取发生。
为了避免FIFO溢出,可以使用Tx Event FIFO水位线,通过设置TXEFC.EFWM,当Tx Event FIFO中的事件数量达到了水位线,将中断标志位IR.TEFW置位。
2.10 FIFO Ack机制
前面提到的Rx FIFO0、FIFO1和Tx Event FIFO,它们的Get索引都是通过Ack机制来实现控制的。通过写入指定的Ack寄存器,来将FIFO的Get索引进行累加。比如在从Rx FIFO0中接收报文完成之后,需要在接收FIFO0应答寄存器(Rx FIFO 0 Acknowledge,RXF0A)来修改与该Buffer关联的索引号。
2.11 中断连接
一个M_CAN节点提供了十几种中断,包括前文提到的接收中断、发送完成事件中断等。
首先在M_CAN模块内部,对于每种类型的中断,在中断使能寄存器CAN_N_IE中都有一个专属的使能位。该使能位需要在启动阶段由Host设置(一般在Start Controller时)。
然后在TC3XX的中断路由模块IR中,每个CAN Module分配了16个中断源,也就是说一个Module中的4个Node要共用这16个中断源,每个Node的中断信号与这16个中断源是可以任意连接的,来自这些Node的多个信号也可以连接到同一个中断源中。通过设置Node中的GRINT1和GRINT2来为Node中的中断信号指定中断源。
一般情况下,我们会将16个中断源平均分给4个Node,每个Node使用4个关键中断信号,分别分配给Rx Buffer中断、Tx Buffer中断、BusOff中断和Rx FIFO中断。
2.12 引脚连接
TC3XX中CAN模块与Port的连接也是比较丰富的,对于每个节点都有多组引脚可选为CanRx和CanTx信号。
连接需要指定型号的用户手册(非Family手册),这里我们以TC38X User Manual为例,我们打开手册38.4 MCMCAN Connectivity章节,找到Table 388 Connections of CAN00。
这里CAN00表示是CAN Module0,Node0的连接关系,如果是Module1,Node2就是CAN12,以此类推。
CAN00提供了8对引脚可供选择,我们从硬件设计获悉引脚关系后,查询对应的Rx Signals,比如Rx硬件连接为P12.0,则在MCAL中配置Rx为RXDC。发送端不需要配置,因为对于CAN模块来说,对每个内部连接都进行发送,由Port来配置使用哪个。
选择了对应的Rx Tx引脚之后,在Port端进行引脚功能配置即可。
3. MCAL配置及代码示例
3.1 内部总线连接
Infineon在M_CAN模块集成中,设计了Module internal Loop-back模式,能够将同一Module中的多个节点进行总线连接。我们在CAN调试过程中,如果手上没有CANOE,或者没有其他控制器进行联合调试。通过将对应NPCRx.LBM寄存器位置位即可(MCAL中可配置)。这样我们内部配置两个CAN Controller进行数据对发就能调试。
这里我们直接使用Infineon官方原版的MCAL配置和代码,稍加调整,实现两个CAN Node的报文对发。
另外这里对Port、Irq、时钟配置就不再赘述了,读者可以参考之前发布的相关文章。每个Can Module的16个中断源依次分配给4个Node,我们这里使用Module0的Node0和Node1,Irq中给Module0前8个中断进行配置即可。
3.2 General
照例General中还是一些常规接口使能配置。
CanMainFunctionModePeriod:CAN的发送接收等可以选择是中断还是轮询,这里我们选择中断,所以忽视该配置;
CanMultiplexedTransmission:该配置表示是否使用Tx FIFO/Tx Queue和专有Tx Buffer混用,这里我们只使用专有Buffer,不勾选;
3.3 Can Controller
然后我们来到Can Controller中,这里对应的就是我们的Can Node配置,每路CAN有各自的一个Controller。
CanBusoffProcessing、CanRxProcessing、CanTxProcessing、CanWakeupProcessing:中断、轮询选择,这些都是代码逻辑,如前所述,如果选择Polling就是在MainFunction中轮询,MCAL中断代码中便不会进行处理,配了也没用;这里我们配置为中断;
CanControllerActivation:Controller激活,勾选视为激活;
CanControllerLoopbackEnable:内部总线测试连接,这里我们需要利用两路内部Controller进行内部总线连接,因此需要勾选,注意非测试软件不要勾选,且勾选后RxInputSelection默认只能使用RXDA;
CanRxInputSelection:Rx引脚选择,如前所述;
CanControllerBaseAddress:CAN Controller基址,MCAL配置中对于该Controller使用哪个Module的哪个Node,由本参数决定,对应ACCENNODE0寄存器的地址,可在对应型号手册中查询,或者IfxCan_reg.h文件中搜索CAN0_N0_ACCENNODE0,比如Module0 Node0的ACCENNODE0地址为0xF0208100(十进制4028662016);
CanControllerId:Controller的软件ID标识;
CanWakeupFunctionalityAPI:Can_CheckWakeup() 使能;
CanControllerDefaultBaudrate:默认波特率配置引用,我们可以配置多种波特率,并在运行时切换,这里配置启动后的默认波特率;
然后来到波特率配置页面:
这里对应前面章节提到的波特率计算,用户根据实际需求填写传播段、相位缓冲段等参数即可。另外注意的是,时钟分频是不能填写的,而是工具根据这些参数自动计算的,参考前文公式。
后面页面的CANFD波特率设置同理,这里如果设置了CANFD波特率,自动打开CANFD使能。另外如果配置了第二采样点,则打开了发送采样延时补偿,这里由硬件自动标定,配置了任意数字都只是使能。
3.4 CanHardwareObject
然后我们来到CanHardwareObject,这里是对发送、接收帧硬件资源定义的地方,也就是配置前文提到的Rx Buffer、Tx Buffer等。
值得一提的是,这里只是硬件资源,并没有分配CAN ID,因为CANID是CanIf层的概念,CanIf来决定为某个CANID引用哪个硬件资源。当然有些工具如Vector DaVinci也会在CAN模块中设置CANID配置,操作更直观。
CanHandleType:硬件资源类型,FULL CAN还是BASIC CAN;
CanHwObjectCount:Tx FIFO数量,这里我们FULL CAN,使用专有Buffer,配置为1即可;
CanHwFIFOThreshold:Tx FIFO水位线,也就是中断触发阈值;
CanIdType:ID类型,标准11位还是扩展29位;
CanObjectId:软件中HardwareObject ID;
CanObjectType:Obj类型,发送或接收;
CanControllerRef:分配给哪个Controller;
这里顺便介绍下CanHwFilter,当我们配置为Basic CAN时生效,可以通过掩码过滤方式配置过滤器。
这里有两个配置,一个FilterCode,一个FilterMask,假设我们接收到的ID为RxID,其过滤成功条件为:RxID & Mask == Code & Mask,也就是Mask决定哪些位需要考察,Code决定该位的目标值。比如我要过滤0x4XX的帧,设置掩码为0xF00,设置Code为0x400即可。
3.5 代码及示例
这里我们使用Infineon官方MCAL接口,及MCAL Demo示例。
首先对外设进行初始化,并初始化中断配置,然后使能相应中断。
IrqCan_Init();
Can_17_McmCan_Init(&Can_17_McmCan_Config);
SRC_CAN_CAN0_INT0.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT1.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT2.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT3.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT4.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT5.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT6.U |= CAN_SRC_SET_SRE ;
SRC_CAN_CAN0_INT7.U |= CAN_SRC_SET_SRE ;
然后设置CanController模式,这一步在Autosar中是由CanSM向下通过CanIf来进行控制的,这里我们手动启动。
Can_17_McmCan_SetControllerMode (Can_17_McmCanConf_CanController_CanController_0, CAN_T_START);
然后我们定义数据及类型,调用AUTOSAR标准接口进行发送。这里说明下Can_PduType中,第一个元素为Pdu回调标识符,用于在CanIf_TxConfirmation函数中进行识别;第二个元素为DLC,第三个元素为CANID,第四个元素为数据指针。
Can_17_McmCan_Write中第一个入参为硬件资源ID,即前文CanHardwareObject配置中的ID,这里使用序号为8的硬件资源。
uint8 tx_data_1[][10] = {
{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },
...
}
Can_PduType PduInfo_1[] =
{
{8, 8, 0x123, tx_data_1[0] },
...
};
Can_17_McmCan_Write(8, &PduInfo_1[0]) ;
然后发送之后首先Controller1会通过内部总线连接收到该帧,进入CAN中断,并调用标准接口函数CanIf_RxIndication。
void CanIf_RxIndication(const Can_HwType *Mailbox, const PduInfoType *PduInfoPtr)
{
...
该回调将CAN层的信息传递到CanIf层,供上层进行数据解析。我们在这里打断点,可以看到其中的信息。这里接收使用的HardwareObjectId为4,接收ID对应,数据符合发送端源数据。
然后在发送端Controller0会产生发送中断,并调用标准回调函数CanIf_TxConfirmation。
void CanIf_TxConfirmation (PduIdType CanTxPduId)
{ ...
我们在这里打断点可以看到入参CanTxPduId为前面发送时提到的Can_PduType的第一个元素,用于标识是哪个PDU的回调,以便我们在这里处理对应PDU的完成事件。
到这里我们就完成了示例,通过内部连接总线测试,实现一路Controller向另一路Controller的数据发送,并进行接收。
大家在调试过程中,如果遇到问题可以查看PSR寄存器和ECR寄存器。
PSR.LEC表征最新的错误状态,比如我这里如果没有接内部回环,就会报Ack错误;PSR.ACT表征当前CAN模块的动作,如果使用具备实时观测的调试器,在发送时能看到这个值会变成11b(比较短,非实时观测调试器捕捉不到)。还有BusOff状态位PSR.BO等。
ECR寄存器则用来查询硬件错误计数使用的。
4 小结
本文详细介绍了英飞凌Aurix TC3XX中的M_CAN模块,对其内部硬件结构和原理进行了详细介绍,对其发送、接收流程进行了详细描述,并介绍了其在TC3XX中的集成连接。最后对MCAL中CAN模块的配置进行了介绍,并借助MCAL Demo实现了收发示例。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_44000419/article/details/141228784
|