3030/*! @brief NanoSecond in one second. */
3131#define ENET_NANOSECOND_ONE_SECOND 1000000000U
3232
33+ /* @brief Floor division which always rounds towards negative infinity.
34+ * Note that, in contrast, integer division would round towards zero. */
35+ #define DIV_FLOOR (x , y ) \
36+ (((x) >= 0 || (x) % (y) == 0) ? (x) / (y) : (x) / (y) - 1)
37+
3338#if defined(ENET_RSTS_N )
3439#define ENET_RESETS_ARRAY ENET_RSTS_N
3540#elif defined(ENET_RSTS )
@@ -2943,17 +2948,12 @@ void ENET_Ptp1588StartTimer(ENET_Type *base, uint32_t ptpClkSrc)
29432948}
29442949
29452950/*!
2946- * brief Gets the current ENET time from the PTP 1588 timer.
2947- * Interrupts are not disabled.
2951+ * @brief Initiates a PTP timer capture and blocks until the timestamp is available
29482952 *
29492953 * param base ENET peripheral base address.
29502954 * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
2951- * param ptpTime The PTP timer structure.
29522955 */
2953- void ENET_Ptp1588GetTimerNoIrqDisable (ENET_Type * base , enet_handle_t * handle , enet_ptp_time_t * ptpTime )
2954- {
2955- /* Get the current PTP time. */
2956- ptpTime -> second = handle -> msTimerSecond ;
2956+ static void ENET_Ptp1588CaptureBlocking (ENET_Type * base , enet_handle_t * handle ) {
29572957 /* Get the nanosecond from the master timer. */
29582958 base -> ATCR |= ENET_ATCR_CAPTURE_MASK ;
29592959
@@ -2971,6 +2971,23 @@ void ENET_Ptp1588GetTimerNoIrqDisable(ENET_Type *base, enet_handle_t *handle, en
29712971 {
29722972 }
29732973#endif
2974+ }
2975+
2976+ /*!
2977+ * brief Gets the current ENET time from the PTP 1588 timer.
2978+ * Interrupts are not disabled.
2979+ *
2980+ * param base ENET peripheral base address.
2981+ * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init.
2982+ * param ptpTime The PTP timer structure.
2983+ */
2984+ void ENET_Ptp1588GetTimerNoIrqDisable (ENET_Type * base , enet_handle_t * handle , enet_ptp_time_t * ptpTime )
2985+ {
2986+ /* Get the current PTP time. */
2987+ ptpTime -> second = handle -> msTimerSecond ;
2988+
2989+ /* Capture current time in ATVR */
2990+ ENET_Ptp1588CaptureBlocking (base , handle );
29742991
29752992 /* Get the captured time. */
29762993 ptpTime -> nanosecond = base -> ATVR ;
@@ -3029,6 +3046,82 @@ void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_
30293046 EnableGlobalIRQ (primask );
30303047}
30313048
3049+ /*!
3050+ * @brief Adjusts the ENET PTP 1588 timer by jumping a relative time difference.
3051+ *
3052+ * Compared to ENET_Ptp1588SetTimer, this function yields more accurate results when
3053+ * the relative time difference between the PTP clock and the target clock is known
3054+ * (e.g., through a capture event retrieved by ENET_Ptp1588GetChannelCaptureValue).
3055+ *
3056+ * @param base ENET peripheral base address.
3057+ * @param nanosecondDiff The offset that is added/subtracted from the current PTP time
3058+ */
3059+ void ENET_Ptp1588JumpTimer (ENET_Type * base , int64_t nanosecondDiff )
3060+ {
3061+ uint32_t instance = ENET_GetInstance (base );
3062+ enet_handle_t * handle = s_ENETHandle [instance ];
3063+
3064+ /* Disables interrupts */
3065+ uint32_t primask = DisableGlobalIRQ ();
3066+ ENET_Ptp1588CaptureBlocking (base , handle );
3067+
3068+ if (nanosecondDiff >= 0 )
3069+ {
3070+ uint32_t nanosecondTime = base -> ATVR % ENET_NANOSECOND_ONE_SECOND ;
3071+ uint64_t secondDiff = (uint64_t )nanosecondDiff / ENET_NANOSECOND_ONE_SECOND ;
3072+
3073+ nanosecondTime += (uint32_t )nanosecondDiff % ENET_NANOSECOND_ONE_SECOND ;
3074+
3075+ /* Increment secondDiff in case of nanosecond overflow */
3076+ if (nanosecondTime >= ENET_NANOSECOND_ONE_SECOND )
3077+ {
3078+ secondDiff ++ ;
3079+ }
3080+
3081+ /* Abort without changes in case handle->msTimerSecond would overflow */
3082+ if (UINT64_MAX - secondDiff < handle -> msTimerSecond )
3083+ {
3084+ /* Enables the interrupt. */
3085+ EnableGlobalIRQ (primask );
3086+
3087+ return ;
3088+ }
3089+
3090+ handle -> msTimerSecond += secondDiff ;
3091+ base -> ATVR = nanosecondTime % ENET_NANOSECOND_ONE_SECOND ;
3092+ } else
3093+ {
3094+ /* Note that nanosecondDiff + (int64_t)nanosecondTime does not result in an overflow
3095+ * as nanosecondDiff < 0 and 0 <= nanosecondTime < 1e9. */
3096+ int32_t nanosecondTime = (int32_t )(base -> ATVR % ENET_NANOSECOND_ONE_SECOND );
3097+ int64_t secondDiff = DIV_FLOOR (nanosecondDiff + (int64_t )nanosecondTime ,
3098+ (int64_t )ENET_NANOSECOND_ONE_SECOND );
3099+
3100+ nanosecondTime += (int32_t )(nanosecondDiff % (int64_t )ENET_NANOSECOND_ONE_SECOND );
3101+
3102+ /* Avoid negative overflow by setting PTP time to zero in this case */
3103+ if (handle -> msTimerSecond < INT64_MAX && (int64_t )handle -> msTimerSecond < - secondDiff )
3104+ {
3105+ handle -> msTimerSecond = 0 ;
3106+ base -> ATVR = 0 ;
3107+
3108+ /* Enables the interrupt. */
3109+ EnableGlobalIRQ (primask );
3110+
3111+ return ;
3112+ }
3113+
3114+ /* Note that simply doing base->ATVR = nanosecondTime % ENET_NANOSECOND_ONE_SECOND
3115+ * could result in an uint32_t underflow if nanosecondDiff is negative. */
3116+ handle -> msTimerSecond -= (uint64_t )(- secondDiff );
3117+ base -> ATVR = ((uint32_t )nanosecondTime + ENET_NANOSECOND_ONE_SECOND ) %
3118+ ENET_NANOSECOND_ONE_SECOND ;
3119+ }
3120+
3121+ /* Enables the interrupt. */
3122+ EnableGlobalIRQ (primask );
3123+ }
3124+
30323125/*!
30333126 * brief Adjusts the ENET PTP 1588 timer.
30343127 *
0 commit comments