AM64x MCU+ SDK  10.00.00
ICSS TimeSync

Introduction

The ICSS TimeSync driver provide APIs for PTP/1588 v2 receiver implementation on PRU-ICSS.

Precision Time Protocol (PTP) comes in a variety of standards and flavors. Every industry has it's own set of sub rules and configurations which are defined by Annexes and Profiles. For example, the telecom industry uses the telecom profile, while power and substation automation requires the power profile. CIP sync requires the Drive profile.

Keeping above points in mind, ICSS TimeSync driver provides support for following flavor :

  1. End-to-End (E2E) version
    • Annex D based solution for EtherNet/IP
    • Delay Request/Response based Ordinary Clock and Transparent Clock

Delay Request/Response based Ordinary Clock and Transparent Clock support is provided to support CIP Sync, which requires support for Annex D of PTP/1588 (PTP over UDP).

Note
ICSS TimeSync will be supported for use in EtherNet/IP Adapter and PRP(Parallel Redundancy Protocol) examples only.

Features Supported

  • Annex D based PTP/1588 solution for EtherNet/IP
  • Single/Dual Step : Capability to handle both single and two step PTP messages
  • Single step Ordinary clock
  • Syntonization factor calculation
  • Simple design for time base (More details in ICSS TimeSync Design)
  • 1PPS output for Sync, with configurable time period for sync generation.
  • Statistics for debugging and monitoring

Features not supported

  • Annex F based PTP/1588 solution with adaptation for HSR/PRP on IEC 62439-3
  • Single step Transparent clock
  • Main clock
  • BMCA (Best Time Source Clock Algorithm)
  • Annex F based PTP/1588 solution in E2E mode
  • Annex D based PTP/1588 solution in P2P mode
  • Management Messages

ICSS TimeSync Design

ICSS TimeSync Design explains the driver design in detail.

Usage

Including the header file

Include the below file to access the APIs

Initializing the Handle

TimeSync_drvInit should be called initialize the driver. It does everything and returns a value indicating whether initialization succeeded or failed. The driver call does not allocate the memory it needs. Therefore the allocation must be done by the application.

int8_t returnVal = TIME_SYNC_OK;
TimeSync_ParamsHandle_t timeSyncHandle;
/* Allocate memory for the handle */
timeSyncHandle = (TimeSync_ParamsHandle_t)malloc(sizeof(TimeSync_ParamsHandle));
DebugP_assert(timeSyncHandle != NULL);
/*Configure PTP. These variables must be configured before doing anything else*/
timeSyncHandle->emacHandle = emacHandle;
timeSyncHandle->pruicssHandle = pruicssHandle;
timeSyncHandle->timeSyncConfig.config = BOTH;
timeSyncHandle->timeSyncConfig.type = E2E;
timeSyncHandle->timeSyncConfig.protocol = UDP_IPV4;
timeSyncHandle->timeSyncConfig.tickPeriod = 500;
timeSyncHandle->txprotocol = 0;
/* ... */
/* ... */
/* Allocate memory for some structures inside handle */
timeSyncHandle->tsRunTimeVar = (timeSync_RuntimeVar_t *)malloc(sizeof(timeSync_RuntimeVar_t));
DebugP_assert(timeSyncHandle->tsRunTimeVar != NULL);
/* ... */
/* ... */
/* Allocate Rx and Tx packet buffers */
returnVal = TimeSync_alloc_PktBuffer(timeSyncHandle);
DebugP_assert(returnVal == TIME_SYNC_OK);
/* Call the initialization API */
returnVal = TimeSync_drvInit(timeSyncHandle);
DebugP_assert(returnVal == TIME_SYNC_OK);

The variables shown in the code above do not show the full list of configurable variables and structures for which memory should be allocated. Please check all members inside TimeSync_ParamsHandle structure.

Enabling/Disabling the Driver

A separate call is required to TimeSync_drvEnable is needed for enabling PTP processing in firmware. The corresponding TimeSync_drvDisable call disables the module in firmware.

Updating IP Address

TimeSync_addIP should be called to update IP and modify checksum in PTP packet buffers, whenever IP is assigned or changed.

PTP Stack Porting Guide

