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 + TMS570LC43x Launchpad] - PTP1588 RX Timestamp

Other Parts Discussed in Thread: DP83630, HALCOGEN

Hi all,

Having had a brilliant experience with other PTP-enabled products from T.I (tiva processors), I have decided to go one step further and try the Precision PHYTER chips.

So far I have been able to run a ptpd v2 port I have within lwIP (running on a host timer interval of 10ms). The PTP is running on UDP obviously and in a 1-step configuration. Both the master and the slave is a launchpad with a phyter on it, unique MACs and static IPs. I have also been successful in producing a constant PPS output on a GPIO pin at a constant frequency and see it on the scope.

I am able to verify the sync message's timestamp on the slave is correct via wireshark, i.e., the timestamp in the sync message's header agrees - when printed on the serial port on the slave via the debugger interface - with the number in wireshark. So I can verify that the sync messages are sent once a second and that they arrive at the slave with the correct timestamp in the header.

The Problem:

I am having trouble reading the Receive timestamp (inside the main loop at the ptpd level), i.e., the time at which the sync message was received at the slave:

1) The PTP_STS register never gets updated, the RXTS_RDY field is always zero.

2) I enabled the interrupt RXTS_IE on a GPIO pin but it never gets asserted.

3) I tried enabling the SFD interrupt on a GPIO pin for both TX/RX and I CAN VERIFY that packets are being received and sent on the scope.

4) Disabled all sort of filters, hash values, status frames and any other functionality that would prevent the timestamps to be registered in their buffers/registers.

5) I am attempting 4 reads of the PTP_RXTS register after the initialisation just to make sure the buffer is not overflowed.

6) The results from reading the PTP_RXTS are always the same: time(s.ns)=1611751441.538009617, overflow=1, sequenceid=24593, message type=0, of which very little makes sense and they are the same EVERY time I read the register.


Any ideas regarding this are welcome.

Regards,

