IEEE1588协议驱动分布式系统高精度同步触发

 2019-8-1 11:40:01     作者:Emtronix    
文章标签:C/C++IEEE1588

  IEEE1588是精确网络对时协议,简称PTP。它通过硬件实现的时间标签(hardware time stamp),使对时精度达到亚微秒级(< 1us),大大高于常规的网络对时协议(NTP)。PTP协议的另一个特色是它可输出精确时间同步的硬件脉冲,通常称为PPS脉冲。在网络化的嵌入式系统中,利用PTP的硬件PPS脉冲,可对处于不同位置的多台设备实现同步触发的功能。这对分布式系统的数据采集、实时控制都具有非常的意义。


  英创公司的多款嵌入式主板,ESM7000、ESM6802和ESM6800,其网络接口均支持PTP协议,且可输出PPS脉冲,因此是分布式智能设备的理想嵌入式平台。以下将以ESM7000为例,介绍实现分布式同步触发的软硬件方案。


基于PTP的同步触发软件流程


  ESM7000预装的Linux平台文件系统中,已包含了PTP对时及硬件时间同步的完整工具,即ptp4l和phc2sys,同时可方便的控制PPS脉冲的使能。在这个基础上,按照图1所示流程就可实现同步触发的功能。


基于IEEE1588协议实现分布式系统的高精度同步触发.png

图1 同步触发软件流程


  在实际的测试中发现,PTP的对时精度与网络环境有密切关系。在单一的100M网络环境所获得的设备间的同步精度在±200ns;而在1000M网环境,同步精度就下降到±1us;混合网络环境,同步精度可差至±15us。


同步触发脉冲的硬件方案


  所谓硬件方案,是指图1中触发脉冲生成器的实现方案。以PTP协议生成的周期性PPS脉冲为基础,由应用程序生成触发使能信号,再通过一个简单的D触发器生成最后的触发脉冲。硬件方案涉及3个信号如下:

  ● PPS_OUT:整秒脉冲输出,即周期固定为1秒,在ESM7000上,PPS的脉冲宽度为10ns,上升沿有效。

  ● TRG_EN:触发使能,通常用一位GPIO来实现,其高电平有效。

  ● TRG_PULSE:触发脉冲,上升沿有效;在TRG_EN为低时,将强制TRG_PULSE为低;当TRG_EN为高时,后续的PPS_OUT脉冲上升沿将锁存高电平,从而是TRG_PULSE变高电平。TRG_PULSE脉冲上升沿将将作为系统采集控制硬件单元的触发输入,触发各个嵌入式设备同步动作。


基于IEEE1588协议实现分布式系统的高精度同步触发.png

图2 同步触发脉冲生成电路原理图


  在图2中,TRG_PULSE还可反馈给ESM7000主板,通知同步触发已发生。但不是必须的。


  大部分ESMARC主板均可支持PTP同步触发功能。对不同型号的主板,PPS脉冲输出管脚有所不同,如下表所示:


主板型号PTP网口PPS信号管脚备注
ESM7000系列eth0CN2.GPIO0 
ESM6802系列eth0CN2.GPIO24V2.4版才支持
ESM6800系列eth1CN2.GPIO22不能使用SD卡
ES6801eth0CN1.GPIO0不能使用CAN1


  对选择哪一位GPIO管脚作为TRG_EN,本方案没有限制。可根据设备的具体情况来确定。


对同步触发从设备测试


  本测试用从设备的“当前时间+ 偏移量”来代替主设备发布的触发时间TRGTIME,就可用简单的脚本测试整个触发过程,具体的脚本如下:


#!/bin/sh
# trg_en_3 $1 [$2] [$3]
# $1 = 0, off ptp; = 1: on ptp
# $2 = number of seconds to delay from cuurent time
# $3 = ip:port
 
PATH="/usr/bin:$PATH"
E_NOARGS=85
re='^[0-9]+$'
TRG_EN_GPIO="gpio1"
TRG_EN_DIRECTORY="/sys/class/em_gpio/em_gpio/$TRG_EN_GPIO"
PHC2SYSLOG="/tmp/phc2syslog.txt"
DELAY=10
 
