drv_rtc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /**
  2. * Copyright (c) 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 <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. ret_code_t drv_rtc_windowed_compare_set(drv_rtc_t const * const p_instance,
  145. uint32_t cc,
  146. uint32_t abs_value,
  147. uint32_t safe_window)
  148. {
  149. ASSERT(p_instance);
  150. uint32_t prev_cc_set;
  151. uint32_t counter;
  152. nrf_rtc_int_t cc_int_mask = (nrf_rtc_int_t)(NRF_RTC_INT_COMPARE0_MASK << cc);
  153. nrf_rtc_event_t cc_evt = CC_IDX_TO_CC_EVENT(cc);;
  154. abs_value &=RTC_COUNTER_COUNTER_Msk;
  155. nrf_rtc_int_disable(p_instance->p_reg, cc_int_mask);
  156. nrf_rtc_event_disable(p_instance->p_reg, cc_int_mask);
  157. nrf_rtc_event_clear(p_instance->p_reg, cc_evt);
  158. prev_cc_set = nrf_rtc_cc_get(p_instance->p_reg, cc);
  159. nrf_rtc_cc_set(p_instance->p_reg, cc,abs_value);
  160. /* If prev CC setting equals or is just in front of the counter then there is a risk that before
  161. * new CC will be set after enabling event previous CC will generate COMPARE event. In such risk
  162. * delay must be introduced between writting CC value and enabling the event.
  163. */
  164. counter = nrf_rtc_counter_get(p_instance->p_reg);
  165. if (((prev_cc_set - counter) & RTC_COUNTER_COUNTER_Msk) == 1)
  166. {
  167. NRF_LOG_DEBUG("RTC: Delay introduced due to risk of pre-firing.");
  168. nrf_delay_us(33);
  169. }
  170. nrf_rtc_event_enable(p_instance->p_reg, cc_int_mask);
  171. counter = nrf_rtc_counter_get(p_instance->p_reg);
  172. int32_t diff = (int32_t)abs_value - (int32_t)counter;
  173. diff &= RTC_COUNTER_COUNTER_Msk;
  174. diff = (diff & 0x800000) ? (diff | 0xFF000000) : diff;
  175. /* If diff shows that abs_value is after the counter or up to 2 ticks before then it is assumed
  176. * that compare channel was set to late. It is based on a assumption that abs_value will never
  177. * be set to value bigger than maximum counter value - safe window. */
  178. if ((diff > -(int32_t)((safe_window & RTC_COUNTER_COUNTER_Msk))) && (diff <= COUNTER_TO_CC_MIN_DISTANCE))
  179. {
  180. //set CC to something back in time to prevent event triggering on next compare set.
  181. NRF_LOG_DEBUG("RTC: Windowed compare set timeout (abs_value:%d, counter:%d).",
  182. abs_value, counter);
  183. return NRF_ERROR_TIMEOUT;
  184. }
  185. else
  186. {
  187. nrf_rtc_int_enable(p_instance->p_reg, cc_int_mask);
  188. }
  189. return NRF_SUCCESS;
  190. }
  191. static void evt_enable(drv_rtc_t const * const p_instance, uint32_t mask, bool irq_enable)
  192. {
  193. ASSERT(p_instance);
  194. nrf_rtc_event_enable(p_instance->p_reg, mask);
  195. if (irq_enable)
  196. {
  197. nrf_rtc_int_enable(p_instance->p_reg, mask);
  198. }
  199. }
  200. static void evt_disable(drv_rtc_t const * const p_instance, uint32_t mask)
  201. {
  202. ASSERT(p_instance);
  203. nrf_rtc_event_disable(p_instance->p_reg, mask);
  204. nrf_rtc_int_disable(p_instance->p_reg, mask);
  205. }
  206. static bool evt_pending(drv_rtc_t const * const p_instance, nrf_rtc_event_t event)
  207. {
  208. ASSERT(p_instance);
  209. if (nrf_rtc_event_pending(p_instance->p_reg, event))
  210. {
  211. nrf_rtc_event_clear(p_instance->p_reg, event);
  212. return true;
  213. }
  214. return false;
  215. }
  216. void drv_rtc_overflow_enable(drv_rtc_t const * const p_instance, bool irq_enable)
  217. {
  218. evt_enable(p_instance, NRF_RTC_INT_OVERFLOW_MASK, irq_enable);
  219. }
  220. void drv_rtc_overflow_disable(drv_rtc_t const * const p_instance)
  221. {
  222. evt_disable(p_instance, NRF_RTC_INT_OVERFLOW_MASK);
  223. }
  224. bool drv_rtc_overflow_pending(drv_rtc_t const * const p_instance)
  225. {
  226. return evt_pending(p_instance, NRF_RTC_EVENT_OVERFLOW);
  227. }
  228. void drv_rtc_tick_enable(drv_rtc_t const * const p_instance, bool irq_enable)
  229. {
  230. evt_enable(p_instance, NRF_RTC_INT_TICK_MASK, irq_enable);
  231. }
  232. void drv_rtc_tick_disable(drv_rtc_t const * const p_instance)
  233. {
  234. evt_disable(p_instance, NRF_RTC_INT_TICK_MASK);
  235. }
  236. bool drv_rtc_tick_pending(drv_rtc_t const * const p_instance)
  237. {
  238. return evt_pending(p_instance, NRF_RTC_EVENT_TICK);
  239. }
  240. void drv_rtc_compare_enable(drv_rtc_t const * const p_instance,
  241. uint32_t cc,
  242. bool irq_enable)
  243. {
  244. evt_enable(p_instance, (uint32_t)NRF_RTC_INT_COMPARE0_MASK << cc, irq_enable);
  245. }
  246. void drv_rtc_compare_disable(drv_rtc_t const * const p_instance, uint32_t cc)
  247. {
  248. evt_disable(p_instance, (uint32_t)NRF_RTC_INT_COMPARE0_MASK << cc);
  249. }
  250. bool drv_rtc_compare_pending(drv_rtc_t const * const p_instance, uint32_t cc)
  251. {
  252. nrf_rtc_event_t cc_evt = CC_IDX_TO_CC_EVENT(cc);
  253. return evt_pending(p_instance, cc_evt);
  254. }
  255. uint32_t drv_rtc_counter_get(drv_rtc_t const * const p_instance)
  256. {
  257. return nrf_rtc_counter_get(p_instance->p_reg);
  258. }
  259. void drv_rtc_irq_trigger(drv_rtc_t const * const p_instance)
  260. {
  261. NVIC_SetPendingIRQ(p_instance->irq);
  262. }
  263. #define drv_rtc_rtc_0_irq_handler RTC0_IRQHandler
  264. #define drv_rtc_rtc_1_irq_handler RTC1_IRQHandler
  265. #define drv_rtc_rtc_2_irq_handler RTC2_IRQHandler
  266. #if defined(APP_TIMER_V2_RTC0_ENABLED)
  267. void drv_rtc_rtc_0_irq_handler(void)
  268. {
  269. m_handlers[DRV_RTC_RTC0_INST_IDX](m_cb[DRV_RTC_RTC0_INST_IDX].p_instance);
  270. }
  271. #endif
  272. #if defined(APP_TIMER_V2_RTC1_ENABLED)
  273. void drv_rtc_rtc_1_irq_handler(void)
  274. {
  275. m_handlers[DRV_RTC_RTC1_INST_IDX](m_cb[DRV_RTC_RTC1_INST_IDX].p_instance);
  276. }
  277. #endif
  278. #if defined(APP_TIMER_V2_RTC2_ENABLED)
  279. void drv_rtc_rtc_2_irq_handler(void)
  280. {
  281. m_handlers[DRV_RTC_RTC2_INST_IDX](m_cb[DRV_RTC_RTC2_INST_IDX].p_instance);
  282. }
  283. #endif