Use NTP provider

An NTP provider is available on the CX70xx from image version 140501 or higher.

The NTP provider can be used on different CX70xx Embedded PCs to provide approximately the same time. There is typically a deviation of ±5 ms between two CX70xxs.

Further information on how to insert the NTP provider into TwinCAT as a TcCOM module and put it into operation can be found here: https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_grundlagen/6326712203.html&id=

Example program for using the NTP provider

CX7000_NTP_Provider.zip

Variable declaration in the ST editor

PROGRAM TimeSync
VAR
(*
Time format:
FileTime64        8 Byte len        begin 1.1.1601    Bit/100ns
DCTime64          8 Byte len        begin 1.1.2000    Bit/100ns
*)
    Test_FileTime64:T_FILETIME64;    (* not used only to see where
                                      this time begin to see the different *)
    Test_DCTime64:T_DCTIME64;        (* not used only to see where
                                      this time begin to see the different *)


    nLocalTime            : T_FILETIME64;       // Filetime 64 - Local RTOS Time
    nPLC_DC_TASKTime      : T_FILETIME64;       (* Filetime 64 - Local DC Time | Local DC Time =
                                                 System Time see DiffSysTimeToPLCDCTime *)
    nSysTime AT %I*        : T_FILETIME64;      // Filetime 64 - Sytem Time        
    nExtTime AT %I*        : T_FILETIME64;      // Filetime 64 - TCNet Ext NTP Time
    nSysToExtTimeOffset     AT %I*    :LINT;    // Offset this is the offset from ExtTime to SysTime
    nSysToExtTimeDeviation  AT %I*    :LINT;    (* Only for Info: Diff from NTP to the NPT Filter
                                                 time is it < 1ms then is bIsSynchronized = TRUE *)
    
    bIsConnected AT %I*:BOOL;            // Connection to the NTP Server
    bIsSynchronized AT %I*:BOOL;         // see nSysToExtTimeDeviation

    FB_LocalSystemTime: FB_LocalSystemTime;        // Functionblock for read the local RTOS Time
    
    dt_LocalTime: DT;            // Time & data - local RTOS Time
    dt_PLC_DC_TASKTime: DT;      (* Time & data - This is the time from the TaskInfo Array, this
                                  is the same time as the Sytem Time from the NTP Object *)
    dt_nSysTime: DT;             // Time & data - Sytem Time from the NTP Object
    dt_nExtTime: DT;             // Time & data - NTP Object Ext NTP Time
        
    PlcTaskSystemInfo                : PlcTaskSystemInfo;    // Task Info


    DiffSysTimeToPLCDCTime: LINT;            // Local DC Time = System Time
    DiffLocalTimeToExtTime: LINT;            (* local Time - ExtTime = same time like
                                              the nSysToExtTimeOffset Time *)
    FB_EcDcTimeCtrl64_1:FB_EcDcTimeCtrl64;   // FB to get Sec/min/Hour... from a DCTime64
    nExtTime64: ULINT;                       // Format DCTime64 from nExtTime
    sec_1: WORD;                             // nExtTime Sec
    Min_1: WORD;                             // nExtTime Min
    msec_1: WORD;                            // nExtTime mSec

    nLocalTimeDC64: ULINT;                   // DCtime64 - from local filetime64
    MaxPLCTime: UDINT;


    lrTimeoffset: LREAL;              // Offest Time in LREAL [ms]
    lrTimeDeviation: LREAL;           (* Deviation Time [ms] this time show you the diff to the
                                       NTP filter time, if its <1ms the is bIsSynchronized = TRUE *)
    
    FB_CX7000_LED_WD: FB_CX7000_LED_WD;    // NPT Status via WD LED from CX7000


END_VAR

Program in the ST editor

PlcTaskSystemInfo:=_TaskInfo[1];      (* Get Task Info Data we need it to read the
                                       PlcTaskSystemInfo.DcTaskTime *)

dt_PLC_DC_TASKTime:=Systemtime_TO_DT(DCTime64_TO_SYSTEMTIME(LINT_TO_ULINT(PlcTaskSystemInfo.DcTaskTime)));         // Get Local DC Time to DT
nPLC_DC_TASKTime:=DCTIME64_TO_FILETIME64(LINT_TO_ULINT(PlcTaskSystemInfo.DcTaskTime));                            // Get Local DC Time to FileTime64

MaxPLCTime:=MAX(PlcTaskSystemInfo.LastExecTime,MaxPLCTime);


lrTimeoffset:=LINT_TO_LREAL(nSysToExtTimeOffset)/1000/10; // Read NTP Offset Time and convert it to Real in [ms]
lrTimeDeviation:=LINT_TO_LREAL(nSysToExtTimeDeviation)/1000/10; // Read NTP Offset Time and convert it to Real in [ms]


// Read the local time from RTOS
FB_LocalSystemTime(
    sNetID:= ,
    bEnable:=TRUE ,
    dwCycle:= ,
    dwOpt:= ,
    tTimeout:= ,
    bValid=> ,
    systemTime=> ,
    tzID=> );

dt_LocalTime:=SystemTime_TO_DT(FB_LocalSystemTime.systemTime);
nLocalTime:=SystemTime_TO_Filetime64(FB_LocalSystemTime.systemTime);

dt_nSysTime:=Filetime64_TO_DT(nSysTime);    // Convert nSysTime to date & time
dt_nExtTime:=Filetime64_TO_DT(nExtTime);    // Convert nExtTime to date & time

DiffSysTimeToPLCDCTime:=ULINT_TO_LINT(nPLC_DC_TASKTime-nSysTime);        // Must be 0 because SysTime = Local DC Time
DiffLocalTimeToExtTime:=ULINT_TO_LINT(nExtTime-nPLC_DC_TASKTime);        // Same diff like nSysToExtTimeOffset

// Ext NTP object as trigger for Outputs
nExtTime64:=FILETIME64_TO_DCTIME64(nExtTime);
FB_EcDcTimeCtrl64_1.A_GetMilli (in:=nExtTime64,get=>msec_1);
FB_EcDcTimeCtrl64_1.A_GetSecond (in:=nExtTime64,get=>sec_1);
FB_EcDcTimeCtrl64_1.A_GetMinute (in:=nExtTime64,get=>Min_1);

// Toggle Outpt every Sec
IF (sec_1 MOD 2) =0 THEN
    gvl.bCX7028_Out_4:=TRUE;
ELSE
    gvl.bCX7028_Out_4:=FALSE;
END_IF


// Set DO NTP Status
gvl.bCX7028_Out_1:=bIsConnected;
gvl.bCX7028_Out_2:=bIsSynchronized;

// WD LED from CX7000
// Red - no connection
// Green flashing - it is connected to NTP Server but it is not sync (that means that the filter is active and the synchonsation to the NTP Server is running - not with TC!)
// Green on - connection and synchonsation is running
FB_CX7000_LED_WD(
    bEnable:=TRUE ,
    eLED:= ,
    tFlashingTimeP1:= ,
    tFlashingTimeP2:= ,
    bError=> ,
    nErrorID=> );
IF bIsConnected AND NOT bIsSynchronized THEN
    FB_CX7000_LED_WD.eLED :=Tc2_SystemCX.E_CX7000_LED.LED_flashing_GREEN_OFF;
ELSIF bIsConnected AND bIsSynchronized THEN
    FB_CX7000_LED_WD.eLED :=Tc2_SystemCX.E_CX7000_LED.LED_GREEN ;
ELSE
    FB_CX7000_LED_WD.eLED :=Tc2_SystemCX.E_CX7000_LED.LED_RED ;
END_IF