This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DP83630: Synchronize between two PHYs' PTP clock accuracy is not sub-nanosecond

Part Number: DP83630

Refer to AN-1794 section 4.1 Figure 6, I connect two DP83630s to a MCU which has two RMII mode MACs, one for upstream port, the other for downstream port.

For the upstream port, the PHY works at RMII Master mode with SYNC_ENET_EN enabled, for the downsteam port, the PHY works at RMII slave mode with SYNC_ENET_EN disabled.

The upstream port PHY feeds with a 25MHz TCXO, it output the 50MHz through it's TX_CLK and feed to downstream port's X1 input.

Using above topology, both upstream port PHY and downstream port PHY work at same clock domain, so I expect their PTP clock can be synchronized to sub nanosecond accuracy.

Refer to AN-1838 section 3.1 Figure 2, I implement the synchronization PTP clock between upstream PHY and downstream PHY.

However, when I test the PPS output from each PHY using a oscilloscope, I found the phase error is uncertainty. 

Everytime I power on the system, after PTP synchronization finished, PPS phase error vary among three values (0ns, 4ns and 8ns, which is multiple of 4ns).  

Do you think the phase error is expected or not?

Is it possible the achieve the sub nanosecond accuracy between the two PHYs ptp clock?

My source code is attached as followed:

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