Porting your own PTP/1588 stack is simple because most of the tasks, especially the time critical tasks are performed by the driver. The stack is only responsible for

  • Running BMCA and finding out the PTP broadcaster
  • Checking for Announce timeouts
  • Handling management messages

Once TimeSync_drvInit and TimeSync_drvEnable APIs are called from the application, all PTP announce and management messages are sent on the highest priority queue to the host. All incoming PTP frames are handled through the regular Rx interrupt registered by ICSS-EMAC (See Interrupts section in ICSS-EMAC Design for more details). TimeSync_processPTPFrame must be called for processing PTP frames. As mentioned in Rx Data Path, rxRTCallBack needs to be registered to process these frames in queues. Therefore, either TimeSync_processPTPFrame must be registered as rxRTCallBack, or if different types of frames (other than PTP) are coming on the high priority queues, then application must differentiate PTP frames in rxRTCallBack and then call the TimeSync_processPTPFrame API for PTP frames.

In TimeSync_processPTPFrame, the frame type is checked and if it is an Announce or Management message the data is copied to the buffer ptpGeneralFrame. Once the frame has been copied a flag generalFrameFlag is set. Another API called TimeSync_getGeneralMessage checks the flag and copies the data from the buffer ptpGeneralFrame to another buffer buff which belongs to the PTP stack. The API TimeSync_getGeneralMessage strips the header from the frame based on whether the mode is E2E or P2P and only copies the relevant data to the stack buffer. This way only the relevant data is sent to stack and stack need not worry whether the mode is E2E or P2P.

The stack can either modify TimeSync_processPTPFrame to call the TimeSync_getGeneralMessage API, or call TimeSync_getGeneralMessage in a loop in a task.

Running Best Main Clock Algorithm

PRU-ICSS firmware compares the Source MAC ID of Sync and Follow Up frames with the value stored at the offset PTP_MASTER_SRC_MAC_ID in PRU-ICSS Shared RAM, and if it does not match then the sync processing does not happen. For starting sync processing, BMCA has to complete and once the source MAC ID of a broadcaster is available, it should be shared with firmware by calling TimeSync_updateParentAddress.

Getting the current time

As explained in Timestamping section of ICSS TimeSync Design page, ICSS TimeSync has a very simple design where the IEP counter acts as the nanoseconds counter. TimeSync_getCurrentTime returns the current time on device.

Resetting the driver

In case of a timeout, link break, etc. the driver requires a reset. This is done using the TimeSync_reset. This API also calls the TimeSync_stackResetCallback_t which can be registered by stack.

Getting other parameters

Most of the information related to PTP is encapsulated in Announce and Management messages. However certain information is part of the driver, and the stack may need access to these for its operation. Relevant information can be read from the runtime structure timeSync_RuntimeVar_t based on the requirement.

Debug Guide

Internal structures used by ICSS TimeSync Driver can be checked for debugging. Most relevant structures are timeSync_RuntimeVar_t are timeSync_SyntInfo_t.

API

APIs for ICSS TimeSync

See also

ICSS-EMAC

E2E
@ E2E
Definition: icss_timeSyncApi.h:194
icss_timeSync_init.h
UDP_IPV4
@ UDP_IPV4
Definition: icss_timeSyncApi.h:162
BOTH
@ BOTH
Definition: icss_timeSyncApi.h:185
timeSync_RuntimeVar_t
Runtime variables for Time Sync implementation.
Definition: icss_timeSyncApi.h:481
TimeSync_ParamsHandle
Time synchronization parameter handle structure.
Definition: icss_timeSyncApi.h:811
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:177
TIME_SYNC_OK
#define TIME_SYNC_OK
Success.
Definition: icss_timeSync.h:56
TimeSync_ParamsHandle_t
struct TimeSync_ParamsHandle_s * TimeSync_ParamsHandle_t
Definition: icss_timeSyncApi.h:962
TimeSync_alloc_PktBuffer
int8_t TimeSync_alloc_PktBuffer(TimeSync_ParamsHandle_t timeSyncHandle)
Allocate Rx and Tx buffers for frames like Sync, Announce etc.
TimeSync_drvInit
int8_t TimeSync_drvInit(TimeSync_ParamsHandle_t timeSyncHandle)
Initializes variables and timers & clocks, call once at the beginning.