|
@@ -25,6 +25,10 @@
|
|
|
static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
|
|
|
|
|
|
#ifdef RT_USING_TIMER_SOFT
|
|
|
+
|
|
|
+#define RT_SOFT_TIMER_IDLE 1
|
|
|
+#define RT_SOFT_TIMER_BUSY 0
|
|
|
+
|
|
|
#ifndef RT_TIMER_THREAD_STACK_SIZE
|
|
|
#define RT_TIMER_THREAD_STACK_SIZE 512
|
|
|
#endif
|
|
@@ -33,6 +37,8 @@ static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
|
|
|
#define RT_TIMER_THREAD_PRIO 0
|
|
|
#endif
|
|
|
|
|
|
+/* soft timer status */
|
|
|
+static rt_uint8_t soft_timer_status = RT_SOFT_TIMER_IDLE;
|
|
|
/* soft timer list */
|
|
|
static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
|
|
|
static struct rt_thread timer_thread;
|
|
@@ -221,6 +227,8 @@ rt_err_t rt_timer_detach(rt_timer_t timer)
|
|
|
level = rt_hw_interrupt_disable();
|
|
|
|
|
|
_rt_timer_remove(timer);
|
|
|
+ /* stop timer */
|
|
|
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
|
|
|
/* enable interrupt */
|
|
|
rt_hw_interrupt_enable(level);
|
|
@@ -284,6 +292,8 @@ rt_err_t rt_timer_delete(rt_timer_t timer)
|
|
|
level = rt_hw_interrupt_disable();
|
|
|
|
|
|
_rt_timer_remove(timer);
|
|
|
+ /* stop timer */
|
|
|
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
|
|
|
/* enable interrupt */
|
|
|
rt_hw_interrupt_enable(level);
|
|
@@ -408,7 +418,8 @@ rt_err_t rt_timer_start(rt_timer_t timer)
|
|
|
if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
|
|
|
{
|
|
|
/* check whether timer thread is ready */
|
|
|
- if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
|
|
|
+ if ((soft_timer_status == RT_SOFT_TIMER_IDLE) &&
|
|
|
+ ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND))
|
|
|
{
|
|
|
/* resume timer thread to check soft timer */
|
|
|
rt_thread_resume(&timer_thread);
|
|
@@ -445,13 +456,12 @@ rt_err_t rt_timer_stop(rt_timer_t timer)
|
|
|
level = rt_hw_interrupt_disable();
|
|
|
|
|
|
_rt_timer_remove(timer);
|
|
|
+ /* change status */
|
|
|
+ timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
|
|
|
/* enable interrupt */
|
|
|
rt_hw_interrupt_enable(level);
|
|
|
|
|
|
- /* change stat */
|
|
|
- timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
-
|
|
|
return RT_EOK;
|
|
|
}
|
|
|
RTM_EXPORT(rt_timer_stop);
|
|
@@ -467,10 +477,13 @@ RTM_EXPORT(rt_timer_stop);
|
|
|
*/
|
|
|
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
|
|
|
{
|
|
|
+ register rt_base_t level;
|
|
|
+
|
|
|
/* timer check */
|
|
|
RT_ASSERT(timer != RT_NULL);
|
|
|
RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
|
|
|
|
|
|
+ level = rt_hw_interrupt_disable();
|
|
|
switch (cmd)
|
|
|
{
|
|
|
case RT_TIMER_CTRL_GET_TIME:
|
|
@@ -505,6 +518,7 @@ rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
+ rt_hw_interrupt_enable(level);
|
|
|
|
|
|
return RT_EOK;
|
|
|
}
|
|
@@ -521,6 +535,7 @@ void rt_timer_check(void)
|
|
|
struct rt_timer *t;
|
|
|
rt_tick_t current_tick;
|
|
|
register rt_base_t level;
|
|
|
+ rt_list_t list = RT_LIST_OBJECT_INIT(list);
|
|
|
|
|
|
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
|
|
|
|
|
@@ -544,7 +559,12 @@ void rt_timer_check(void)
|
|
|
|
|
|
/* remove timer from timer list firstly */
|
|
|
_rt_timer_remove(t);
|
|
|
-
|
|
|
+ if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC))
|
|
|
+ {
|
|
|
+ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
+ }
|
|
|
+ /* add timer to temporary list */
|
|
|
+ rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
|
|
|
/* call timeout function */
|
|
|
t->timeout_func(t->parameter);
|
|
|
|
|
@@ -554,6 +574,12 @@ void rt_timer_check(void)
|
|
|
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
|
|
|
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
|
|
|
|
|
|
+ /* Check whether the timer object is detached or started again */
|
|
|
+ if (rt_list_isempty(&list))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
|
|
|
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
|
|
|
{
|
|
@@ -561,14 +587,8 @@ void rt_timer_check(void)
|
|
|
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
rt_timer_start(t);
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- /* stop timer */
|
|
|
- t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
- }
|
|
|
}
|
|
|
- else
|
|
|
- break;
|
|
|
+ else break;
|
|
|
}
|
|
|
|
|
|
/* enable interrupt */
|
|
@@ -589,18 +609,20 @@ rt_tick_t rt_timer_next_timeout_tick(void)
|
|
|
|
|
|
#ifdef RT_USING_TIMER_SOFT
|
|
|
/**
|
|
|
- * This function will check timer list, if a timeout event happens, the
|
|
|
+ * This function will check software-timer list, if a timeout event happens, the
|
|
|
* corresponding timeout function will be invoked.
|
|
|
*/
|
|
|
void rt_soft_timer_check(void)
|
|
|
{
|
|
|
rt_tick_t current_tick;
|
|
|
struct rt_timer *t;
|
|
|
+ register rt_base_t level;
|
|
|
+ rt_list_t list = RT_LIST_OBJECT_INIT(list);
|
|
|
|
|
|
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
|
|
|
|
|
|
- /* lock scheduler */
|
|
|
- rt_enter_critical();
|
|
|
+ /* disable interrupt */
|
|
|
+ level = rt_hw_interrupt_disable();
|
|
|
|
|
|
while (!rt_list_isempty(&rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
|
|
|
{
|
|
@@ -619,17 +641,32 @@ void rt_soft_timer_check(void)
|
|
|
|
|
|
/* remove timer from timer list firstly */
|
|
|
_rt_timer_remove(t);
|
|
|
+ if (!(t->parent.flag & RT_TIMER_FLAG_PERIODIC))
|
|
|
+ {
|
|
|
+ t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
+ }
|
|
|
+ /* add timer to temporary list */
|
|
|
+ rt_list_insert_after(&list, &(t->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
|
|
|
+
|
|
|
+ soft_timer_status = RT_SOFT_TIMER_BUSY;
|
|
|
+ /* enable interrupt */
|
|
|
+ rt_hw_interrupt_enable(level);
|
|
|
|
|
|
- /* not lock scheduler when performing timeout function */
|
|
|
- rt_exit_critical();
|
|
|
/* call timeout function */
|
|
|
t->timeout_func(t->parameter);
|
|
|
|
|
|
RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
|
|
|
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
|
|
|
|
|
|
- /* lock scheduler */
|
|
|
- rt_enter_critical();
|
|
|
+ /* disable interrupt */
|
|
|
+ level = rt_hw_interrupt_disable();
|
|
|
+
|
|
|
+ soft_timer_status = RT_SOFT_TIMER_IDLE;
|
|
|
+ /* Check whether the timer object is detached or started again */
|
|
|
+ if (rt_list_isempty(&list))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
|
|
|
(t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
|
|
@@ -638,17 +675,11 @@ void rt_soft_timer_check(void)
|
|
|
t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
rt_timer_start(t);
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- /* stop timer */
|
|
|
- t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
|
|
|
- }
|
|
|
}
|
|
|
else break; /* not check anymore */
|
|
|
}
|
|
|
-
|
|
|
- /* unlock scheduler */
|
|
|
- rt_exit_critical();
|
|
|
+ /* enable interrupt */
|
|
|
+ rt_hw_interrupt_enable(level);
|
|
|
|
|
|
RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
|
|
|
}
|