drv_rtc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /**
  2. * Copyright (c) 2018 - 2020, 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 <nrfx.h>
  41. #include <nrf_delay.h>
  42. #include <drv_rtc.h>
  43. /* Module is integral part of app_timer implementation. */
  44. #define NRF_LOG_MODULE_NAME app_timer
  45. #include <nrf_log.h>
  46. #define EVT_TO_STR(event) \
  47. (event == NRF_RTC_EVENT_TICK ? "NRF_RTC_EVENT_TICK" : \
  48. (event == NRF_RTC_EVENT_OVERFLOW ? "NRF_RTC_EVENT_OVERFLOW" : \
  49. (event == NRF_RTC_EVENT_COMPARE_0 ? "NRF_RTC_EVENT_COMPARE_0" : \
  50. (event == NRF_RTC_EVENT_COMPARE_1 ? "NRF_RTC_EVENT_COMPARE_1" : \
  51. (event == NRF_RTC_EVENT_COMPARE_2 ? "NRF_RTC_EVENT_COMPARE_2" : \
  52. (event == NRF_RTC_EVENT_COMPARE_3 ? "NRF_RTC_EVENT_COMPARE_3" : \
  53. "UNKNOWN EVENT"))))))
  54. #if defined ( __ICCARM__ )
  55. /* IAR gives warning for offsetof with non-constant expression.*/
  56. #define CC_IDX_TO_CC_EVENT(_cc) \
  57. ((nrf_rtc_event_t)(offsetof(NRF_RTC_Type, EVENTS_COMPARE[0]) + sizeof(uint32_t)*_cc))
  58. #else
  59. #define CC_IDX_TO_CC_EVENT(_cc) \
  60. ((nrf_rtc_event_t)(offsetof(NRF_RTC_Type, EVENTS_COMPARE[_cc])))
  61. #endif
  62. /**@brief RTC driver instance control block structure. */
  63. typedef struct
  64. {
  65. drv_rtc_t const * p_instance;
  66. nrfx_drv_state_t state; /**< Instance state. */
  67. } drv_rtc_cb_t;
  68. // User callbacks local storage.
  69. static drv_rtc_handler_t m_handlers[DRV_RTC_ENABLED_COUNT];
  70. static drv_rtc_cb_t m_cb[DRV_RTC_ENABLED_COUNT];
  71. // According to Produce Specification RTC may not trigger COMPARE event if CC value set is equal to
  72. // COUNTER value or COUNTER+1.
  73. #define COUNTER_TO_CC_MIN_DISTANCE 2
  74. ret_code_t drv_rtc_init(drv_rtc_t const * const p_instance,
  75. drv_rtc_config_t const * p_config,
  76. drv_rtc_handler_t handler)
  77. {
  78. ASSERT(p_instance);
  79. ASSERT(p_config);
  80. ASSERT(handler);
  81. ret_code_t err_code;
  82. m_handlers[p_instance->instance_id] = handler;
  83. if (m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED)
  84. {
  85. err_code = NRF_ERROR_INVALID_STATE;
  86. NRF_LOG_WARNING("RTC instance already initialized.");
  87. return err_code;
  88. }
  89. nrf_rtc_prescaler_set(p_instance->p_reg, p_config->prescaler);
  90. NRFX_IRQ_PRIORITY_SET(p_instance->irq, p_config->interrupt_priority);
  91. NRFX_IRQ_ENABLE(p_instance->irq);
  92. m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_INITIALIZED;
  93. m_cb[p_instance->instance_id].p_instance = p_instance;
  94. err_code = NRF_SUCCESS;
  95. NRF_LOG_INFO("RTC: initialized.");
  96. return err_code;
  97. }
  98. void drv_rtc_uninit(drv_rtc_t const * const p_instance)
  99. {
  100. ASSERT(p_instance);
  101. uint32_t mask = NRF_RTC_INT_TICK_MASK |
  102. NRF_RTC_INT_OVERFLOW_MASK |
  103. NRF_RTC_INT_COMPARE0_MASK |
  104. NRF_RTC_INT_COMPARE1_MASK |
  105. NRF_RTC_INT_COMPARE2_MASK |
  106. NRF_RTC_INT_COMPARE3_MASK;
  107. ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
  108. NRFX_IRQ_DISABLE(p_instance->irq);
  109. drv_rtc_stop(p_instance);
  110. nrf_rtc_event_disable(p_instance->p_reg, mask);
  111. nrf_rtc_int_disable(p_instance->p_reg, mask);
  112. m_cb[p_instance->instance_id].state = NRFX_DRV_STATE_UNINITIALIZED;
  113. NRF_LOG_INFO("RTC: Uninitialized.");
  114. }
  115. void drv_rtc_start(drv_rtc_t const * const p_instance)
  116. {
  117. ASSERT(p_instance);
  118. nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_START);
  119. }
  120. void drv_rtc_stop(drv_rtc_t const * const p_instance)
  121. {
  122. ASSERT(p_instance);
  123. nrf_rtc_task_trigger(p_instance->p_reg, NRF_RTC_TASK_STOP);
  124. }
  125. void drv_rtc_compare_set(drv_rtc_t const * const p_instance,
  126. uint32_t cc,
  127. uint32_t abs_value,
  128. bool irq_enable)
  129. {
  130. ASSERT(p_instance);
  131. nrf_rtc_int_t cc_int_mask = (nrf_rtc_int_t)(NRF_RTC_INT_COMPARE0_MASK << cc);
  132. nrf_rtc_event_t cc_evt = CC_IDX_TO_CC_EVENT(cc);
  133. abs_value &= RTC_COUNTER_COUNTER_Msk;
  134. nrf_rtc_int_disable(p_instance->p_reg, cc_int_mask);
  135. nrf_rtc_event_disable(p_instance->p_reg, cc_int_mask);
  136. nrf_rtc_event_clear(p_instance->p_reg, cc_evt);
  137. nrf_rtc_cc_set(p_instance->p_reg, cc,abs_value);
  138. nrf_rtc_event_enable(p_instance->p_reg, cc_int_mask);
  139. if (irq_enable)
  140. {
  141. nrf_rtc_int_enable(p_instance->p_reg, cc_int_mask);
  142. }
  143. }
  144. static void evt_enable(drv_rtc_t const * const p_instance, uint32_t mask, bool irq_enable)
  145. {
  146. ASSERT(p_instance);
  147. nrf_rtc_event_enable(p_instance->p_reg, mask);
  148. if (irq_enable)
  149. {
  150. nrf_rtc_int_enable(p_instance->p_reg, mask);
  151. }
  152. }
  153. static void evt_disable(drv_rtc_t const * const p_instance, uint32_t mask)
  154. {
  155. ASSERT(p_instance);
  156. nrf_rtc_event_disable(p_instance->p_reg, mask);
  157. nrf_rtc_int_disable(p_instance->p_reg, mask);
  158. }
  159. static bool evt_pending(drv_rtc_t const * const p_instance, nrf_rtc_event_t event)
  160. {
  161. ASSERT(p_instance);
  162. if (nrf_rtc_event_pending(p_instance->p_reg, event))
  163. {
  164. nrf_rtc_event_clear(p_instance->p_reg, event);
  165. return true;
  166. }
  167. return false;
  168. }
  169. static uint32_t ticks_sub(uint32_t a, uint32_t b)
  170. {
  171. return (a - b) & RTC_COUNTER_COUNTER_Msk;
  172. }
  173. ret_code_t drv_rtc_windowed_compare_set(drv_rtc_t const * const p_instance,
  174. uint32_t cc,
  175. uint32_t abs_value,
  176. uint32_t safe_window)
  177. {
  178. ASSERT(p_instance);
  179. uint32_t prev_cc_set;
  180. uint32_t now;
  181. uint32_t diff;
  182. nrf_rtc_int_t cc_int_mask = (nrf_rtc_int_t)(NRF_RTC_INT_COMPARE0_MASK << cc);
  183. nrf_rtc_event_t cc_evt = CC_IDX_TO_CC_EVENT(cc);;
  184. abs_value &=RTC_COUNTER_COUNTER_Msk;
  185. evt_disable(p_instance, cc_int_mask);
  186. /* First handle potential prefiring caused by CC being set to next tick. Even if CC is
  187. * overwritten it may happen that event will be generated for previous CC in next tick.
  188. * Following algorith is applied:
  189. * - read previous CC
  190. * - write current counter value to CC (furtherest in future)
  191. * - if previous CC was in one tick from now wait half of the 32k tick and clear event which
  192. * may be set. Half tick delay is used because CC is latched in the middle of the 32k tick.
  193. */
  194. now = nrf_rtc_counter_get(p_instance->p_reg);
  195. prev_cc_set = nrf_rtc_cc_get(p_instance->p_reg, cc);
  196. nrf_rtc_cc_set(p_instance->p_reg, cc, now);
  197. nrf_rtc_event_clear(p_instance->p_reg, cc_evt);
  198. if (ticks_sub(prev_cc_set, now) == 1)
  199. {
  200. nrf_delay_us(16);
  201. nrf_rtc_event_clear(p_instance->p_reg, cc_evt);
  202. }
  203. now = nrf_rtc_counter_get(p_instance->p_reg);
  204. diff = ticks_sub(abs_value, now);
  205. nrf_rtc_event_enable(p_instance->p_reg, cc_int_mask);
  206. /* Setting CC for +1 from now may not generate event. In that case set CC+2 and check if counter
  207. * changed during that process. If changed it means that 1 tick expired. */
  208. if (diff == 1)
  209. {
  210. nrf_rtc_cc_set(p_instance->p_reg, cc, abs_value + 1);
  211. nrf_delay_us(16);
  212. if (now != nrf_rtc_counter_get(p_instance->p_reg))
  213. {
  214. /* one tick elapsed already. */
  215. return NRF_ERROR_TIMEOUT;
  216. }
  217. } else {
  218. nrf_rtc_cc_set(p_instance->p_reg, cc, abs_value);
  219. now = nrf_rtc_counter_get(p_instance->p_reg);
  220. diff = ticks_sub(abs_value - 1, now);
  221. /* Check if counter equals cc value or is behind in the safe window. If yes it means that
  222. * CC expired. */
  223. if (diff > (RTC_COUNTER_COUNTER_Msk - safe_window))
  224. {
  225. return NRF_ERROR_TIMEOUT;
  226. }
  227. else if (diff == 0)
  228. {
  229. /* If cc value == counter + 1, it may hit +1 case. */
  230. nrf_rtc_cc_set(p_instance->p_reg, cc, abs_value + 1);
  231. if (now != nrf_rtc_counter_get(p_instance->p_reg))
  232. {
  233. /* one tick elapsed already. */
  234. return NRF_ERROR_TIMEOUT;
  235. }
  236. }
  237. }
  238. evt_enable(p_instance, cc_int_mask, true);
  239. return NRF_SUCCESS;
  240. }
  241. void drv_rtc_overflow_enable(drv_rtc_t const * const p_instance, bool irq_enable)
  242. {
  243. evt_enable(p_instance, NRF_RTC_INT_OVERFLOW_MASK, irq_enable);
  244. }
  245. void drv_rtc_overflow_disable(drv_rtc_t const * const p_instance)
  246. {
  247. evt_disable(p_instance, NRF_RTC_INT_OVERFLOW_MASK);
  248. }
  249. bool drv_rtc_overflow_pending(drv_rtc_t const * const p_instance)
  250. {
  251. return evt_pending(p_instance, NRF_RTC_EVENT_OVERFLOW);
  252. }
  253. void drv_rtc_tick_enable(drv_rtc_t const * const p_instance, bool irq_enable)
  254. {
  255. evt_enable(p_instance, NRF_RTC_INT_TICK_MASK, irq_enable);
  256. }
  257. void drv_rtc_tick_disable(drv_rtc_t const * const p_instance)
  258. {
  259. evt_disable(p_instance, NRF_RTC_INT_TICK_MASK);
  260. }
  261. bool drv_rtc_tick_pending(drv_rtc_t const * const p_instance)
  262. {
  263. return evt_pending(p_instance, NRF_RTC_EVENT_TICK);
  264. }
  265. void drv_rtc_compare_enable(drv_rtc_t const * const p_instance,
  266. uint32_t cc,
  267. bool irq_enable)
  268. {
  269. evt_enable(p_instance, (uint32_t)NRF_RTC_INT_COMPARE0_MASK << cc, irq_enable);
  270. }
  271. void drv_rtc_compare_disable(drv_rtc_t const * const p_instance, uint32_t cc)
  272. {
  273. evt_disable(p_instance, (uint32_t)NRF_RTC_INT_COMPARE0_MASK << cc);
  274. }
  275. bool drv_rtc_compare_pending(drv_rtc_t const * const p_instance, uint32_t cc)
  276. {
  277. nrf_rtc_event_t cc_evt = CC_IDX_TO_CC_EVENT(cc);
  278. return evt_pending(p_instance, cc_evt);
  279. }
  280. uint32_t drv_rtc_compare_get(drv_rtc_t const * const p_instance, uint32_t cc)
  281. {
  282. return nrf_rtc_cc_get(p_instance->p_reg, cc);
  283. }
  284. uint32_t drv_rtc_counter_get(drv_rtc_t const * const p_instance)
  285. {
  286. return nrf_rtc_counter_get(p_instance->p_reg);
  287. }
  288. void drv_rtc_irq_trigger(drv_rtc_t const * const p_instance)
  289. {
  290. NVIC_SetPendingIRQ(p_instance->irq);
  291. }
  292. #define drv_rtc_rtc_0_irq_handler RTC0_IRQHandler
  293. #define drv_rtc_rtc_1_irq_handler RTC1_IRQHandler
  294. #define drv_rtc_rtc_2_irq_handler RTC2_IRQHandler
  295. #if defined(APP_TIMER_V2_RTC0_ENABLED)
  296. void drv_rtc_rtc_0_irq_handler(void)
  297. {
  298. m_handlers[DRV_RTC_RTC0_INST_IDX](m_cb[DRV_RTC_RTC0_INST_IDX].p_instance);
  299. }
  300. #endif
  301. #if defined(APP_TIMER_V2_RTC1_ENABLED)
  302. void drv_rtc_rtc_1_irq_handler(void)
  303. {
  304. m_handlers[DRV_RTC_RTC1_INST_IDX](m_cb[DRV_RTC_RTC1_INST_IDX].p_instance);
  305. }
  306. #endif
  307. #if defined(APP_TIMER_V2_RTC2_ENABLED)
  308. void drv_rtc_rtc_2_irq_handler(void)
  309. {
  310. m_handlers[DRV_RTC_RTC2_INST_IDX](m_cb[DRV_RTC_RTC2_INST_IDX].p_instance);
  311. }
  312. #endif