# if no arg, exit
if [ -z "$1" ]
then
       echo "Usage: `basename $0` filename"
       exit $E_NOARGS
fi
 
# if $1 != 1, off ptp and exit
if [ "$1" -ne 1 ]
then
    echo 0 > /sys/class/ptp/ptp0/pps_enable
    pkill phc2sys
    pkill ptp4l
       exit 0
fi 
 
# get trigger delay is available, default = 10(s)
if [ $# -ge 2 ]
then
       DELAY="$2"
fi
 
# now we start to make trg_en step by step
 
echo "step 1: setup gpio1 as trg_en"
if [ ! -d "$TRG_EN_DIRECTORY" ]
then
       echo "config $TRG_EN_GPIO as trg_en"
       echo 1 > /sys/class/em_gpio/em_gpio/export
fi
echo out > /sys/class/em_gpio/em_gpio/$TRG_EN_GPIO/direction
echo 0 > /sys/class/em_gpio/em_gpio/$TRG_EN_GPIO/value
 
echo "step 2: start ptp"
phc2sys -s eth0 -c CLOCK_REALTIME -w -m -u 4 > $PHC2SYSLOG &
sleep 1
ptp4l -i eth0 -s &
 
echo "step 3: wait phc2sys sync convergence"
num_rms=0
while [ "$num_rms" -lt 3 ]
do
       RMS_ARRAY=$(cat $PHC2SYSLOG | tail -n 3 | sed -r 's/.*rms[ ]+([0-9]+).*/\1/g')
       # echo "$RMS_ARRAY"
 
       for rms in $RMS_ARRAY
       do
              if ! [[ $rms =~ $re ]]
        then
            echo "$rms is NOT an integer!"
                     break
              fi           
 
              echo "$rms"
              if [ "$rms" -lt 350 ]; then
                     let "num_rms += 1"
              fi
       done
      
       # clear log file if rms is convergence
       if [ "$num_rms" -ge 3 ]; then
              echo "rms is convergence ($num_rms)"
              cat /dev/null > $PHC2SYSLOG
       else
              let "num_rms = 0"
              sleep 2
       fi
done
 
echo "step 4: enable pps, and setup trigger time"
echo 1 > /sys/class/ptp/ptp0/pps_enable
TRGTIME=$(date +%s)                                       # get current date in seconds
let "TRGTIME = $TRGTIME + $DELAY"
PPSTIME=$(cat /sys/class/pps/pps0/assert | cut -d '.' -f 1)
echo "TRGTIME = $TRGTIME PPSTIME = $PPSTIME"
 
echo "step 5: wait pps time reach trigger time"
while [ "$PPSTIME" -lt "$TRGTIME" ]
do
       sleep 0.1
       PPSTIME=$(cat /sys/class/pps/pps0/assert | cut -d '.' -f 1)
done
 
echo "step 6: now PPSTIME = TRGTIME, set trg_en"
echo 1 > /sys/class/em_gpio/em_gpio/$TRG_EN_GPIO/value
 
echo "step 7: wait pps time reach trigger time + 1"
let "TRGTIME = $TRGTIME + 1"
while [ "$PPSTIME" -lt "$TRGTIME" ]
do
       sleep 0.1
       PPSTIME=$(cat /sys/class/pps/pps0/assert | cut -d '.' -f 1)
done
 
echo "step 8: clear trg_en"
echo 0 > /sys/class/em_gpio/em_gpio/$TRG_EN_GPIO/value
echo "basename $0 done"


  从示波器可观察到,上述脚本产生的TRG_EN信号,准确使能PPS脉冲产生与之上升沿完全同步的触发脉冲TRG_PULSE。


  对分布式系统同步触发功能感兴趣的客户,可通过邮件support@emtronix.com与英创公司技术部门联系,以了解详细的实现代码。

文章标签:C/C++IEEE1588