EB协议栈支持gPTP时间同步功能,阅读此文章的前置知识是了解gPTP时间同步是如何工作的,这部分内容不在此详细展开,读者自行搜索相关知识。
读完此文章,你可以:
1. 了解EB 协议栈时间同步的计算过程
2. EB配置如何影响代码的运行
一、gPTP 时间同步工作原理简介:
1.1 gPTP报文类型
sync (获取T2)
follow up (获取T1)
pdelay_req,
pdelay_resp,
pdelay_resp_follow_up,
其中sync, follow up 由master主动发送, pdelay_req由slave 主动发送, pdelay_resp, pdelay_resp_follow_up由master收到 slave 的pdelay_req 后发送;
1.2 报文作用及工作过程
这5种报文可分为2组,sync, follow up一组,pdelay_req, pdelay_resp, pdelay_resp_follow_up一组,其中 pdelay_req, pdelay_resp, pdelay_resp_follow_up用于计算链路延时,计为pdelay; 计算原理如下图:
- a. slave 发送pdelay_req时,记录发送完成时刻的时间戳T1,
- b. master收到pdelay_req的时刻的时间戳记为T2, 并通过pdelay_resp报文把T2发送给slave, master 发送完成pdelay_resp的时刻的时间戳记为T3,
- c. slave 收到pdelay_resp报文的时刻的时间戳记为T4,并将报文内携带的T2时间戳解析出来,
- d. 接下来master再发送pdelay_resp_follow_up 报文,将T3 时间戳通过报文发送给slave,
- e. slave在收到pdelay_resp_follow_up报文后,将报文内携带的T3时间戳解析出来.
至此,用于计算链路延时的T1,T2,T3,T4 全部得到(注意区别sync, follow up报文的T1,T2),根据公式 PDelay=[(T4-T3)+(T2-T1)] / 2 计算出来。
sync, follow up 用于slave 跟上master时间。
具体代码内如何通过 pdelay_req, pdelay_resp, pdelay_resp_follow_up 计算pdelay,以及如何完成同步,下面结合代码说明。
二、EB 协议栈详细介绍
2.1 时间同步模块在autosar分层的位置
从上图可以看出,EthTSyn 在EthIf 之上,在StbM之下。
本文主要讲解gPTP协议在EB协议栈中的实现,因此,重点关注的文件是EthTSyn.c /.h。而macl 部分的实现,在Eth_Private.c/.h文件中, 但是本文会提及与之相关联的代码,明确调用关系。
2.2 接收gPTP报文
硬件接收到任何以太网报文的时候都是通过EthIf_RxIndication 一级一级向上通知,并根据报文类型,分发给不同的模块处理。收到gPTP报文也不例外,在Eth_Private.c的Eth_HwReceive 函数内,通过EthIf_RxIndication ,向上通知,如下图:
根据frameType这个参数,最终通知到的上层模块是EthTSyn,对应调用的函数是EthTSyn_RxIndication。
注意:要完成这个通知,需要在EB的EthIf模块内配置EthTSyn_RxIndication 回调函数,如下图:
配置完成后才会在回调函数的数组内,添加EthTSyn_RxIndication 函数指针,如下图:
2.3 gPTP报文接收后的处理
上面已经讲清楚了如何从硬件内接收gPTP报文,接收报文通知到EthTSyn_RxIndication函数内之后,调用EthTSyn_ProcessRxMsg函数处理gPTP报文在此函数内,根据MsgType (MsgType就是指Sync, follow up , p_delay_req等在1.1章节提及的报文),进入对应的函数内处理报文。
2.3.1 sync报文处理
sync报文在EthTSyn_ProcessRxSyncFrame函数内处理,此函数中需要得到IngressTime,即T2,记录在EthTSyn_Slave[EthTSynCtrlIdx].Sync_ActualIngressTimeStamp 变量内。
此函数内还有一些异常处理,如上一次收到了sync报文,但是没有收到follow up报文,又收到了sync报文的处理,此时会处理EB 配置内下图相关的参数
2.3.2 follow up 报文处理
follow up报文在EthTSyn_ProcessRxSynFUpFrame 内处理,此函数比较复杂,涉及到的时间很多,并且会在此函数内,通过EthIf_SetGlobalTime 函数,修正本地时间与master时间的offset。
此if 语句用于判断是否已经收到过sync报文,如果之前没有收到sync报文,那么当前的follow up报文被当做是异常报文丢弃掉。
各时间获取如下图:
接下来就是计算本地时间与master时间的差值,并将最终计算出来正确的时间,通过EthIf_SetGlobalTime(EthTSynCtrlIdx,&TmpTimeStamp) 函数写入本地时间内
2.3.3 pdelay_resp 报文处理
为什么跳过pdelay_req报文,因为pdelay_req 是slave 发送,放到发送章节说明
pdelay_resp 在函数EthTSyn_ProcessRxPdelayRespFrame内处理,主要作用是获取T4 与T2,
2.3.4 pdelay_resp_follow up 报文处理
pdelay_resp_follow up在函数EthTSyn_ProcessRxPdelayRespFUpFrame内处理, 主要作用是获取T3,
2.4 报文发送
2.4.1 p_delay_req报文发送处理
p_delay_req报文是周期性发送的,那么肯定有地方做定时处理,EB协议栈在EthTSyn_TriggerPeriodicFrames函数内定时,通过SendNextPdelayReqFrame_Timeout变量记录定时时间,变量为0时,置发送标志位。此时间收到以下两个EB配置的影响,如下图:
标志位在Frame2Transmit置位后,在函数EthTSyn_TransmitFrameWithDebounce内查询到此标志位,准备发送p_delay_req报文,发送过程不再详细介绍,主要需要知道的是,如何拿到T1这个时间,
硬件发送完成后,通过TxConfirmation 函数从底层往上层通知,直到通知到EthTSyn_TxConfirmation内。
注意,硬件发送完成有两种方式,一种是中断,发送完成后调用Eth_HwTxConfirmation 一级一级向上通知,另一种是在EthIf_MainFunctionTx函数内一直查询,然后再分层通知。
与接收一样,要能够通过EthIf_TxConfirmation通知,同样需要在EB 配置的EthIf模块内,配置回调函数,才能在数组内记录EthTSyn_TxConfirmation函数指针
通知到EthTSyn_TxConfirmation后,在函数内获取T1
至此,所有报文讲解完毕,需要注意的是,本文只以slave的角度讲解EB 协议栈的报文,并未讲解作为master情况下,如何发送sync, follow up ,如有需要,可私信于我。
3. 其他
EthTSynGlobalTimeFollowUpTimeout , 此配置用于处理异常情况,对应代码内的变量是GlobalTimeFollowUpTimeout, 此配置的意思是,收到sync报文后,多长时间没有收到follow up 报文,则认为超时,后续即使再收到follow up, 也会丢弃掉此次follow up报文,需要等到下次再收到sync报文之后,才能继续处理follow up报文。
以上讲解,如果问题,请留言说明,谢谢。