app_timer_rtx.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /**
  2. * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include "sdk_common.h"
  41. #if NRF_MODULE_ENABLED(APP_TIMER)
  42. #include "app_timer.h"
  43. #include <stdlib.h>
  44. #include "nrf.h"
  45. #include "nrf_soc.h"
  46. #include "app_error.h"
  47. #include "cmsis_os.h"
  48. #include "app_util_platform.h"
  49. #define RTC1_IRQ_PRI APP_IRQ_PRIORITY_LOWEST /**< Priority of the RTC1 interrupt. */
  50. #define MAX_RTC_COUNTER_VAL 0x00FFFFFF /**< Maximum value of the RTC counter. */
  51. /**@brief This structure keeps information about osTimer.*/
  52. typedef struct
  53. {
  54. osTimerDef_t timerDef;
  55. uint32_t buffer[6];
  56. osTimerId id;
  57. }app_timer_info_t;
  58. /**@brief Store an array of timers with configuration. */
  59. typedef struct
  60. {
  61. uint8_t max_timers; /**< The maximum number of timers*/
  62. uint32_t prescaler;
  63. app_timer_info_t * app_timers; /**< Pointer to table of timers*/
  64. }app_timer_control_t;
  65. app_timer_control_t app_timer_control;
  66. /**@brief This structure is defined by RTX. It keeps information about created osTimers. It is used in app_timer_start(). */
  67. typedef struct os_timer_cb_
  68. {
  69. struct os_timer_cb_ * next; /**< Pointer to next active Timer */
  70. uint8_t state; /**< Timer State */
  71. uint8_t type; /**< Timer Type (Periodic/One-shot). */
  72. uint16_t reserved; /**< Reserved. */
  73. uint32_t tcnt; /**< Timer Delay Count. */
  74. uint32_t icnt; /**< Timer Initial Count. */
  75. void * arg; /**< Timer Function Argument. */
  76. const osTimerDef_t * timer; /**< Pointer to Timer definition. */
  77. } os_timer_cb;
  78. /**@brief This functions are defined by RTX.*/
  79. //lint --save -e10 -e19 -e526
  80. extern osStatus svcTimerStop(osTimerId timer_id); /**< Used in app_timer_stop(). */
  81. extern osStatus svcTimerStart(osTimerId timer_id, uint32_t millisec); /**< Used in app_timer_start(). */
  82. // lint --restore
  83. static void * rt_id2obj (void *id) /**< Used in app_timer_start(). This function gives information if osTimerID is valid */
  84. {
  85. if ((uint32_t)id & 3U)
  86. {
  87. return NULL;
  88. }
  89. #ifdef OS_SECTIONS_LINK_INFO
  90. if ((os_section_id$$Base != 0U) && (os_section_id$$Limit != 0U))
  91. {
  92. if (id < (void *)os_section_id$$Base)
  93. {
  94. return NULL;
  95. }
  96. if (id >= (void *)os_section_id$$Limit)
  97. {
  98. return NULL;
  99. }
  100. }
  101. #endif
  102. return id;
  103. }
  104. ret_code_t app_timer_init(void)
  105. {
  106. if (p_buffer == NULL)
  107. {
  108. return NRF_ERROR_INVALID_PARAM;
  109. }
  110. app_timer_control.app_timers = p_buffer;
  111. NVIC_SetPriority(RTC1_IRQn, RTC1_IRQ_PRI);
  112. return NRF_SUCCESS;
  113. }
  114. ret_code_t app_timer_create(app_timer_id_t const * p_timer_id,
  115. app_timer_mode_t mode,
  116. app_timer_timeout_handler_t timeout_handler)
  117. {
  118. if ((timeout_handler == NULL) || (p_timer_id == NULL))
  119. {
  120. return NRF_ERROR_INVALID_PARAM;
  121. }
  122. app_timer_info_t * p_timer_info = (app_timer_info_t *)*p_timer_id;
  123. p_timer_info->timerDef.timer = p_timer_info->buffer;
  124. p_timer_info->timerDef.ptimer = (os_ptimer)timeout_handler;
  125. p_timer_info->id = osTimerCreate(&(p_timer_info->timerDef), (os_timer_type)mode, NULL);
  126. if (p_timer_info->id)
  127. return NRF_SUCCESS;
  128. else
  129. {
  130. return NRF_ERROR_INVALID_PARAM; // This error is unspecified by rtx
  131. }
  132. }
  133. #define osTimerRunning 2
  134. ret_code_t app_timer_start(app_timer_id_t timer_id, uint32_t timeout_ticks, void * p_context)
  135. {
  136. if ((timeout_ticks < APP_TIMER_MIN_TIMEOUT_TICKS))
  137. {
  138. return NRF_ERROR_INVALID_PARAM;
  139. }
  140. uint32_t timeout_ms =
  141. ((uint32_t)ROUNDED_DIV(timeout_ticks * 1000 * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1),
  142. (uint32_t)APP_TIMER_CLOCK_FREQ));
  143. app_timer_info_t * p_timer_info = (app_timer_info_t *)timer_id;
  144. if (rt_id2obj((void *)p_timer_info->id) == NULL)
  145. return NRF_ERROR_INVALID_PARAM;
  146. // Pass p_context to timer_timeout_handler
  147. ((os_timer_cb *)(p_timer_info->id))->arg = p_context;
  148. if (((os_timer_cb *)(p_timer_info->id))->state == osTimerRunning)
  149. {
  150. return NRF_SUCCESS;
  151. }
  152. // osTimerStart() returns osErrorISR if it is called in interrupt routine.
  153. switch (osTimerStart((osTimerId)p_timer_info->id, timeout_ms) )
  154. {
  155. case osOK:
  156. return NRF_SUCCESS;
  157. case osErrorISR:
  158. break;
  159. case osErrorParameter:
  160. return NRF_ERROR_INVALID_PARAM;
  161. default:
  162. return NRF_ERROR_INVALID_PARAM;
  163. }
  164. // Start timer without svcCall
  165. switch (svcTimerStart((osTimerId)p_timer_info->id, timeout_ms))
  166. {
  167. case osOK:
  168. return NRF_SUCCESS;
  169. case osErrorISR:
  170. return NRF_ERROR_INVALID_STATE;
  171. case osErrorParameter:
  172. return NRF_ERROR_INVALID_PARAM;
  173. default:
  174. return NRF_ERROR_INVALID_PARAM;
  175. }
  176. }
  177. ret_code_t app_timer_stop(app_timer_id_t timer_id)
  178. {
  179. app_timer_info_t * p_timer_info = (app_timer_info_t *)timer_id;
  180. switch (osTimerStop((osTimerId)p_timer_info->id) )
  181. {
  182. case osOK:
  183. return NRF_SUCCESS;
  184. case osErrorISR:
  185. break;
  186. case osErrorParameter:
  187. return NRF_ERROR_INVALID_PARAM;
  188. case osErrorResource:
  189. return NRF_SUCCESS;
  190. default:
  191. return NRF_ERROR_INVALID_PARAM;
  192. }
  193. // Stop timer without svcCall
  194. switch (svcTimerStop((osTimerId)p_timer_info->id))
  195. {
  196. case osOK:
  197. return NRF_SUCCESS;
  198. case osErrorISR:
  199. return NRF_ERROR_INVALID_STATE;
  200. case osErrorParameter:
  201. return NRF_ERROR_INVALID_PARAM;
  202. case osErrorResource:
  203. return NRF_SUCCESS;
  204. default:
  205. return NRF_ERROR_INVALID_PARAM;
  206. }
  207. }
  208. ret_code_t app_timer_stop_all(void)
  209. {
  210. for (int i = 0; i < app_timer_control.max_timers; i++)
  211. {
  212. if (app_timer_control.app_timers[i].id)
  213. {
  214. (void)app_timer_stop((app_timer_id_t)app_timer_control.app_timers[i].id);
  215. }
  216. }
  217. return 0;
  218. }
  219. extern uint32_t os_tick_val(void);
  220. uint32_t app_timer_cnt_get(void)
  221. {
  222. return os_tick_val();
  223. }
  224. uint32_t app_timer_cnt_diff_compute(uint32_t ticks_to,
  225. uint32_t ticks_from)
  226. {
  227. return ((ticks_to - ticks_from) & MAX_RTC_COUNTER_VAL);
  228. }
  229. #endif //NRF_MODULE_ENABLED(APP_TIMER)