STM32H743XI增加PTP功能
前言
为了项目需要,需要增加PTP功能。但是STM32官方HAL库并没有支持PTP功能。虽然最新的HAL库里面提供了PTP相关的接口,但是并没有实际去配置寄存器,只是提供接口让用户自己去配置寄存器。所以只能自己摸索。
PTP协议入门参考:PTP简介 - S7700 V200R020C10 配置指南-设备管理 - 华为 (huawei.com)
在网上搜到的比较好的参考文章是:RT-Thread : IEEE1588/PTP 协议的实现_stm32 ptp-CSDN博客
本人按照上面文章写的来移植PTP协议。使用了两个开发板:野火霸天虎STM32F407ZGT6, 野火STM32H743XI
STM32F407ZGT6开发板作为Master,STM32H743XI作为Slave。
虽然参考文章写的已经很详细,但自己还是遇到了文章中没有提到的问题,在下面重点说明。
注意事项
-
移植参考文章中提到的PTPd协议时,要首先仔细阅读PTPd中的README.md文件,里面描述了怎么更改。
-
可以在PTP初始化函数中限定只作为slave角色,slave不会发出Sync/FollowUp消息,会不停地等待Announce消息, 等到Announce之后会进入PTP_SLAVE角色。
-
PTPd代码中涉及到状态机的转换,知道状态机是怎么转换的之后才能明白代码逻辑。状态机转换可参考文章:trev_2019-Q4_PTP_in_Broadcasting_Part_2.pdf (ebu.ch)
-
用两个开发板调试时,需要配置两个开发板在同一网段。两个开发板mac地址不能一样,否则会报“handleSync: ignore from self”(mac地址不能一样,否则消息被判为来自自己,然后不处理)。
-
若Master接收不到Slave发出的Delay_Req消息,需要更改Master的如下配置:
-
Delay_Req的时间间隔是随机的
重点问题
调试过程中花了很多时间来解决Master和Slave之间时间相差较大的问题。如下图所示,Slave收到FollowUp消息后,计算Sync收到时间与发出时间的差值offsetFromMaster, 其值一直很大,导致Slave进不了PTP_SLAVE状态。
是否使用HSE
最开始怀疑两个开发板使用的是内部时钟源HSI,而没有使用精度更高的外部时钟源HSE。
经研究代码发现STM32H743XI已经使用了外部时钟源,如下图所示:
STM32F407ZGT6参考野火文档增加了使用HSE的代码如下,测试发现并不是时钟本身的原因。
驱动配置寄存器是否正确
排除了HSE的猜测后,就开始怀疑寄存器配置是否正确。重点是PTP参考时钟与Adden,Increment直接的关系:
查阅reference book之后,确定HCLK,Adden等都是正确的配置。
时间戳是否是硬件产生
最终发现是时间戳的获取方法有问题!!!
如下图所示,当初移植PTPd时没有注意到LWIP_PTP,就没有去定义,因此Sync的发出时间和接收时间都是软件通过getTime()来获取的,这样导致Master和Slave之间时间差一直很大。
定义LWIP_PTP为1后,就要更改ETH接收和发送代码以让ETH MAC产生时间戳。
-
发送方向
根据DesignWare Cores Ethernet Quality-of-Service Databook,TDES2中的TTSE置上后,DMA完成搬运后,会将帧发出时间戳回填到TDES0和TDES1,这个时间戳是硬件打的。
代码改动如下:
-
接收方向
根据DesignWare Cores Ethernet Quality-of-Service Databook,需要配置MAC_Timestamp_Control寄存器,然后DMA会在Receive Normal Descriptor之后产生一个Context Descriptor,Context Descriptor的RDES0和RDES1是收到帧时的时间戳。
代码改动如下:
按照上面的改动来调试,发现还是存在问题,原因是使用的开发板的参考程序HAL库比较老,存在bug: Solved: Inconsistent ethernet RX descriptor queue when usi… - STMicroelectronics Community
将bug修复后还是不行,于是将ETH_RX_DESC_CNT由4改成8,后面一切正常了。
测试方法
PPS信号
参考:通过PPS信号验证PTP同步_ts2phc用来和gps时间同步_就是个linux工程师的博客-CSDN博客
使用这个方式需要在代码中配置相应的GPIO,PPS信号大概率和其他信号复用GPIO,需要参考芯片手册来配置GPIO。
添加log
本人使用的是添加log的方式,通过串口打印出主从时钟之间的差异,如下图中的打印,主从时钟之间的差异在40ns以内,已经完全满足PTP协议的要求。