Evros

  • Hi Evros,

    The RXTS_RDY field will be cleared upon a read of PTP_RX_TS. When you are running the program are you actually clearing the interrupt before you check it?

    Kind regards,
    Ross
  • Hi Ross,

    Thank you for the quick response. I am afraid that this is not the case. Here is the initialisation procedure that I am following. The following lines are placed inside hdkif.c (lwIP port) at the end of hdkif_hw_init() after EMACMIIEnable() has been called and before the TX/RX interrupts are enabled.

    The register naming conventions are according to the datasheet and are self-explanatory regarding which bits are set, etc.

      // Select Page 4 and Disable PTP IN PTP_CTL
      MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_4);
      MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_CTL, (uint16)PTPCTL_PTP_DISABLE);
    
    // Set PTP_RATE to 0. MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_RATEH, (uint16)0); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_RATEL, (uint16)0);
    // Set PTP_TDR and Load PTP clock MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)0); // Nanoseconds[15:0] MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)0); // Nanoseconds[31:16] MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)0); // Seconds[15:0] MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)0); // Seconds[31:16] MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_CTL, (uint16)PTPCTL_PTP_LOAD_CLK);
    // Enable PTP in PTP_CTL MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_CTL, (uint16)PTPCTL_PTP_ENABLE);
    // Set up trigger PPS signal. MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_5); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TRIG,
    (uint16)(PTPTRIG_PULSE | PTPTRIG_CSEL_0 | PTPTRIG_TRIG_WR) ); // Arm the trigger MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_4); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_CTL,
    (uint16)(PTPCTL_PTP_TRIG_SEL_0 | PTPCTL_PTP_TRIG_LOAD) ); // Select trigger 0 for loading.
    uint32 expireTimeSeconds, expireTimeNanoSeconds, pulseWidth, pulseWidth2; // Set the PTP_TDR register with 8 16-bit value settings. expireTimeSeconds = 1; expireTimeNanoSeconds = 0; pulseWidth = 15259; pulseWidth2 = 15259; MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(expireTimeNanoSeconds & 0xFFFF)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(expireTimeNanoSeconds >> 16)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(expireTimeSeconds & 0xFFFF)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(expireTimeSeconds >> 16)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(pulseWidth & 0xFFFF)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(pulseWidth >> 16)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(pulseWidth2 & 0xFFFF)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TDR, (uint16)(pulseWidth2 >> 16)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_CTL,
    (uint16)(PTPCTL_PTP_TRIG_SEL_0 | PTPCTL_PTP_TRIG_EN) ); // Select trigger 0 for loading.
    // Enable Interrupt on TX and RX timestamp ready. MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_STS,
    (uint16)(PTPSTS_TXTS_IE | PTPSTS_RXTS_IE) );
    // Enable Transmit Timestamp operation MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PHY_PAGESEL,
    (uint16)PAGESEL_PAGE_5); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TXCFG0,
    (uint16)(PTPTXCFG0_SYNC_1STEP | PTPTXCFG0_IGNORE_2STEP | PTPTXCFG0_CRC_1STEP | PTPTXCFG0_TX_IPV4_EN | PTPTXCFG0_TX_TS_EN )); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_TXCFG1, (uint16)0x0000); // Set data and byte masks to 0.
    // Enable Receive Timestamp operation MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_5); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_RXCFG0,
    (uint16)(PTPRXCFG0_IP1588_EN_DFLT | PTPRXCFG0_IP1588_EN_ALT | PTPRXCFG0_IP1588_EN_SPEC | PTPRXCFG0_RX_IPV4_EN | PTPRXCFG0_RX_TS_EN) ); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_RXCFG1, (uint16)0x0000); // Disable masks. MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_RXCFG3,
    (uint16)(PTPRXCFG3_TS_MIN_IFG_C | PTPRXCFG3_ACC_UDP | PTPRXCFG3_ACC_CRC | PTPRXCFG3_PTP_DOMAIN_0)); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_PSF_CFG0, (uint16)0x0000); // Disable PSF MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_6); MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_RXHASH, (uint16)0x0000); // No hash filter. MDIOPhyRegWrite(hdkif->mdio_base, hdkif->phy_addr, (uint32)PTP_INTCTL, (uint16)PTPINTCTL_GPIO_4); uint16 sequenceId; uint8 messageType; uint8 overflowCount; uint16 sourceHash; uint32 temp_s; uint32 temp_ns; PHYTERGetRxTimeStamp(MDIO_0_BASE, 1, &temp_s, &temp_ns, &overflowCount, &sequenceId, &messageType, &sourceHash); PHYTERGetRxTimeStamp(MDIO_0_BASE, 1, &temp_s, &temp_ns, &overflowCount, &sequenceId, &messageType, &sourceHash); PHYTERGetRxTimeStamp(MDIO_0_BASE, 1, &temp_s, &temp_ns, &overflowCount, &sequenceId, &messageType, &sourceHash); PHYTERGetRxTimeStamp(MDIO_0_BASE, 1, &temp_s, &temp_ns, &overflowCount, &sequenceId, &messageType, &sourceHash);



    Then I attempt to read the PTP_STS and PHY_RXTSusing the following functions:

    void PHYTERGetRxTimeStamp(uint32 mdioBaseAddr, 	uint32 phyAddr,
    												uint32 	*time_s,
    												uint32 	*time_ns,
    												uint8	        *overflowCount,
    												uint16 	*sequenceId,
    												uint8	        *messageType,
    												uint16	*sourceHash)
    {
    	uint16 reg = 0x0000U;
    	uint16 *regPtr = ®
    
    	MDIOPhyRegWrite(mdioBaseAddr, phyAddr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_4);
    
    	(void)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PHY_RXTS, regPtr);
    	*time_ns = (uint32)reg;
            (void)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PHY_RXTS, regPtr);
            *overflowCount = (reg & 0xC000) >> 14;
            *time_ns |= (uint32)((reg & 0x3FFF) << 16);
    
    	(void)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PHY_RXTS, regPtr);
           *time_s = (uint32)reg;
    	(void)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PHY_RXTS, regPtr);
            *time_s |= (uint32)(reg << 16);
    
    	(void)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PHY_RXTS, sequenceId);
    
    	(void)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PHY_RXTS, regPtr);
    	*messageType = (uint8)(reg & 0xF000);
    	*sourceHash  = (uint16)(reg & 0x0FFF);
    
    	MDIOPhyRegWrite(mdioBaseAddr, phyAddr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_0);
    
    	return;
    }

     

    uint16 PHYTERGetRxTSRdy(uint32 mdioBaseAddr, 	uint32 phyAddr)
    {
    	uint16 reg = 0x0000U;
    	uint16 *regPtr = &reg;
    
    	boolean phy_read;
    
    	MDIOPhyRegWrite(mdioBaseAddr, phyAddr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_4);
    	phy_read = (uint8)MDIOPhyRegRead(mdioBaseAddr, phyAddr, (uint32)PTP_STS, regPtr);
    	MDIOPhyRegWrite(mdioBaseAddr, phyAddr, (uint32)PHY_PAGESEL, (uint16)PAGESEL_PAGE_0);
    
    
    	if (reg & PTPSTS_RXTS_RDY)
    		return TRUE;
    	else
    		return FALSE;
    }

    I would appreciate any ideas or brainstorming regarding this. I am not asking for someone to correct my code but guidance on the set of settings of the DP83630 so I can get the timestamps delivered to the registers. Which is a fairly simple scenario.

    Kind Regards,

    Evros

  • Hi Evros,

    Have you tried using a loopback cable to confirm that the 1588 packets you send on the TX are received? I would be interested to see if this simple loopback works and that you see RX 1588 indication.

    If this does not work then we would need to figure out more why the RX block is not registering the reception.

    Kind regards,
    Ross
  • Hi Ross,

    Thanks again for the info.

    I will make up a cable and give it a go.

    Is there anything related to the Launchpad that could prevent the RX lines from reaching the MCU, i.e., them being multiplexed with something else on the board ?

    Also remember, I am ABLE to receive the sync message and read the originTimestamp from it correctly but I am unable to read the RX timestamp for the sync packet.

    Regards,

    Evros

  • Hi Ross,

    Just tried the loopback cable. Unfortunately I got the same result again.

    I would like to ask if you can provide the minimal settings for the PHYTER to function as intended. I have followed the Software Development Guide and have also resorted to other device drivers as well but could not find anything wrong with my configuration.

    Regards,

    Evros

  • Hi Evros,

    Let me look this over a bit more right now and I'll send you some suggestions later today.

    Kind regards,
    Ross
  • Hi Ross,

    I appreciate your help. I got a bit fixated on using this PHYTER as it will solve a bunch of issues and hopefully for many years to come.

    I hope you can help me resolve this. I am convinced it must be a very-very minor detail.

    I kept going back to the initialisation of the PHY in the lwip port (used in the activewebserver demo) and could not find anything wrong with it.

    Regards,

    Evros

  • Hi Ross,

    I managed to resolve this. To be frank I am not sure at the moment what the case must have been; here is the short story:

    I went through the HALCOGEN again to make sure everything was correct and I accidentally re-generated the code. This resulted in the loss of the functions I had written related to the PHYTER inside the Phyter's driver. I rewrote the functions in the same way I did before but this resulted in fixing my issue. This means I must have been doing a mistake somewhere that got corrected when I rewrote the functions.

    In any case, consider this closed please.

    I would like to thank you and your team there for your excellent work and promptness.

    Regards,
    Evros
  • Hi Evros,
    Glad to hear this is resolved. Please let us know if you run into any other issues with the PHY.
    Kind regards,
    Ross
  • Hi Evros,

    I think "DP83630 + TMS570LC43x Launchpad" solution is cheapest choice to verify the accuracy of 1588 in clock synchronous  mode.

    You did great attempt to do the migration of code from PC version EPL C library to  TMS570LC43x  launchpad!

    Hope you can share the progress to all of us, especially the performance of PTP synchronous.