Skip to content

Commit ba66f71

Browse files
Simon Eggermmahadevan108
authored andcommitted
Add Relative Clock Jump
While ENET_Ptp1588SetTimer provides a mechanism to set the clock to an absolute time value, this often introduces additional software delays. In contrast, ENET_Ptp1588JumpTimer uses a relative offset in case we already have to hardware timestamps. Signed-off-by: Simon Egger <[email protected]>
1 parent 7bf6f09 commit ba66f71

File tree

2 files changed

+112
-7
lines changed

2 files changed

+112
-7
lines changed

mcux/mcux-sdk-ng/drivers/enet/fsl_enet.c

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@
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
*

mcux/mcux-sdk-ng/drivers/enet/fsl_enet.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,18 @@ static inline uint32_t ENET_Ptp1588GetChannelCaptureValue(ENET_Type *base, enet_
19731973
*/
19741974
void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime);
19751975

1976+
/*!
1977+
* @brief Adjusts the ENET PTP 1588 timer by jumping a relative time difference.
1978+
*
1979+
* Compared to ENET_Ptp1588SetTimer, this function yields more accurate results when
1980+
* the relative time difference between the PTP clock and the target clock is known
1981+
* (e.g., through a capture event retrieved by ENET_Ptp1588GetChannelCaptureValue).
1982+
*
1983+
* @param base ENET peripheral base address.
1984+
* @param nanosecondDiff The offset that is added/subtracted from the current PTP time
1985+
*/
1986+
void ENET_Ptp1588JumpTimer(ENET_Type *base, int64_t nanosecondDiff);
1987+
19761988
/*!
19771989
* @brief The IEEE 1588 PTP time stamp interrupt handler.
19781990
*

0 commit comments

Comments
 (0)