From 8c8aa4418b22a97a3cd2c9a27af1c81756fad4d8 Mon Sep 17 00:00:00 2001 From: "lijin.unix" Date: Tue, 22 Dec 2009 15:06:27 +0000 Subject: [PATCH] add soft timer.other's platform maybe compiled err,pls add some macro definition in rtconfig.h. ( RT_TIMER_THREAD_STACK_SIZE RT_TIMER_THREAD_PRIO RT_TIMER_EX_TICKS_PER_SEC) git-svn-id: https://rt-thread.googlecode.com/svn/trunk@215 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- bsp/lpc2478/rtconfig.h | 7 ++ include/rtdef.h | 3 + src/timer.c | 152 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 161 insertions(+), 1 deletion(-) diff --git a/bsp/lpc2478/rtconfig.h b/bsp/lpc2478/rtconfig.h index 249945b009..449d4c3ef1 100644 --- a/bsp/lpc2478/rtconfig.h +++ b/bsp/lpc2478/rtconfig.h @@ -14,6 +14,13 @@ /* Tick per Second*/ #define RT_TICK_PER_SECOND 100 +#define RT_TIMER_THREAD_STACK_SIZE 512 + +#define RT_TIMER_THREAD_PRIO 1 + /* Rate at which timer management task runs (Hz) */ +#define RT_TIMER_EX_TICKS_PER_SEC 10 + + /* SECTION: RT_DEBUG */ /* Thread Debug*/ /* #define RT_THREAD_DEBUG */ diff --git a/include/rtdef.h b/include/rtdef.h index 5979b45404..cc36b95b68 100644 --- a/include/rtdef.h +++ b/include/rtdef.h @@ -234,6 +234,9 @@ struct rt_object_information #define RT_TIMER_FLAG_ONE_SHOT 0x0 /* one shot timer. */ #define RT_TIMER_FLAG_PERIODIC 0x2 /* periodic timer. */ +#define RT_TIMER_FLAG_HARD_TIMER 0x0 /* hard timer,the timer's callback function will be called in tick isr. */ +#define RT_TIMER_FLAG_SOFT_TIMER 0x4 /* soft timer,the timer's callback function will be called in timer thread. */ + #define RT_TIMER_CTRL_SET_TIME 0x0 /* set timer. */ #define RT_TIMER_CTRL_GET_TIME 0x1 /* get timer. */ #define RT_TIMER_CTRL_SET_ONESHOT 0x2 /* change timer to one shot. */ diff --git a/src/timer.c b/src/timer.c index f35ce8e964..cf395cc3ea 100644 --- a/src/timer.c +++ b/src/timer.c @@ -14,6 +14,7 @@ * 2006-06-04 Bernard implement rt_timer_control * 2006-08-10 Bernard fix the periodic timer bug * 2006-09-03 Bernard implement rt_timer_detach + * 2009-11-11 LiJin add soft timer */ #include @@ -22,8 +23,13 @@ #include "kservice.h" /* #define TIMER_DEBUG */ + +/* hard timer list */ static rt_list_t rt_timer_list; +/* soft timer list */ +static rt_list_t rt_soft_timer_list; + #ifdef RT_USING_HOOK extern void (*rt_object_take_hook)(struct rt_object* object); extern void (*rt_object_put_hook)(struct rt_object* object); @@ -57,6 +63,7 @@ void rt_timer_timeout_sethook(void (*hook)(struct rt_timer* timer)) void rt_system_timer_init() { rt_list_init(&rt_timer_list); + rt_list_init(&rt_soft_timer_list); } static void _rt_timer_init(rt_timer_t timer, @@ -221,7 +228,25 @@ rt_err_t rt_timer_start(rt_timer_t timer) /* disable interrupt */ level = rt_hw_interrupt_disable(); - + if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) + {/* insert timer to soft timer list */ + for (n = rt_soft_timer_list.next; n != &rt_soft_timer_list; n = n->next) + { + t = rt_list_entry(n, struct rt_timer, list); + if (t->timeout_tick > timer->timeout_tick) + { + rt_list_insert_before(n, &(timer->list)); + break; + } + } + /* no found suitable position in timer list */ + if (n == &rt_soft_timer_list) + { + rt_list_insert_before(n, &(timer->list)); + } + } + else + {/* insert timer to system timer list */ /* insert timer to system timer list */ for (n = rt_timer_list.next; n != &rt_timer_list; n = n->next) { @@ -238,6 +263,7 @@ rt_err_t rt_timer_start(rt_timer_t timer) { rt_list_insert_before(n, &(timer->list)); } + } timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; @@ -324,6 +350,7 @@ rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg) * corresponding timeout function will be invoked. * */ +void rt_soft_timer_tick_hook (void); void rt_timer_check() { rt_tick_t current_tick; @@ -383,9 +410,132 @@ void rt_timer_check() /* enable interrupt */ rt_hw_interrupt_enable(level); + /**/ + rt_soft_timer_tick_hook ( ); + #ifdef TIMER_DEBUG rt_kprintf("timer check leave\n"); #endif } + +static struct rt_thread soft_timer_thread; +static rt_uint8_t rt_thread_stack[RT_TIMER_THREAD_STACK_SIZE]; +static struct rt_semaphore timer_sem; + +static rt_uint16_t timer_ex_cnt; + + +rt_err_t timer_signal (void) +{ + return rt_sem_release(&timer_sem); +} + +void rt_soft_timer_tick_hook (void) +{ + timer_ex_cnt++; + if (timer_ex_cnt >= (RT_TICK_PER_SECOND / RT_TIMER_EX_TICKS_PER_SEC)) + { + timer_ex_cnt = 0; + timer_signal(); + } +} + +/** + * This function will check timer list, if a timeout event happens, the + * corresponding timeout function will be invoked. + * + */ +void rt_soft_timer_check() +{ + rt_tick_t current_tick; + rt_list_t *n; + struct rt_timer *t; + +#ifdef TIMER_DEBUG + rt_kprintf("timer check enter\n"); +#endif + + current_tick = rt_tick_get(); + + for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list); ) + { + t = rt_list_entry(n, struct rt_timer, list); + if (current_tick >= t->timeout_tick) + { +#ifdef RT_USING_HOOK + if (rt_timer_timeout_hook != RT_NULL) rt_timer_timeout_hook(t); +#endif + /* move node to the next */ + n = n->next; + + /* remove timer from timer list firstly */ + rt_list_remove(&(t->list)); + + /* call timeout function */ + t->timeout_func(t->parameter); + + /* reget tick */ + current_tick = rt_tick_get(); + +#ifdef TIMER_DEBUG + rt_kprintf("current tick: %d\n", current_tick); +#endif + + if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && + (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + { + /* start it */ + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + rt_timer_start(t); + } + else + { + /* stop timer */ + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + } + else break; + } +#ifdef TIMER_DEBUG + rt_kprintf("timer check leave\n"); +#endif +} + +static void rt_thread_timer_entry(void* parameter) +{ + (void)parameter; + while (1) + { + rt_sem_take(&timer_sem,RT_WAITING_FOREVER); + + rt_enter_critical(); + + rt_soft_timer_check( ); + + rt_exit_critical(); + } +} + + +/** + * @ingroup SystemInit + * + * This function will init system timer thread + * + */ +void rt_timer_thread_init(void) +{ + rt_sem_init(&timer_sem, "timer", 1, RT_IPC_FLAG_FIFO); + timer_ex_cnt = 0; + /*init timer_ex thread*/ + rt_thread_init(&soft_timer_thread, + "timer", + rt_thread_timer_entry, RT_NULL, + &rt_thread_stack[0], sizeof(rt_thread_stack), + RT_TIMER_THREAD_PRIO, 10); + + /* startup */ + rt_thread_startup(&soft_timer_thread); +} /*@}*/