mirror of
https://github.com/apache/nuttx.git
synced 2026-05-28 11:56:10 +08:00
arch/stm32f7: Fixes bug in tickless driver where the compare register is set to a value less than the current time.
This commit is contained in:
committed by
Xiang Xiao
parent
ac7e5de5ae
commit
e5be32ac21
@@ -139,7 +139,7 @@ struct stm32_tickless_s
|
|||||||
volatile bool pending; /* True: pending task */
|
volatile bool pending; /* True: pending task */
|
||||||
uint32_t period; /* Interval period */
|
uint32_t period; /* Interval period */
|
||||||
uint32_t base;
|
uint32_t base;
|
||||||
#if CONFIG_SCHED_TICKLESS_ALARM
|
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||||
uint64_t last_alrm;
|
uint64_t last_alrm;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -393,6 +393,17 @@ static int stm32_tickless_handler(int irq, void *context, void *arg)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: stm32_get_counter
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static uint64_t stm32_get_counter(void)
|
||||||
|
{
|
||||||
|
return ((uint64_t)g_tickless.overflow << 32) |
|
||||||
|
STM32_TIM_GETCOUNTER(g_tickless.tch);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -988,22 +999,43 @@ int up_timer_start(FAR const struct timespec *ts)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_TICKLESS_ALARM
|
||||||
int up_alarm_start(FAR const struct timespec *ts)
|
int up_alarm_start(FAR const struct timespec *ts)
|
||||||
{
|
{
|
||||||
|
size_t offset = 1;
|
||||||
uint64_t tm = ((uint64_t)ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec) /
|
uint64_t tm = ((uint64_t)ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec) /
|
||||||
NSEC_PER_TICK;
|
NSEC_PER_TICK;
|
||||||
uint64_t counter = ((uint64_t)g_tickless.overflow << 32) |
|
irqstate_t flags;
|
||||||
STM32_TIM_GETCOUNTER(g_tickless.tch);
|
|
||||||
|
|
||||||
g_tickless.last_alrm = tm;
|
flags = enter_critical_section();
|
||||||
|
|
||||||
int32_t diff = tm / NSEC_PER_TICK + counter;
|
|
||||||
|
|
||||||
STM32_TIM_SETCOMPARE(g_tickless.tch, CONFIG_STM32F7_TICKLESS_CHANNEL, tm);
|
STM32_TIM_SETCOMPARE(g_tickless.tch, CONFIG_STM32F7_TICKLESS_CHANNEL, tm);
|
||||||
|
|
||||||
stm32_tickless_ackint(g_tickless.channel);
|
stm32_tickless_ackint(g_tickless.channel);
|
||||||
stm32_tickless_enableint(CONFIG_STM32F7_TICKLESS_CHANNEL);
|
stm32_tickless_enableint(CONFIG_STM32F7_TICKLESS_CHANNEL);
|
||||||
|
|
||||||
|
g_tickless.pending = true;
|
||||||
|
|
||||||
|
/* We must protect for a race condition here with very small differences
|
||||||
|
* between the time of the alarm and the time now. We must ensure that the
|
||||||
|
* compare register is set, and interrupts are enabled BEFORE the rising edge
|
||||||
|
* of the clock when COUNT==COMPARE. Otherwise, we cannot be sure we are
|
||||||
|
* going to get the interrupt. If we didn't catch this case, we wouldn't
|
||||||
|
* interrupt until a full loop of the clock.
|
||||||
|
*
|
||||||
|
* Since we can't make assumptions about the clock speed and tick rate,
|
||||||
|
* we simply keep adding an offset to the current time, until we can leave
|
||||||
|
* certain that the interrupt is going to fire as soon as we leave the
|
||||||
|
* critical section.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (tm <= stm32_get_counter())
|
||||||
|
{
|
||||||
|
tm = stm32_get_counter() + offset++;
|
||||||
|
STM32_TIM_SETCOMPARE(g_tickless.tch, CONFIG_STM32F7_TICKLESS_CHANNEL, tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,5 +1051,6 @@ int up_alarm_cancel(FAR struct timespec *ts)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* CONFIG_SCHED_TICKLESS */
|
#endif /* CONFIG_SCHED_TICKLESS */
|
||||||
|
|||||||
Reference in New Issue
Block a user