timer.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2006-03-12 Bernard first version
  23. * 2006-04-29 Bernard implement thread timer
  24. * 2006-06-04 Bernard implement rt_timer_control
  25. * 2006-08-10 Bernard fix the periodic timer bug
  26. * 2006-09-03 Bernard implement rt_timer_detach
  27. * 2009-11-11 LiJin add soft timer
  28. * 2010-05-12 Bernard fix the timer check bug.
  29. * 2010-11-02 Charlie re-implement tick overflow issue
  30. * 2012-12-15 Bernard fix the next timeout issue in soft timer
  31. */
  32. #include <rtthread.h>
  33. #include <rthw.h>
  34. /* hard timer list */
  35. static rt_list_t rt_timer_list = RT_LIST_OBJECT_INIT(rt_timer_list);
  36. #ifdef RT_USING_TIMER_SOFT
  37. #ifndef RT_TIMER_THREAD_STACK_SIZE
  38. #define RT_TIMER_THREAD_STACK_SIZE 512
  39. #endif
  40. #ifndef RT_TIMER_THREAD_PRIO
  41. #define RT_TIMER_THREAD_PRIO 0
  42. #endif
  43. /* soft timer list */
  44. static rt_list_t rt_soft_timer_list;
  45. static struct rt_thread timer_thread;
  46. ALIGN(RT_ALIGN_SIZE)
  47. static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
  48. #endif
  49. #ifdef RT_USING_HOOK
  50. extern void (*rt_object_take_hook)(struct rt_object *object);
  51. extern void (*rt_object_put_hook)(struct rt_object *object);
  52. static void (*rt_timer_timeout_hook)(struct rt_timer *timer);
  53. /**
  54. * @addtogroup Hook
  55. */
  56. /*@{*/
  57. /**
  58. * This function will set a hook function, which will be invoked when timer
  59. * is timeout.
  60. *
  61. * @param hook the hook function
  62. */
  63. void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer))
  64. {
  65. rt_timer_timeout_hook = hook;
  66. }
  67. /*@}*/
  68. #endif
  69. static void _rt_timer_init(rt_timer_t timer,
  70. void (*timeout)(void *parameter),
  71. void *parameter,
  72. rt_tick_t time,
  73. rt_uint8_t flag)
  74. {
  75. /* set flag */
  76. timer->parent.flag = flag;
  77. /* set deactivated */
  78. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  79. timer->timeout_func = timeout;
  80. timer->parameter = parameter;
  81. timer->timeout_tick = 0;
  82. timer->init_tick = time;
  83. /* initialize timer list */
  84. rt_list_init(&(timer->list));
  85. }
  86. static rt_tick_t rt_timer_list_next_timeout(rt_list_t *timer_list)
  87. {
  88. struct rt_timer *timer;
  89. if (rt_list_isempty(timer_list))
  90. return RT_TICK_MAX;
  91. timer = rt_list_entry(timer_list->next, struct rt_timer, list);
  92. return timer->timeout_tick;
  93. }
  94. /**
  95. * @addtogroup Clock
  96. */
  97. /*@{*/
  98. /**
  99. * This function will initialize a timer, normally this function is used to
  100. * initialize a static timer object.
  101. *
  102. * @param timer the static timer object
  103. * @param name the name of timer
  104. * @param timeout the timeout function
  105. * @param parameter the parameter of timeout function
  106. * @param time the tick of timer
  107. * @param flag the flag of timer
  108. */
  109. void rt_timer_init(rt_timer_t timer,
  110. const char *name,
  111. void (*timeout)(void *parameter),
  112. void *parameter,
  113. rt_tick_t time,
  114. rt_uint8_t flag)
  115. {
  116. /* timer check */
  117. RT_ASSERT(timer != RT_NULL);
  118. /* timer object initialization */
  119. rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
  120. _rt_timer_init(timer, timeout, parameter, time, flag);
  121. }
  122. RTM_EXPORT(rt_timer_init);
  123. /**
  124. * This function will detach a timer from timer management.
  125. *
  126. * @param timer the static timer object
  127. *
  128. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  129. */
  130. rt_err_t rt_timer_detach(rt_timer_t timer)
  131. {
  132. register rt_base_t level;
  133. /* timer check */
  134. RT_ASSERT(timer != RT_NULL);
  135. /* disable interrupt */
  136. level = rt_hw_interrupt_disable();
  137. /* remove it from timer list */
  138. rt_list_remove(&(timer->list));
  139. /* enable interrupt */
  140. rt_hw_interrupt_enable(level);
  141. rt_object_detach((rt_object_t)timer);
  142. return -RT_EOK;
  143. }
  144. RTM_EXPORT(rt_timer_detach);
  145. #ifdef RT_USING_HEAP
  146. /**
  147. * This function will create a timer
  148. *
  149. * @param name the name of timer
  150. * @param timeout the timeout function
  151. * @param parameter the parameter of timeout function
  152. * @param time the tick of timer
  153. * @param flag the flag of timer
  154. *
  155. * @return the created timer object
  156. */
  157. rt_timer_t rt_timer_create(const char *name,
  158. void (*timeout)(void *parameter),
  159. void *parameter,
  160. rt_tick_t time,
  161. rt_uint8_t flag)
  162. {
  163. struct rt_timer *timer;
  164. /* allocate a object */
  165. timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name);
  166. if (timer == RT_NULL)
  167. {
  168. return RT_NULL;
  169. }
  170. _rt_timer_init(timer, timeout, parameter, time, flag);
  171. return timer;
  172. }
  173. RTM_EXPORT(rt_timer_create);
  174. /**
  175. * This function will delete a timer and release timer memory
  176. *
  177. * @param timer the timer to be deleted
  178. *
  179. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  180. */
  181. rt_err_t rt_timer_delete(rt_timer_t timer)
  182. {
  183. register rt_base_t level;
  184. /* timer check */
  185. RT_ASSERT(timer != RT_NULL);
  186. /* disable interrupt */
  187. level = rt_hw_interrupt_disable();
  188. /* remove it from timer list */
  189. rt_list_remove(&(timer->list));
  190. /* enable interrupt */
  191. rt_hw_interrupt_enable(level);
  192. rt_object_delete((rt_object_t)timer);
  193. return -RT_EOK;
  194. }
  195. RTM_EXPORT(rt_timer_delete);
  196. #endif
  197. /**
  198. * This function will start the timer
  199. *
  200. * @param timer the timer to be started
  201. *
  202. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  203. */
  204. rt_err_t rt_timer_start(rt_timer_t timer)
  205. {
  206. struct rt_timer *t;
  207. register rt_base_t level;
  208. rt_list_t *n, *timer_list;
  209. /* timer check */
  210. RT_ASSERT(timer != RT_NULL);
  211. if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
  212. return -RT_ERROR;
  213. RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));
  214. /*
  215. * get timeout tick,
  216. * the max timeout tick shall not great than RT_TICK_MAX/2
  217. */
  218. RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2);
  219. timer->timeout_tick = rt_tick_get() + timer->init_tick;
  220. /* disable interrupt */
  221. level = rt_hw_interrupt_disable();
  222. #ifdef RT_USING_TIMER_SOFT
  223. if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
  224. {
  225. /* insert timer to soft timer list */
  226. timer_list = &rt_soft_timer_list;
  227. }
  228. else
  229. #endif
  230. {
  231. /* insert timer to system timer list */
  232. timer_list = &rt_timer_list;
  233. }
  234. for (n = timer_list->next; n != timer_list; n = n->next)
  235. {
  236. t = rt_list_entry(n, struct rt_timer, list);
  237. /*
  238. * It supposes that the new tick shall less than the half duration of
  239. * tick max. And if we have two timers that timeout at the same time,
  240. * it's prefered that the timer inserted early get called early.
  241. */
  242. if ((t->timeout_tick - timer->timeout_tick) == 0)
  243. {
  244. rt_list_insert_after(n, &(timer->list));
  245. break;
  246. }
  247. else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
  248. {
  249. rt_list_insert_before(n, &(timer->list));
  250. break;
  251. }
  252. }
  253. /* no found suitable position in timer list */
  254. if (n == timer_list)
  255. {
  256. rt_list_insert_before(n, &(timer->list));
  257. }
  258. timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
  259. /* enable interrupt */
  260. rt_hw_interrupt_enable(level);
  261. #ifdef RT_USING_TIMER_SOFT
  262. if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
  263. {
  264. /* check whether timer thread is ready */
  265. if (timer_thread.stat != RT_THREAD_READY)
  266. {
  267. /* resume timer thread to check soft timer */
  268. rt_thread_resume(&timer_thread);
  269. rt_schedule();
  270. }
  271. }
  272. #endif
  273. return -RT_EOK;
  274. }
  275. RTM_EXPORT(rt_timer_start);
  276. /**
  277. * This function will stop the timer
  278. *
  279. * @param timer the timer to be stopped
  280. *
  281. * @return the operation status, RT_EOK on OK, -RT_ERROR on error
  282. */
  283. rt_err_t rt_timer_stop(rt_timer_t timer)
  284. {
  285. register rt_base_t level;
  286. /* timer check */
  287. RT_ASSERT(timer != RT_NULL);
  288. if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  289. return -RT_ERROR;
  290. RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));
  291. /* disable interrupt */
  292. level = rt_hw_interrupt_disable();
  293. /* remove it from timer list */
  294. rt_list_remove(&(timer->list));
  295. /* enable interrupt */
  296. rt_hw_interrupt_enable(level);
  297. /* change stat */
  298. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  299. return RT_EOK;
  300. }
  301. RTM_EXPORT(rt_timer_stop);
  302. /**
  303. * This function will get or set some options of the timer
  304. *
  305. * @param timer the timer to be get or set
  306. * @param cmd the control command
  307. * @param arg the argument
  308. *
  309. * @return RT_EOK
  310. */
  311. rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void *arg)
  312. {
  313. /* timer check */
  314. RT_ASSERT(timer != RT_NULL);
  315. switch (cmd)
  316. {
  317. case RT_TIMER_CTRL_GET_TIME:
  318. *(rt_tick_t *)arg = timer->init_tick;
  319. break;
  320. case RT_TIMER_CTRL_SET_TIME:
  321. timer->init_tick = *(rt_tick_t *)arg;
  322. break;
  323. case RT_TIMER_CTRL_SET_ONESHOT:
  324. timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
  325. break;
  326. case RT_TIMER_CTRL_SET_PERIODIC:
  327. timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
  328. break;
  329. }
  330. return RT_EOK;
  331. }
  332. RTM_EXPORT(rt_timer_control);
  333. /**
  334. * This function will check timer list, if a timeout event happens, the
  335. * corresponding timeout function will be invoked.
  336. *
  337. * @note this function shall be invoked in operating system timer interrupt.
  338. */
  339. void rt_timer_check(void)
  340. {
  341. struct rt_timer *t;
  342. rt_tick_t current_tick;
  343. register rt_base_t level;
  344. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
  345. current_tick = rt_tick_get();
  346. /* disable interrupt */
  347. level = rt_hw_interrupt_disable();
  348. while (!rt_list_isempty(&rt_timer_list))
  349. {
  350. t = rt_list_entry(rt_timer_list.next, struct rt_timer, list);
  351. /*
  352. * It supposes that the new tick shall less than the half duration of
  353. * tick max.
  354. */
  355. if ((current_tick - t->timeout_tick) < RT_TICK_MAX/2)
  356. {
  357. RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
  358. /* remove timer from timer list firstly */
  359. rt_list_remove(&(t->list));
  360. /* call timeout function */
  361. t->timeout_func(t->parameter);
  362. /* re-get tick */
  363. current_tick = rt_tick_get();
  364. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
  365. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  366. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  367. {
  368. /* start it */
  369. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  370. rt_timer_start(t);
  371. }
  372. else
  373. {
  374. /* stop timer */
  375. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  376. }
  377. }
  378. else
  379. break;
  380. }
  381. /* enable interrupt */
  382. rt_hw_interrupt_enable(level);
  383. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
  384. }
  385. /**
  386. * This function will return the next timeout tick in the system.
  387. *
  388. * @return the next timeout tick in the system
  389. */
  390. rt_tick_t rt_timer_next_timeout_tick(void)
  391. {
  392. return rt_timer_list_next_timeout(&rt_timer_list);
  393. }
  394. #ifdef RT_USING_TIMER_SOFT
  395. /**
  396. * This function will check timer list, if a timeout event happens, the
  397. * corresponding timeout function will be invoked.
  398. */
  399. void rt_soft_timer_check(void)
  400. {
  401. rt_tick_t current_tick;
  402. rt_list_t *n;
  403. struct rt_timer *t;
  404. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
  405. current_tick = rt_tick_get();
  406. for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list);)
  407. {
  408. t = rt_list_entry(n, struct rt_timer, list);
  409. /*
  410. * It supposes that the new tick shall less than the half duration of
  411. * tick max.
  412. */
  413. if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
  414. {
  415. RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t));
  416. /* move node to the next */
  417. n = n->next;
  418. /* remove timer from timer list firstly */
  419. rt_list_remove(&(t->list));
  420. /* call timeout function */
  421. t->timeout_func(t->parameter);
  422. /* re-get tick */
  423. current_tick = rt_tick_get();
  424. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
  425. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  426. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  427. {
  428. /* start it */
  429. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  430. rt_timer_start(t);
  431. }
  432. else
  433. {
  434. /* stop timer */
  435. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  436. }
  437. }
  438. else break; /* not check anymore */
  439. }
  440. RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
  441. }
  442. /* system timer thread entry */
  443. static void rt_thread_timer_entry(void *parameter)
  444. {
  445. rt_tick_t next_timeout;
  446. while (1)
  447. {
  448. /* get the next timeout tick */
  449. next_timeout = rt_timer_list_next_timeout(&rt_soft_timer_list);
  450. if (next_timeout == RT_TICK_MAX)
  451. {
  452. /* no software timer exist, suspend self. */
  453. rt_thread_suspend(rt_thread_self());
  454. rt_schedule();
  455. }
  456. else
  457. {
  458. rt_tick_t current_tick;
  459. /* get current tick */
  460. current_tick = rt_tick_get();
  461. if ((next_timeout - current_tick) < RT_TICK_MAX/2)
  462. {
  463. /* get the delta timeout tick */
  464. next_timeout = next_timeout - current_tick;
  465. rt_thread_delay(next_timeout);
  466. }
  467. }
  468. /* lock scheduler */
  469. rt_enter_critical();
  470. /* check software timer */
  471. rt_soft_timer_check();
  472. /* unlock scheduler */
  473. rt_exit_critical();
  474. }
  475. }
  476. #endif
  477. /**
  478. * @ingroup SystemInit
  479. *
  480. * This function will initialize system timer
  481. *
  482. * @deprecated since 1.1.0, this function does not need to be invoked
  483. * in the system initialization.
  484. */
  485. void rt_system_timer_init(void)
  486. {
  487. }
  488. /**
  489. * @ingroup SystemInit
  490. *
  491. * This function will initialize system timer thread
  492. */
  493. void rt_system_timer_thread_init(void)
  494. {
  495. #ifdef RT_USING_TIMER_SOFT
  496. rt_list_init(&rt_soft_timer_list);
  497. /* start software timer thread */
  498. rt_thread_init(&timer_thread,
  499. "timer",
  500. rt_thread_timer_entry,
  501. RT_NULL,
  502. &timer_thread_stack[0],
  503. sizeof(timer_thread_stack),
  504. RT_TIMER_THREAD_PRIO,
  505. 10);
  506. /* startup */
  507. rt_thread_startup(&timer_thread);
  508. #endif
  509. }
  510. /*@}*/