Skip to main content
Explorer
June 30, 2025
Question

STM32H743 PTP offload timestamps

  • June 30, 2025
  • 4 replies
  • 489 views

Hello all,

I am developing ptp master and slave with offload.

Now I have a master sending the sync

max65_0-1751294125207.png

and a slave sending delay_req:

max65_1-1751294193182.png

with the master sending back delay_resp:

max65_2-1751294248439.png

Given this message exchange, the slave should be able to correct its time, but, to do this, it needs some timestamp.

Referring to figure 788:

max65_3-1751294404413.png

How can I (the slave) get t1,..,t4?

Thank you

P.S.

Every delay_req has :
originTimestamp (seconds): 0
so it seems that hw does not correct the timestamp

    This topic has been closed for replies.

    4 replies

    Graduate II
    June 30, 2025

    The PTP offload does NOT do any time correction, it only takes care of the messaging, which is quite a lot.

    You need to get the t1 .. t4 timestamps from the TX & RX descriptors, then do the correction stuff by yourself.

     

    But I'm really curious, because last week I failed to get any message from the PTP offload.

    1) Is your master another STM32H7 ?

    2) What are your register settings / contents for 

    - ETH->MACTSCR

    - ETH->MACPOCR

    ETH->MACLMIR

    - ETH->MACIER

    ?

    ST doesn't give any answers concerning PTP offload.
    And that's very frustrating, I have all that ethernet stuff running smoothly (no HAL), but can't get this working...

     

    Graduate II
    June 30, 2025

    Warning: this is all theory by reference manual for the H723 .. H735 series - and I don't have this working!

    Timestamps & descriptors:

    TX:

    - set the TX timestamp enable interrupt: ETH->MACIER |= ETH_MACIER_TSIE;

    - get the TX timestamp in the interrupt handler from:
    ETH->MACTTSSNR and ETH->MACTTSSSR (attention: these registers are called MACTXTSSNR / MACTXTSSSR in RM0468)

     

    RX:

    - check each RX descriptor group for:
      - write back format:
        if( (pDmaRxDescrCur->DESC3 & ETH_DMADESC_CTXT) == 0 )

      - last descriptor in chain:
        if( pDmaRxDescrCur->DESC3 & ETH_DMADESC_LD )

      - valid & timestamp available:

        if( ((pDmaRxDescrCur->DESC3 & ETH_DMARXNDESCWBF_RS1V) != 0) &&
        ((pDmaRxDescrCur->DESC1 & ETH_DMARXNDESCWBF_TSA) != 0) )

      - then PTP message check, timestamp is in next descriptor (CONTEXT)

     
    				/* check message type for:
    				 *	SYNC 			-> t1 (slave, from master)
    				 *	DELAY REQUEST 	-> t3 (master, from slave)
    				 */
    				if( (pDmaRxDescrCur->DESC1 & ETH_DMARXNDESCWBF_PMT_SYNC) != 0 )
    				{
    					((EthDmaDescr_t *)pDmaRxDescrCur->pNext)->u32Flags |= ETH_DESCR_FLAG_RX_PTP_SYNC;
    				}
    				else if( (pDmaRxDescrCur->DESC1 & ETH_DMARXNDESCWBF_PMT_DREQ) != 0 )
    				{
    					((EthDmaDescr_t *)pDmaRxDescrCur->pNext)->u32Flags |= ETH_DESCR_FLAG_RX_PTP_DLRQ;
    				}
     
     
    That's at least working with PTP over UDP with LWIP.

     

     

    max65Author
    Explorer
    July 1, 2025

    Thank you @LCE , but I am not using lwip to send/receive udp packets, so it is not clear how can I get timestamps from tx/rx descriptors: can you spend some word about this?

     

    This is my code:

    void PTP_ini(bool master)
    {
     uint32_t mactscr = MACTSCR_TXTSSTSM | MACTSCR_TSIPENA | MACTSCR_TSVER2ENA | MACTSCR_TSCTRLSSR | MACTSCR_TSENA;
     if (master) {
     mactscr |= MACTSCR_SNAPTYPSEL(0) | MACTSCR_TSMSTRENA | MACTSCR_TSEVNTENA;
     }
     else {
     mactscr |= MACTSCR_SNAPTYPSEL(0) | MACTSCR_TSEVNTENA;
     }
     ETH->MACTSCR = mactscr;
    
     if (master) {
     // imposto data
     // clk_ptp_ref_i Digital input PTP reference clock input. This input is connected to eth_hclk clock
     uint32_t nani = 1000000000 / HAL_RCC_GetHCLKFreq();
     if (0 == nani) {
     nani = 1;
     }
     ETH->MACSSIR = MACSSIR_SSINC(nani);
     ETH->MACSTSUR = 1751269181;
     ETH->MACSTNUR = 0;
     // This bit should be zero before it is updated
     while ((ETH->MACTSCR & MACTSCR_TSINIT) == MACTSCR_TSINIT) {
     }
     ETH->MACTSCR |= MACTSCR_TSINIT;
     // This bit is reset when the initialization is	complete
     while ((ETH->MACTSCR & MACTSCR_TSINIT) == MACTSCR_TSINIT) {
     }
     }
    
     // offload
     uint32_t macpocr = MACPOCR_DN(0) | MACPOCR_PTOEN;
     if (master) {
     macpocr |= MACPOCR_ASYNCEN;
     ETH->MACLMIR = MACLMIR_LSI(1);
     }
     else {
     ETH->MACLMIR = MACLMIR_DRSYNCR(0);
     }
     ETH->MACPOCR = macpocr;
    
     // clockidentity || sourceportid ==
     // MACSPI2R || MACSPI1R || MACSPI0R
     uint32_t tmp;
     CONTROLLA(HAL_OK == HAL_RNG_GenerateRandomNumber(&hrng, &tmp));
     // sourceportid = 0x0001
     tmp &= 0xFFFF0000;
     tmp |= 1;
     ETH->MACSPI0R = tmp;
     CONTROLLA(HAL_OK == HAL_RNG_GenerateRandomNumber(&hrng, &tmp));
     ETH->MACSPI1R = tmp;
     CONTROLLA(HAL_OK == HAL_RNG_GenerateRandomNumber(&hrng, &tmp));
     tmp &= 0xFFFF;
     ETH->MACSPI2R = tmp;
    }

    Graduate II
    July 1, 2025

    Thanks for your setup code!

    Unfortunately there must be something else, I still don't get anything from the PTP offload - otherwise ETH is working - so maybe there's something blocking this ? 

     

    Anyway, are you already working somehow with the ETH's descriptors? Are you using the HAL driver for other ETH stuff? If yes, which IP stack if not LWIP?

    It's not that simple...
    You need to create an array and linked list of RX descriptors in a special internal SRAM range.

    These descriptors must be initialized and handed over to DMA by setting the OWN bit (mind the necessary memory barriers) (and probably others), and assigning buffer addresses, and, ... 

    Then the current RX descriptor can be polled by checking if DMA released it by resetting the OWN bit, then check some more descriptor bits, and so on.

     

    Although I don't like and use it, the ETH HAL function can be used, or used as a basis.

    max65Author
    Explorer
    July 1, 2025

    Hello @LCE , I am calling the function when the link is up, that is:

     

    	HAL_ETH_GetMACConfig(&heth, &MACConf) ;
    	MACConf.DuplexMode = fullduplex ? ETH_FULLDUPLEX_MODE : ETH_HALFDUPLEX_MODE ;
    	MACConf.Speed = centomega ? ETH_SPEED_100M : ETH_SPEED_10M ;
    	HAL_ETH_SetMACConfig(&heth, &MACConf) ;
    
    #ifdef USA_PTP
    	PTP_ini(false/true) ;
    #endif
    
    	HAL_NVIC_EnableIRQ(ETH_IRQn) ;
    
    	CONTROLLA(HAL_OK == HAL_ETH_Start_IT(&heth)) ;

     

    I am not receiving/trasmitting so no desc is involved (to partially confirm this, I have used "live watch" in iar ewarm, and I don't see any change)

     

    Graduate II
    July 1, 2025

    Check 

    ETH_DMARxDescListInit() in ETH HAL file.

    But mind the placement of the descriptors in SRAM! Maybe check some examples for your H743.

    You should start by reading the TX timestamps (master: SYNC, slave: Delay Request) when the interrupt occurs.

    In your PTP offload setup add the interrupt enable, then write an interrupt handler.

    /* enable interrupt for TX timestamp */
    ETH->MACIER |= ETH_MACIER_TSIE;
    
    ...
    
    void ETH_IRQHandler(void)
    {
    
    /* PTP target time reached ? */
    	if( ETH->MACTSSR & ETH_MACTSSR_TSTARGT0 )
    	{
    		PTP_TargetTime_IRQHandler();
    	}
    
    /* PTP offload TX timestamp available ? */
    	if( ETH->MACTSSR & ETH_MACTSSR_TXTSSIS )
    	{
    		PTP_TxTsis_IRQHandler();
    	}
    
    ...
    
    /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    /* ISR for PTP: TX timestamp */
    void PTP_TxTsis_IRQHandler(void)
    {
    	/* MUST read status register to reset interrupt (?) */
    	uint32_t u32TempReg = ETH->MACISR;
    	u32TempReg = ETH->MACTSSR;
    	UNUSED(u32TempReg);
    
    	/* read TX timestamp here ?
    	 *	NOTE: different register names in reference manual
    	 *		MACTTSSNR -> MACTXTSSNR
    	 *		MACTTSSSR -> MACTXTSSSR
    	 */
    	u32TxTsNano = ETH->MACTTSSNR;
    	u32TxTsSecs = ETH->MACTTSSSR;
    }