Skip to content

Commit

Permalink
arch/arm64: Fix clock drift from tick timer.
Browse files Browse the repository at this point in the history
In the previous implementation, when the current timer count just exceeds the next tick time, it will still cause clock drift. This commit fixed clock drift by using the abosolute ticks (clock_systime_tick() + ticks).

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
  • Loading branch information
Fix-Point committed Oct 10, 2024
1 parent 90836e5 commit 8b9a8b9
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 10 deletions.
15 changes: 12 additions & 3 deletions arch/arm64/src/common/arm64_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
#define ARM_ARCH_TIMER_PRIO IRQ_DEFAULT_PRIORITY
#define ARM_ARCH_TIMER_FLAGS IRQ_TYPE_LEVEL

#define ARM_ARCH_TIMER_UNINITIALIZED_TICK ((UINT64_MAX / TICK_PER_SEC) + 1)

/****************************************************************************
* Private Types
****************************************************************************/
Expand Down Expand Up @@ -286,9 +288,14 @@ static int arm64_tick_start(struct oneshot_lowerhalf_s *lower,

priv->running = this_cpu();

next_cycle =
arm64_arch_timer_count() / priv->cycle_per_tick * priv->cycle_per_tick +
ticks * priv->cycle_per_tick;
/* When we first set the timer, we should get the current tick */

if (g_current_tick == ARM_ARCH_TIMER_UNINITIALIZED_TICK)
{
lower->ops->tick_current(lower, &g_current_tick);
}

next_cycle = (g_current_tick + ticks) * priv->cycle_per_tick;

arm64_arch_timer_set_compare(next_cycle);
arm64_arch_timer_set_irq_mask(false);
Expand Down Expand Up @@ -381,6 +388,8 @@ struct oneshot_lowerhalf_s *arm64_oneshot_initialize(void)
priv->cycle_per_tick = arm64_arch_timer_get_cntfrq() / TICK_PER_SEC;
tmrinfo("cycle_per_tick %" PRIu64 "\n", priv->cycle_per_tick);

g_current_tick = ARM_ARCH_TIMER_UNINITIALIZED_TICK;

/* Attach handler */

irq_attach(ARM_ARCH_TIMER_IRQ,
Expand Down
20 changes: 14 additions & 6 deletions drivers/timers/arch_alarm.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,19 @@
#define CONFIG_BOARD_LOOPSPERUSEC ((CONFIG_BOARD_LOOPSPERMSEC+500)/1000)

/****************************************************************************
* Private Data
* Public Data
****************************************************************************/

static FAR struct oneshot_lowerhalf_s *g_oneshot_lower;

#ifndef CONFIG_SCHED_TICKLESS
static clock_t g_current_tick;
clock_t g_current_tick;
#endif

/****************************************************************************
* Private Data
****************************************************************************/

static FAR struct oneshot_lowerhalf_s *g_oneshot_lower;

/****************************************************************************
* Private Functions
****************************************************************************/
Expand Down Expand Up @@ -117,6 +121,8 @@ static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower,
FAR void *arg)
{
clock_t now;
clock_t diff;
clock_t chase;
ONESHOT_TICK_CURRENT(g_oneshot_lower, &now);

#ifdef CONFIG_SCHED_TICKLESS
Expand All @@ -128,6 +134,8 @@ static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower,
* atomically w. respect to a HW timer
*/

diff = now - g_current_tick;
g_current_tick = now;
ONESHOT_TICK_START(g_oneshot_lower, oneshot_callback, NULL, 1);

/* It is always an error if this progresses more than 1 tick at a time.
Expand All @@ -139,11 +147,11 @@ static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower,

/* DEBUGASSERT(now - g_current_tick <= 1); */

while (now - g_current_tick > 0)
for (chase = 0; chase < diff; chase++)
{
g_current_tick++;
nxsched_process_timer();
}

#endif
}

Expand Down
8 changes: 8 additions & 0 deletions include/nuttx/timers/arch_alarm.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@
#include <nuttx/config.h>
#include <nuttx/timers/oneshot.h>

/****************************************************************************
* Public Data
****************************************************************************/

#ifndef CONFIG_SCHED_TICKLESS
extern clock_t g_current_tick;
#endif

/****************************************************************************
* Public Function Prototypes
****************************************************************************/
Expand Down
2 changes: 1 addition & 1 deletion sched/semaphore/sem_tickwait.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ int nxsem_tickwait(FAR sem_t *sem, uint32_t delay)

int nxsem_tickwait_uninterruptible(FAR sem_t *sem, uint32_t delay)
{
clock_t end = clock_systime_ticks() + delay + 1;
clock_t end = clock_systime_ticks() + delay;
int ret;

for (; ; )
Expand Down

0 comments on commit 8b9a8b9

Please sign in to comment.