NS_UINT SimpleSyncTwoPHY(RunTimeOpts *rtOpts, NS_BOOL SyncEth1ToEth0, NS_BOOL DoSync)
{
NS_UINT eventNum[2] = {0xFF,0xFF};
NS_UINT riseFlag[2];
NS_UINT eventsMissed[2];
NS_UINT events;
NS_STATUS status;
int deltaRate;
int WaitTime;

NS_UINT phaseError;

NS_BOOL negAdj;

TimeInternal eventTime[2];
TimeInternal TimeDiff;
TimeInternal TimeDiffPhy1ToPhy2;
TimeInternal TimeDiffPhy2ToPhy1;

long long val;
long long val1;
long long val2;
long long DeltaT;
long long DeltaP;

// Flush eth0 PHY's Event Timestamp
while ( (events = PTPCheckForEvents( pEPL_HANDLE1)))
{
if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
{
PTPGetEvent(pEPL_HANDLE1, &eventNum[0], &riseFlag[0], &(eventTime[0].seconds),&eventTime[0].nanoseconds, &eventsMissed[0]);
}
else
{
break;
}

}


// Flush eth1 PHY's Event Timestamp
while ( (events = PTPCheckForEvents( pEPL_HANDLE2)))
{
if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
{
PTPGetEvent(pEPL_HANDLE2, &eventNum[1], &riseFlag[1], &(eventTime[1].seconds), &eventTime[1].nanoseconds, &eventsMissed[1]);
}
else
{
break;
}
}

//Set PHY1's GPIO3(SYNC_TRIGGER) as a riging edge event number 0 capture
PTPSetEventConfig(pEPL_HANDLE1, 0, TRUE, FALSE, TRUE, 3);

//Set PHY2's GPIO3(SYNC_TRIGGER) as a riging edge event number 0 capture
PTPSetEventConfig(pEPL_HANDLE2, 0, TRUE, FALSE, TRUE, 3);


//Set MCU's SYNC_TRIGGER pin as input, to avoid conflict with PHY's trigger output
FM3_GPIO->PFRA &= ~(1u<<0x0); // PA0, not special function
FM3_GPIO->DDRA &= ~(1u<<0x0); // Set SYNC_TRIGGER pin as input



//Calculate the trigger timing offset 500ms from current PHY1's PTP time
PTPClockReadCurrent(pEPL_HANDLE1, &(eventTime[0].seconds),&(eventTime[0].nanoseconds));
val = (long long)(eventTime[0].seconds * 1e9) + (long long)eventTime[0].nanoseconds;
val += 50000000;

//Phase align the trigger signal
val = val - val % 8;

eventTime[0].seconds = (int)(val / 1e9);
eventTime[0].nanoseconds = (int)(val % (long long)1e9);

//Set PHY1's GPIO3(SYNC_TRIGGER) as a trigger 1 output, and output a 1us positive pulse
PTPCancelTrigger(pEPL_HANDLE1, 1);
PTPSetTriggerConfig( pEPL_HANDLE1, 1, TRGOPT_PULSE | TRGOPT_NOTIFY_EN, 3);
PTPArmTrigger( pEPL_HANDLE1, 1, eventTime[0].seconds, eventTime[0].nanoseconds,
FALSE, FALSE, 10000, 10000);

//Waiting for trigger 1 to trigger
WaitTime = 0x10000000;
status = PTPHasTriggerExpired(pEPL_HANDLE1,1);
while((NS_STATUS_SUCCESS != status) && (WaitTime>0))
{
status = PTPHasTriggerExpired(pEPL_HANDLE1,1);
WaitTime--;
}


if(!WaitTime)
{

printf("Error waiting for trigger!\n");
return -1;
}
else
{

printf("PHY1 Triggerred!\n");
}

PTPCancelTrigger(pEPL_HANDLE1, 1);
PTPSetTriggerConfig( pEPL_HANDLE1, 1, TRGOPT_PULSE | TRGOPT_NOTIFY_EN, 0);

// Flush Transmit and Receive Timestamps and get Event Timestamp
while ( (events = PTPCheckForEvents( pEPL_HANDLE1)))
{
if ( events & PTPEVT_TRANSMIT_TIMESTAMP_BIT)
PTPGetTransmitTimestamp( pEPL_HANDLE1, &(eventTime[0].seconds), &(eventTime[0].nanoseconds),&eventsMissed[0]);
else if ( events & PTPEVT_RECEIVE_TIMESTAMP_BIT)
PTPGetTransmitTimestamp( pEPL_HANDLE1, &(eventTime[0].seconds), &(eventTime[0].nanoseconds),&eventsMissed[0]);
else if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
{
PTPGetEvent(pEPL_HANDLE1, &eventNum[0], &riseFlag[0], &(eventTime[0].seconds), &(eventTime[0].nanoseconds), &eventsMissed[0]);
if(eventNum[0] & (1<<0))
break;
}
}
if(!(eventNum[0] & (1<<0)) )
{
printf("Error, PHY1 no SYNC_Trigger event captured!!!\n");
return -1;
}
// Disconnect event 0 from GPIO 3
PTPSetEventConfig( pEPL_HANDLE1, 0, FALSE, FALSE, FALSE, 0);



// Flush Transmit and Receive Timestamps and get Event Timestamp
while ( (events = PTPCheckForEvents( pEPL_HANDLE2)))
{
if ( events & PTPEVT_TRANSMIT_TIMESTAMP_BIT)
PTPGetTransmitTimestamp( pEPL_HANDLE2, &(eventTime[1].seconds), &(eventTime[1].nanoseconds),&eventsMissed[1]);
else if ( events & PTPEVT_RECEIVE_TIMESTAMP_BIT)
PTPGetTransmitTimestamp( pEPL_HANDLE2, &(eventTime[1].seconds), &(eventTime[1].nanoseconds),&eventsMissed[1]);
else if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
{
PTPGetEvent(pEPL_HANDLE2, &eventNum[1], &riseFlag[1], &(eventTime[1].seconds), &(eventTime[1].nanoseconds), &eventsMissed[1]);
if(eventNum[1] & (1<<0))
break;
}
}
if(!(eventNum[1] & (1<<0)) )
{
printf("Error, PHY2 no SYNC_Trigger event captured!!!\n");
return -1;
}
// Disconnect event 0 from GPIO 3
PTPSetEventConfig( pEPL_HANDLE2, 0, FALSE, FALSE, FALSE, 0);

subTime(&TimeDiffPhy1ToPhy2, &eventTime[0],&eventTime[1]);
val = (long long)(TimeDiffPhy1ToPhy2.seconds * 1e9) + (long long)TimeDiffPhy1ToPhy2.nanoseconds;

val +=16;

negAdj = FALSE;
if(val < 0)
negAdj = TRUE;

TimeDiff.seconds = (int)(val / 1e9);
TimeDiff.nanoseconds = (int)(val % (long long)1e9);

PTPClockStepAdjustment( pEPL_HANDLE2 , abs(TimeDiff.seconds), abs(TimeDiff.nanoseconds), negAdj);

PTPClockReadCurrent(pEPL_HANDLE1, &(eventTime[0].seconds),&(eventTime[0].nanoseconds));
val = (long long)(eventTime[0].seconds * 1e9) + (long long)eventTime[0].nanoseconds;
val += 50000000;

//PPS phase alignment
val = val - val%32;

eventTime[0].seconds = (int)(val / 1e9);
eventTime[0].nanoseconds = (int)(val % (long long)1e9);



// Setup PHY1's PPS configuration
PTPSetTriggerConfig( pEPL_HANDLE1, 0, TRGOPT_PULSE |TRGOPT_PERIODIC| TRGOPT_NOTIFY_EN, 0);
PTPCancelTrigger( pEPL_HANDLE1, 0);
PTPSetTriggerConfig( pEPL_HANDLE1, 0, TRGOPT_PULSE|TRGOPT_PERIODIC|TRGOPT_NOTIFY_EN, 1);
PTPArmTrigger( pEPL_HANDLE1, 0, eventTime[0].seconds, eventTime[0].nanoseconds,
FALSE, FALSE, 16, 16);

// Setup PHY2's PPS configuration
PTPSetTriggerConfig( pEPL_HANDLE2, 0, TRGOPT_PULSE |TRGOPT_PERIODIC| TRGOPT_NOTIFY_EN, 0);
PTPCancelTrigger( pEPL_HANDLE2, 0);
PTPSetTriggerConfig( pEPL_HANDLE2, 0, TRGOPT_PULSE|TRGOPT_PERIODIC|TRGOPT_NOTIFY_EN, 1);
PTPArmTrigger( pEPL_HANDLE2, 0, eventTime[0].seconds, eventTime[0].nanoseconds,
FALSE, FALSE, 16, 16);

}

 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

  • Hi,

    a. Can you measure the phase difference between CLK_OUT of Phy1 and PPS of both Phy across the resets and share ?
    b. Also, can you try using CLK_OUT of Intenral PTP Clock 25 Mhz from Phy 1 to Phy2 ( below from datasheet)

    -------------------
    CLOCK OUTPUT: This pin provides a highly configurable system clock,
    which may have one of four sources:
    1. Relative to the internal PTP clock, with a default frequency of 25 MHz
    (default)
    2. 50 MHz RMII reference clock in RMII Master Mode
    3. 25 MHz Receive Clock (same as RX_CLK) in 100 Mb mode
    4. 25 MHz or 50 MHz pass-through of X1 reference clock
    CLOCK INPUT: This pin is used to input an external IEEE 1588 reference
    clock for use by the IEEE 1588 logic. The CLK_OUT_EN strap should be
    disabled in the system to prevent possible contention. The PTP_CLKSRC
    register must be configured prior
    ----------------------------------------

    Regards,
    Geet
  • "across the resets and share ?"

    Here the "share" means what?

    Btw: I implement two individual resets for each PHY which from MCU's two different GPIO, that means those two PHYs cannot be reset at same time.
  • "share" : share the test results.

    Reset : You can reset the Phy with XTAL first followed by Phy using the CLK_OUT.

    Regards,
    Geet

  • Thank you for your quick response.

    For case A you mentioned, I do 8 times power-on test, every time phase alignment among those three signal is different. Then I try to reset the MCU only while keep the board power on, the phenomenon is same. So I only record the power on test result at followed.

     

    For case B you mentioned, I cannot accept PHY2's PTP function work as low as 25MHz clock, I still hope both PHY1 and PH2 have 125MHz PTP clock, so I haven't try it yet.

     

    Followed is my test result for case A:

     

    ===================================================

    Oscilloscope setting:

    C1: PHY1's 25MHz PTP clock (Write color)

    C2: PHY1's PPS output (Green color)

    C3: PHY2's PPS output (Brown color)

    ===================================================

     

    ===================================================

    Software Sequence:

    1. Setting PHY1 to generate the first trigger signal

    2. PHY1 and PHY2 event captured, record the event timestamp

    3. Calculate the offset from PHY2 to PHY1

    4. Do the step adjust

    5. Setting PHY1 to generate the second trigger signal

    6. PHY1 and PHY2 event captured, record the event timestamp

    7. Reconfirm the offset from PHY2 to PHY1

    ==================================================

     

    In followed eight times test log and waveform, in the step7, PHY1 and PHY2 has no time offset, that means synchronization is success. However the waveform have phase error, because event timestamp's accuracy is 8ns, so I doubt PHY1 and PHY2 didn't synchronized actually.

     

    First time Test log:

    PHY1 Triggerred!

    Setting trigger time is 20s983520000ns

    PHY1 event time is 20s983520000ns

    PHY2 event time is 1s7155856ns

    Timediff is 19976364144ns

    PHY1 Triggerred!

    Setting trigger time is 21s487240000ns

    PHY1 event time is 21s487240000ns

    PHY2 event time is 21s487240000ns

    Timediff is 0ns

     

    First time, snapshot from oscilloscope:

     

    Second time Test log:

    PHY1 Triggerred!

    Setting trigger time is 17s979580000ns

    PHY1 event time is 17s979580000ns

    PHY2 event time is 1s7139000ns

    Timediff is 16972441000ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 18s483320000ns

    PHY1 event time is 18s483320000ns

    PHY2 event time is 18s483320000ns

    Timediff is 0ns

     

     

    Second time, snapshot from oscilloscope:

     

    3rd time Test log:

    PHY1 Triggerred!

    Setting trigger time is 17s982380000ns

    PHY1 event time is 17s982380000ns

    PHY2 event time is 1s7133208ns

    Timediff is 16975246792ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 18s486120000ns

    PHY1 event time is 18s486120000ns

    PHY2 event time is 18s486120000ns

    Timediff is 0ns

     

    3rd time, snapshot from oscilloscope:

     

    4th time Test log:

    PHY1 Triggerred!

    Setting trigger time is 17s983100000ns

    PHY1 event time is 17s983100000ns

    PHY2 event time is 1s7161264ns

    Timediff is 16975938736ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 18s486820000ns

    PHY1 event time is 18s486820000ns

    PHY2 event time is 18s486820000ns

    Timediff is 0ns

     

     

    4th time, snapshot from oscilloscope:

    5th time Test log:

    PHY1 Triggerred!

    Setting trigger time is 26s982240000ns

    PHY1 event time is 26s982240000ns

    PHY2 event time is 1s7137488ns

    Timediff is 25975102512ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 27s485980000ns

    PHY1 event time is 27s485980000ns

    PHY2 event time is 27s485980000ns

    Timediff is 0ns

     

     

    5th time, snapshot from oscilloscope:

     

    6th time Test log:

    PHY1 Triggerred!

    Setting trigger time is 26s982080000ns

    PHY1 event time is 26s982080000ns

    PHY2 event time is 1s7148464ns

    Timediff is 25974931536ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 27s485820000ns

    PHY1 event time is 27s485820000ns

    PHY2 event time is 27s485820000ns

    Timediff is 0ns

     

    6th time, snapshot from oscilloscope:

    7th time Test log:

    PHY1 Triggerred!

    Setting trigger time is 26s981960000ns

    PHY1 event time is 26s981960004ns

    PHY2 event time is 1s7162112ns

    Timediff is 25974797892ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 27s485680000ns

    PHY1 event time is 27s485680004ns

    PHY2 event time is 27s485680004ns

    Timediff is 0ns

     

    7th time, snapshot from oscilloscope:

    8th time Test log:

    PHY1 Triggerred!

    Setting trigger time is 17s983380000ns

    PHY1 event time is 17s983380000ns

    PHY2 event time is 1s7135864ns

    Timediff is 16976244136ns

    D0

    PHY1 Triggerred!

    Setting trigger time is 18s487120000ns

    PHY1 event time is 18s487120000ns

    PHY2 event time is 18s487120000ns

    Timediff is 0ns

    8th time, snapshot from oscilloscope:

  • Followed is implementation of  PHY2 synchronize to PHY1  source code when do above test: 

    NS_UINT SimpleSyncTwoPHY(RunTimeOpts *rtOpts, NS_BOOL SyncEth1ToEth0, NS_BOOL DoSync)
    {
    NS_UINT eventNum[2] = {0xFF,0xFF};
    NS_UINT riseFlag[2];
    NS_UINT eventsMissed[2];
    NS_UINT events;
    NS_STATUS status;
    int deltaRate;
    int WaitTime;
    NS_UINT x;

    NS_UINT phaseError;

    NS_BOOL negAdj;

    TimeInternal eventTime[2];
    TimeInternal TimeDiff;
    TimeInternal TimeDiffPhy1ToPhy2;
    TimeInternal TimeDiffPhy2ToPhy1;

    long long val;
    long long val1;
    long long val2;
    long long DeltaT;
    long long DeltaP;

    //Set MCU's SYNC_TRIGGER pin as input, to avoid conflict with PHY's trigger output
    FM3_GPIO->PFRA &= ~(1u<<0x0); // PA0, not special function
    FM3_GPIO->DDRA |= (1u<<0x0); // Set SYNC_TRIGGER pin as output
    *SYNC_TRIGGER_PIN = 0; //Initialize SYNC_TRIGGER_PIN at low level
    FM3_GPIO->DDRA &= ~(1u<<0x0); // Set SYNC_TRIGGER pin as input


    //Disconnect PHY1's GPIO3 from event 0
    PTPSetEventConfig(pEPL_HANDLE1, 0, FALSE, FALSE, FALSE, 0);
    //Disconnect PHY2's GPIO3 from event 0
    PTPSetEventConfig(pEPL_HANDLE2, 0, FALSE, FALSE, FALSE, 0);


    // Flush eth0 PHY's Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE1)))
    {
    if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE1, &eventNum[0], &riseFlag[0], &(eventTime[0].seconds),&eventTime[0].nanoseconds, &eventsMissed[0]);
    }
    else
    {
    break;
    }

    }


    // Flush eth1 PHY's Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE2)))
    {
    if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE2, &eventNum[1], &riseFlag[1], &(eventTime[1].seconds), &eventTime[1].nanoseconds, &eventsMissed[1]);
    }
    else
    {
    break;
    }
    }



    //Calculate the trigger timing offset 500ms from current PHY1's PTP time
    PTPClockReadCurrent(pEPL_HANDLE1, &(eventTime[0].seconds),&(eventTime[0].nanoseconds));
    val = (long long)(eventTime[0].seconds * 1e9) + (long long)eventTime[0].nanoseconds;
    val += 500000000;

    //Phase align the trigger signal
    val = val - val % 20000;

    eventTime[0].seconds = (int)(val / 1e9);
    eventTime[0].nanoseconds = (int)(val % (long long)1e9);



    //Set PHY1's GPIO3(SYNC_TRIGGER) as a trigger 1 output, and output a 1us positive pulse
    PTPCancelTrigger(pEPL_HANDLE1, 1);
    PTPSetTriggerConfig( pEPL_HANDLE1, 1, TRGOPT_PULSE | TRGOPT_NOTIFY_EN, 3);


    PTPArmTrigger( pEPL_HANDLE1, 1, eventTime[0].seconds, eventTime[0].nanoseconds,
    FALSE, FALSE, 10000, 10000);

    //Set PHY1's GPIO3(SYNC_TRIGGER) as a riging edge event number 0 capture
    PTPSetEventConfig(pEPL_HANDLE1, 0, TRUE, FALSE, TRUE, 3);

    //Set PHY2's GPIO3(SYNC_TRIGGER) as a riging edge event number 0 capture
    PTPSetEventConfig(pEPL_HANDLE2, 0, TRUE, FALSE, TRUE, 3);


    //Waiting for trigger 1 to trigger
    WaitTime = 0x10000000;
    status = PTPHasTriggerExpired(pEPL_HANDLE1,1);
    while((NS_STATUS_SUCCESS != status) && (WaitTime>0))
    {
    status = PTPHasTriggerExpired(pEPL_HANDLE1,1);
    WaitTime--;
    }


    if(!WaitTime)
    {

    printf("Error waiting for trigger!\n");
    return -1;
    }
    else
    {

    printf("PHY1 Triggerred!\n");
    }

    PTPCancelTrigger(pEPL_HANDLE1, 1);
    PTPSetTriggerConfig( pEPL_HANDLE1, 1, TRGOPT_PULSE | TRGOPT_NOTIFY_EN, 0);

    printf("Setting trigger time is %ds%dns\n", eventTime[0].seconds,eventTime[0].nanoseconds);

    // Flush Transmit and Receive Timestamps and get Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE1)))
    {
    if ( events & PTPEVT_TRANSMIT_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE1, &(eventTime[0].seconds), &(eventTime[0].nanoseconds),&eventsMissed[0]);
    else if ( events & PTPEVT_RECEIVE_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE1, &(eventTime[0].seconds), &(eventTime[0].nanoseconds),&eventsMissed[0]);
    else if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE1, &eventNum[0], &riseFlag[0], &(eventTime[0].seconds), &(eventTime[0].nanoseconds), &eventsMissed[0]);
    if(eventNum[0] & (1<<0))
    {
    break;
    }
    }
    }
    if(!(eventNum[0] & (1<<0)) )
    {
    printf("Error, PHY1 no SYNC_Trigger event captured!!!\n");
    return -1;
    }
    // Disconnect event 0 from GPIO 3
    PTPSetEventConfig( pEPL_HANDLE1, 0, FALSE, FALSE, FALSE, 0);

    printf("PHY1 event time is %ds%dns\n", eventTime[0].seconds, eventTime[0].nanoseconds);

    // Flush Transmit and Receive Timestamps and get Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE2)))
    {
    if ( events & PTPEVT_TRANSMIT_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE2, &(eventTime[1].seconds), &(eventTime[1].nanoseconds),&eventsMissed[1]);
    else if ( events & PTPEVT_RECEIVE_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE2, &(eventTime[1].seconds), &(eventTime[1].nanoseconds),&eventsMissed[1]);
    else if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE2, &eventNum[1], &riseFlag[1], &(eventTime[1].seconds), &(eventTime[1].nanoseconds), &eventsMissed[1]);
    if(eventNum[0] & (1<<0))
    {
    break;
    }
    }
    }
    if(!(eventNum[1] & (1<<0)) )
    {
    printf("Error, PHY2 no SYNC_Trigger event captured!!!\n");
    return -1;
    }
    // Disconnect event 0 from GPIO 3
    PTPSetEventConfig( pEPL_HANDLE2, 0, FALSE, FALSE, FALSE, 0);

    printf("PHY2 event time is %ds%dns\n", eventTime[1].seconds, eventTime[1].nanoseconds);

    subTime(&TimeDiffPhy1ToPhy2, &eventTime[0],&eventTime[1]);
    val = (long long)(TimeDiffPhy1ToPhy2.seconds * 1e9) + (long long)TimeDiffPhy1ToPhy2.nanoseconds;

    printf("Timediff is %lldns\n", val);

    val +=16;

    negAdj = FALSE;
    if(val < 0)
    negAdj = TRUE;

    TimeDiff.seconds = (int)(val / 1e9);
    TimeDiff.nanoseconds = (int)(val % (long long)1e9);

    PTPClockStepAdjustment( pEPL_HANDLE2 , abs(TimeDiff.seconds), abs(TimeDiff.nanoseconds), negAdj);




    //Second time trigger to confirm the synchronize result

    // Flush eth0 PHY's Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE1)))
    {
    if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE1, &eventNum[0], &riseFlag[0], &(eventTime[0].seconds),&eventTime[0].nanoseconds, &eventsMissed[0]);
    }
    else
    {
    break;
    }

    }


    // Flush eth1 PHY's Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE2)))
    {
    if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE2, &eventNum[1], &riseFlag[1], &(eventTime[1].seconds), &eventTime[1].nanoseconds, &eventsMissed[1]);
    }
    else
    {
    break;
    }
    }



    //Calculate the trigger timing offset 500ms from current PHY1's PTP time
    PTPClockReadCurrent(pEPL_HANDLE1, &(eventTime[0].seconds),&(eventTime[0].nanoseconds));
    val = (long long)(eventTime[0].seconds * 1e9) + (long long)eventTime[0].nanoseconds;
    val += 500000000;

    //Phase align the trigger signal
    val = val - val % 20000;

    eventTime[0].seconds = (int)(val / 1e9);
    eventTime[0].nanoseconds = (int)(val % (long long)1e9);

    //Set PHY1's GPIO3(SYNC_TRIGGER) as a trigger 1 output, and output a 1us positive pulse
    PTPCancelTrigger(pEPL_HANDLE1, 1);
    PTPSetTriggerConfig( pEPL_HANDLE1, 1, TRGOPT_PULSE | TRGOPT_NOTIFY_EN, 3);
    PTPArmTrigger( pEPL_HANDLE1, 1, eventTime[0].seconds, eventTime[0].nanoseconds,
    FALSE, FALSE, 10000, 10000);

    //Set PHY1's GPIO3(SYNC_TRIGGER) as a riging edge event number 0 capture
    PTPSetEventConfig(pEPL_HANDLE1, 0, TRUE, FALSE, TRUE, 3);

    //Set PHY2's GPIO3(SYNC_TRIGGER) as a riging edge event number 0 capture
    PTPSetEventConfig(pEPL_HANDLE2, 0, TRUE, FALSE, TRUE, 3);

    //Waiting for trigger 1 to trigger
    WaitTime = 0x10000000;
    status = PTPHasTriggerExpired(pEPL_HANDLE1,1);
    while((NS_STATUS_SUCCESS != status) && (WaitTime>0))
    {
    status = PTPHasTriggerExpired(pEPL_HANDLE1,1);
    WaitTime--;
    }


    if(!WaitTime)
    {

    printf("Error waiting for trigger!\n");
    return -1;
    }
    else
    {

    printf("PHY1 Triggerred!\n");
    }

    PTPCancelTrigger(pEPL_HANDLE1, 1);
    PTPSetTriggerConfig( pEPL_HANDLE1, 1, TRGOPT_PULSE | TRGOPT_NOTIFY_EN, 0);

    printf("Setting trigger time is %ds%dns\n", eventTime[0].seconds,eventTime[0].nanoseconds);

    // Flush Transmit and Receive Timestamps and get Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE1)))
    {
    if ( events & PTPEVT_TRANSMIT_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE1, &(eventTime[0].seconds), &(eventTime[0].nanoseconds),&eventsMissed[0]);
    else if ( events & PTPEVT_RECEIVE_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE1, &(eventTime[0].seconds), &(eventTime[0].nanoseconds),&eventsMissed[0]);
    else if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE1, &eventNum[0], &riseFlag[0], &(eventTime[0].seconds), &(eventTime[0].nanoseconds), &eventsMissed[0]);
    if(eventNum[0] & (1<<0))
    break;
    }
    }
    if(!(eventNum[0] & (1<<0)) )
    {
    printf("Error, PHY1 no SYNC_Trigger event captured!!!\n");
    return -1;
    }
    // Disconnect event 0 from GPIO 3
    PTPSetEventConfig( pEPL_HANDLE1, 0, FALSE, FALSE, FALSE, 0);

    printf("PHY1 event time is %ds%dns\n", eventTime[0].seconds, eventTime[0].nanoseconds);


    // Flush Transmit and Receive Timestamps and get Event Timestamp
    while ( (events = PTPCheckForEvents( pEPL_HANDLE2)))
    {
    if ( events & PTPEVT_TRANSMIT_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE2, &(eventTime[1].seconds), &(eventTime[1].nanoseconds),&eventsMissed[1]);
    else if ( events & PTPEVT_RECEIVE_TIMESTAMP_BIT)
    PTPGetTransmitTimestamp( pEPL_HANDLE2, &(eventTime[1].seconds), &(eventTime[1].nanoseconds),&eventsMissed[1]);
    else if ( events & PTPEVT_EVENT_TIMESTAMP_BIT)
    {
    PTPGetEvent(pEPL_HANDLE2, &eventNum[1], &riseFlag[1], &(eventTime[1].seconds), &(eventTime[1].nanoseconds), &eventsMissed[1]);
    if(eventNum[1] & (1<<0))
    break;
    }
    }
    if(!(eventNum[1] & (1<<0)) )
    {
    printf("Error, PHY2 no SYNC_Trigger event captured!!!\n");
    return -1;
    }
    // Disconnect event 0 from GPIO 3
    PTPSetEventConfig( pEPL_HANDLE2, 0, FALSE, FALSE, FALSE, 0);

    printf("PHY2 event time is %ds%dns\n", eventTime[1].seconds, eventTime[1].nanoseconds);

    subTime(&TimeDiffPhy1ToPhy2, &eventTime[0],&eventTime[1]);
    val = (long long)(TimeDiffPhy1ToPhy2.seconds * 1e9) + (long long)TimeDiffPhy1ToPhy2.nanoseconds;

    printf("Timediff is %lldns\n", val);

    PTPClockReadCurrent(pEPL_HANDLE1, &(eventTime[0].seconds),&(eventTime[0].nanoseconds));


    // Setup PHY1's PPS configuration
    PTPSetTriggerConfig( pEPL_HANDLE1, 0, TRGOPT_PULSE |TRGOPT_PERIODIC| TRGOPT_NOTIFY_EN, 0);
    PTPCancelTrigger( pEPL_HANDLE1, 0);
    PTPSetTriggerConfig( pEPL_HANDLE1, 0, TRGOPT_PULSE|TRGOPT_PERIODIC|TRGOPT_NOTIFY_EN, 1);
    PTPArmTrigger( pEPL_HANDLE1, 0, eventTime[0].seconds+2, 0,
    FALSE, FALSE, 500000000, 500000000);

    // Setup PHY2's PPS configuration
    PTPSetTriggerConfig( pEPL_HANDLE2, 0, TRGOPT_PULSE |TRGOPT_PERIODIC| TRGOPT_NOTIFY_EN, 0);
    PTPCancelTrigger( pEPL_HANDLE2, 0);
    PTPSetTriggerConfig( pEPL_HANDLE2, 0, TRGOPT_PULSE|TRGOPT_PERIODIC|TRGOPT_NOTIFY_EN, 1);
    PTPArmTrigger( pEPL_HANDLE2, 0, eventTime[0].seconds+2, 0,
    FALSE, FALSE, 500000000, 500000000);

    }

  • Thanks for the info. I relooked again at App Note and your clocking diagram. I believe you are "figure 6" clocking while for synchrnous ethernet, you need to follow "figure 7" clocking tree.

    The key difference is :

    1. CLK_OUT is configured to provide 50 Mhz RMII clock on Phy 1 towards MAC
    2. TX_CLK is configured to output 25 Mhz Clock synchrnouse to PTP clock of the Phy 1. This clock acts as input to Phy2.




    Regards,
    Geet
  • Yes, of course I am "Figure 6" clock mode.

    In the beginning I prefer the "Figure 7" clock mode too, however I found it require each MAC have individual REFCLK, unfortunately my MCU have only one common REFCLK share for two MACs, so I have to abandon it.

    Before I abandon it, I do a long time test for Figure 7 in followed condition:

    1. PHY1 and PHY2 both work at RMII Master mode

    2. Feed PHY1's X1 with 25MHz TCXO

    3. Set PHY1 (upstream port ) work at SYN_ETHER_EN enable mode

    4. Set PHY2 (downstream port) work at SYN_ETHER_EN disable mode

    5. Set PHY1's TX_CLK output 25MHz clock and feed to PHY2's X1 input

    6. Set PHY2 output 50MHz RMII clock to MCU's REFCLK.

    Above clocking is derived from Figure 7 except both PHY1 and PHY2 share the PHY2's RMII 50MHz clock. After long time test, I found the frame CRC error issue of communication in the path of MAC + PHY1 after several times power on test. Obviously, PHY1's RMII interface RX signal is phase-misalignment with PHY2's 50MHz RMII clock. That's why the CRC error issue occur. 

    In summary, because my MCU's limitation, using Figure 6 clock mode, it can work well in aspect of Ethernet communication, but unfortunately it cannot provide an accuracy PTP clock synchronization between two PHYs, using Figure 7 clock mode, RMII REFCLK phase-misalignment issue will occur inevitably. 

    Am I right?

    Or you have some other clocking proposal?  

       

  • Hello,

    Thanks for the details on experiment you have tried.  To achieve synchronous Ethernet, we shall stick to Figure 7 as the in this case only the clocks are phase locked.

    On your experiment with Figure 7:

      a. when you observe CRC errors, are these across all packets or some of the packets are corrupted ?

    b. Which Phy you observed the CRC error ?

    c. Did you look at phase difference between data and clock ?

    d.  Do you see RX_ERR as well ?

    Regards,
    Geet

  • >a. when you observe CRC errors, are these across all packets or some of the packets are corrupted ?
    Some of the packets, not all. However the error rate is very high sometimes.

    >b. Which Phy you observed the CRC error ?
    The PHY which not response for feed REFCLK to MAC will be CRC error. The other MAC+PHY without CRC error.

    >c. Did you look at phase difference between data and clock ?
    Yes, phase is changed every time I power on the system.
    I also try to observe each PHY's RMII clock phase, for PHY1, I set the CLKOUT to output the RMII clock, for PHY2, I set the RX_CLK to output RMII clock. When I check the phase between them, I found it change every time I power on the system. The phase error is so big that can not be ignored for meeting the RMII interface timing.

    >d. Do you see RX_ERR as well ?
    No, RX_ERR is OK

    I can confirm that if using Figure 7 clock diagram, the individual REFCLKs for each MAC+PHY pairs are very important. In my case, my MCU have two MACs however share the same REFCLK. So I can't use Figure 7, and Figure 6 is my only choice.

    In Figure 7, I can achieve the sub-nanosecond accuracy between PHY1 and PHY2, and I agree with you that Figure 7 is better choice for sub-nanosecond application.

    However I am strapped in Figure 6, I cannot change my platform now.

    I'd like to try the "plan B" you mentioned in Mar 13 reply. My idea is:
    1. Set up the Figure 6 clock diagram
    2. Let PHY1 output 125MHz ptp clock from CLKOUT pin
    3. Let PHY2's CLKOUT pin as ptp clock input pin.
    I think PHY1 and PHY2's PTP portion will work at same clock domain and with fixed phase different in this case, maybe it can achieve the sub-nanosecond accuracy.

    I will report you my result.
  • Sorry, I make a mistake.
    Plan B still has problem, even PHY1 and PHY2 are synchronized, however when PHY2 connect to its link partner, they can not achieve synchronization because PHY2's Ethernet clock and PTP clock are separated and not phase aligned, so that means PHY2's link partner cannot synchronize with PHY2's PTP clock.
    No resolution yet.

  • You need to find way to use the Figure 7. let me know if you need any further help.

    Regards,
    Geet