timer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  1. /*
  2. * File : timer.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2006-03-12 Bernard first version
  13. * 2006-04-29 Bernard implement thread timer
  14. * 2006-06-04 Bernard implement rt_timer_control
  15. * 2006-08-10 Bernard fix the periodic timer bug
  16. * 2006-09-03 Bernard implement rt_timer_detach
  17. * 2009-11-11 LiJin add soft timer
  18. * 2010-05-12 Bernard fix the timer check bug.
  19. * 2010-11-02 Charlie re-implement tick overflow issue
  20. */
  21. #include <rtthread.h>
  22. #include <rthw.h>
  23. /* hard timer list */
  24. static rt_list_t rt_timer_list = RT_LIST_OBJECT_INIT(rt_timer_list);
  25. #ifdef RT_USING_TIMER_SOFT
  26. /* soft timer list */
  27. static rt_list_t rt_soft_timer_list;
  28. #endif
  29. #ifdef RT_USING_HOOK
  30. extern void (*rt_object_take_hook)(struct rt_object *object);
  31. extern void (*rt_object_put_hook)(struct rt_object *object);
  32. static void (*rt_timer_timeout_hook)(struct rt_timer *timer);
  33. /**
  34. * @addtogroup Hook
  35. */
  36. /*@{*/
  37. /**
  38. * This function will set a hook function, which will be invoked when timer
  39. * is timeout.
  40. *
  41. * @param hook the hook function
  42. */
  43. void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer))
  44. {
  45. rt_timer_timeout_hook = hook;
  46. }
  47. /*@}*/
  48. #endif
  49. static void _rt_timer_init(rt_timer_t timer,
  50. void (*timeout)(void *parameter), void *parameter,
  51. rt_tick_t time, rt_uint8_t flag)
  52. {
  53. /* set flag */
  54. timer->parent.flag = flag;
  55. /* set deactivated */
  56. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  57. timer->timeout_func = timeout;
  58. timer->parameter = parameter;
  59. timer->timeout_tick = 0;
  60. timer->init_tick = time;
  61. /* initialize timer list */
  62. rt_list_init(&(timer->list));
  63. }
  64. /**
  65. * @addtogroup Clock
  66. */
  67. /*@{*/
  68. /**
  69. * This function will initialize a timer, normally this function is used to initialize
  70. * a static timer object.
  71. *
  72. * @param timer the static timer object
  73. * @param name the name of timer
  74. * @param timeout the timeout function
  75. * @param parameter the parameter of timeout function
  76. * @param time the tick of timer
  77. * @param flag the flag of timer
  78. */
  79. void rt_timer_init(rt_timer_t timer,
  80. const char *name,
  81. void (*timeout)(void *parameter), void *parameter,
  82. rt_tick_t time, rt_uint8_t flag)
  83. {
  84. /* timer check */
  85. RT_ASSERT(timer != RT_NULL);
  86. /* timer object initialization */
  87. rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
  88. _rt_timer_init(timer, timeout, parameter, time, flag);
  89. }
  90. /**
  91. * This function will detach a timer from timer management.
  92. *
  93. * @param timer the static timer object
  94. *
  95. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  96. */
  97. rt_err_t rt_timer_detach(rt_timer_t timer)
  98. {
  99. register rt_base_t level;
  100. /* timer check */
  101. RT_ASSERT(timer != RT_NULL);
  102. /* disable interrupt */
  103. level = rt_hw_interrupt_disable();
  104. /* remove it from timer list */
  105. rt_list_remove(&(timer->list));
  106. /* enable interrupt */
  107. rt_hw_interrupt_enable(level);
  108. rt_object_detach((rt_object_t)timer);
  109. return -RT_EOK;
  110. }
  111. #ifdef RT_USING_HEAP
  112. /**
  113. * This function will create a timer
  114. *
  115. * @param name the name of timer
  116. * @param timeout the timeout function
  117. * @param parameter the parameter of timeout function
  118. * @param time the tick of timer
  119. * @param flag the flag of timer
  120. *
  121. * @return the created timer object
  122. */
  123. rt_timer_t rt_timer_create(const char *name, void (*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag)
  124. {
  125. struct rt_timer *timer;
  126. /* allocate a object */
  127. timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name);
  128. if (timer == RT_NULL)
  129. {
  130. return RT_NULL;
  131. }
  132. _rt_timer_init(timer, timeout, parameter, time, flag);
  133. return timer;
  134. }
  135. /**
  136. * This function will delete a timer and release timer memory
  137. *
  138. * @param timer the timer to be deleted
  139. *
  140. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  141. */
  142. rt_err_t rt_timer_delete(rt_timer_t timer)
  143. {
  144. register rt_base_t level;
  145. /* timer check */
  146. RT_ASSERT(timer != RT_NULL);
  147. /* disable interrupt */
  148. level = rt_hw_interrupt_disable();
  149. /* remove it from timer list */
  150. rt_list_remove(&(timer->list));
  151. /* enable interrupt */
  152. rt_hw_interrupt_enable(level);
  153. rt_object_delete((rt_object_t)timer);
  154. return -RT_EOK;
  155. }
  156. #endif
  157. /**
  158. * This function will start the timer
  159. *
  160. * @param timer the timer to be started
  161. *
  162. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  163. */
  164. rt_err_t rt_timer_start(rt_timer_t timer)
  165. {
  166. struct rt_timer *t;
  167. register rt_base_t level;
  168. rt_list_t *n, *timer_list;
  169. /* timer check */
  170. RT_ASSERT(timer != RT_NULL);
  171. if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
  172. return -RT_ERROR;
  173. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));
  174. /* disable interrupt */
  175. level = rt_hw_interrupt_disable();
  176. /* get timeout tick, the max timeout tick shall not great than RT_TICK_MAX/2 */
  177. RT_ASSERT(timer->init_tick < RT_TICK_MAX/2);
  178. timer->timeout_tick = rt_tick_get() + timer->init_tick;
  179. #ifdef RT_USING_TIMER_SOFT
  180. if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
  181. {
  182. /* insert timer to soft timer list */
  183. timer_list = &rt_soft_timer_list;
  184. }
  185. else
  186. #endif
  187. {
  188. /* insert timer to system timer list */
  189. timer_list = &rt_timer_list;
  190. }
  191. for (n = timer_list->next; n != timer_list; n = n->next)
  192. {
  193. t = rt_list_entry(n, struct rt_timer, list);
  194. /*
  195. * It supposes that the new tick shall less than the half duration of tick max.
  196. */
  197. if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX/2)
  198. {
  199. rt_list_insert_before(n, &(timer->list));
  200. break;
  201. }
  202. }
  203. /* no found suitable position in timer list */
  204. if (n == timer_list)
  205. {
  206. rt_list_insert_before(n, &(timer->list));
  207. }
  208. timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
  209. /* enable interrupt */
  210. rt_hw_interrupt_enable(level);
  211. return -RT_EOK;
  212. }
  213. /**
  214. * This function will stop the timer
  215. *
  216. * @param timer the timer to be stopped
  217. *
  218. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  219. */
  220. rt_err_t rt_timer_stop(rt_timer_t timer)
  221. {
  222. register rt_base_t level;
  223. /* timer check */
  224. RT_ASSERT(timer != RT_NULL);
  225. if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  226. return -RT_ERROR;
  227. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));
  228. /* disable interrupt */
  229. level = rt_hw_interrupt_disable();
  230. /* change stat */
  231. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  232. /* remove it from timer list */
  233. rt_list_remove(&(timer->list));
  234. /* enable interrupt */
  235. rt_hw_interrupt_enable(level);
  236. return RT_EOK;
  237. }
  238. /**
  239. * This function will get or set some options of the timer
  240. *
  241. * @param timer the timer to be get or set
  242. * @param cmd the control command
  243. * @param arg the argument
  244. *
  245. * @return RT_EOK
  246. */
  247. rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void *arg)
  248. {
  249. /* timer check */
  250. RT_ASSERT(timer != RT_NULL);
  251. switch (cmd)
  252. {
  253. case RT_TIMER_CTRL_GET_TIME:
  254. *(rt_tick_t *)arg = timer->init_tick;
  255. break;
  256. case RT_TIMER_CTRL_SET_TIME:
  257. timer->init_tick = *(rt_tick_t *)arg;
  258. break;
  259. case RT_TIMER_CTRL_SET_ONESHOT:
  260. timer->parent.flag &= ~(1 << RT_TIMER_FLAG_PERIODIC);
  261. break;
  262. case RT_TIMER_CTRL_SET_PERIODIC:
  263. timer->parent.flag |= (1 << RT_TIMER_FLAG_PERIODIC);
  264. break;
  265. }
  266. return RT_EOK;
  267. }
  268. /**
  269. * This function will check timer list, if a timeout event happens, the
  270. * corresponding timeout function will be invoked.
  271. *
  272. * @note this function shall be invoked in operating system timer interrupt.
  273. */
  274. #ifdef RT_USING_TIMER_SOFT
  275. void rt_soft_timer_tick_increase(void);
  276. #endif
  277. void rt_timer_check(void)
  278. {
  279. struct rt_timer *t;
  280. rt_tick_t current_tick;
  281. register rt_base_t level;
  282. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
  283. current_tick = rt_tick_get();
  284. /* disable interrupt */
  285. level = rt_hw_interrupt_disable();
  286. while (!rt_list_isempty(&rt_timer_list))
  287. {
  288. t = rt_list_entry(rt_timer_list.next, struct rt_timer, list);
  289. /*
  290. * It supposes that the new tick shall less than the half duration of tick max.
  291. */
  292. if ((current_tick - t->timeout_tick) < RT_TICK_MAX/2)
  293. {
  294. RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
  295. /* remove timer from timer list firstly */
  296. rt_list_remove(&(t->list));
  297. /* call timeout function */
  298. t->timeout_func(t->parameter);
  299. /* re-get tick */
  300. current_tick = rt_tick_get();
  301. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
  302. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  303. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  304. {
  305. /* start it */
  306. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  307. rt_timer_start(t);
  308. }
  309. else
  310. {
  311. /* stop timer */
  312. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  313. }
  314. }
  315. else
  316. break;
  317. }
  318. /* enable interrupt */
  319. rt_hw_interrupt_enable(level);
  320. /* increase soft timer tick */
  321. #ifdef RT_USING_TIMER_SOFT
  322. rt_soft_timer_tick_increase();
  323. #endif
  324. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
  325. }
  326. #ifdef RT_USING_TIMER_SOFT
  327. static struct rt_thread timer_thread;
  328. ALIGN(RT_ALIGN_SIZE)
  329. static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
  330. static struct rt_semaphore timer_sem;
  331. static rt_uint16_t timer_ex_cnt;
  332. void rt_soft_timer_tick_increase(void)
  333. {
  334. timer_ex_cnt ++;
  335. if (timer_ex_cnt >= (RT_TICK_PER_SECOND / RT_TIMER_TICK_PER_SECOND))
  336. {
  337. timer_ex_cnt = 0;
  338. rt_sem_release(&timer_sem);
  339. }
  340. }
  341. /**
  342. * This function will check timer list, if a timeout event happens, the
  343. * corresponding timeout function will be invoked.
  344. */
  345. void rt_soft_timer_check(void)
  346. {
  347. rt_tick_t current_tick;
  348. rt_list_t *n;
  349. struct rt_timer *t;
  350. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
  351. current_tick = rt_tick_get();
  352. for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list);)
  353. {
  354. t = rt_list_entry(n, struct rt_timer, list);
  355. /*
  356. * It supposes that the new tick shall less than the half duration of tick max.
  357. */
  358. if ((current_tick - t->timeout_tick) < RT_TICK_MAX/2)
  359. {
  360. RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
  361. /* move node to the next */
  362. n = n->next;
  363. /* remove timer from timer list firstly */
  364. rt_list_remove(&(t->list));
  365. /* call timeout function */
  366. t->timeout_func(t->parameter);
  367. /* re-get tick */
  368. current_tick = rt_tick_get();
  369. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
  370. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  371. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  372. {
  373. /* start it */
  374. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  375. rt_timer_start(t);
  376. }
  377. else
  378. {
  379. /* stop timer */
  380. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  381. }
  382. }
  383. else
  384. break; /* not check anymore */
  385. }
  386. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
  387. }
  388. /* system timer thread entry */
  389. static void rt_thread_timer_entry(void *parameter)
  390. {
  391. while (1)
  392. {
  393. /* take software timer semaphore */
  394. rt_sem_take(&timer_sem, RT_WAITING_FOREVER);
  395. /* lock scheduler */
  396. rt_enter_critical();
  397. /* check software timer */
  398. rt_soft_timer_check();
  399. /* unlock scheduler */
  400. rt_exit_critical();
  401. }
  402. }
  403. #endif
  404. /**
  405. * @ingroup SystemInit
  406. *
  407. * This function will initialize system timer
  408. *
  409. * @deprecated since 1.1.0, this function does not need to be invoked
  410. * in the system initialization.
  411. */
  412. void rt_system_timer_init(void)
  413. {
  414. }
  415. /**
  416. * @ingroup SystemInit
  417. *
  418. * This function will initialize system timer thread
  419. */
  420. void rt_system_timer_thread_init(void)
  421. {
  422. #ifdef RT_USING_TIMER_SOFT
  423. rt_list_init(&rt_soft_timer_list);
  424. rt_sem_init(&timer_sem, "timer", 0, RT_IPC_FLAG_FIFO);
  425. /* start software timer thread */
  426. rt_thread_init(&timer_thread,
  427. "timer",
  428. rt_thread_timer_entry, RT_NULL,
  429. &timer_thread_stack[0], sizeof(timer_thread_stack),
  430. RT_TIMER_THREAD_PRIO, 10);
  431. /* startup */
  432. rt_thread_startup(&timer_thread);
  433. #endif
  434. }
  435. /*@}*/