pal_os.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /**
  2. * MIT License
  3. *
  4. * Copyright (c) 2018 Infineon Technologies AG
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in all
  14. * copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. * SOFTWARE
  23. *
  24. *
  25. * \file
  26. *
  27. * \brief This file implements the platform abstraction layer APIs for os event/scheduler.
  28. *
  29. * \addtogroup grPAL
  30. * @{
  31. */
  32. /**********************************************************************************************************************
  33. * HEADER FILES
  34. *********************************************************************************************************************/
  35. #include <stdbool.h>
  36. #include "stdlib.h"
  37. #include "stdio.h"
  38. #include "optiga/pal/pal_os_event.h"
  39. #include "optiga/pal/pal_os_timer.h"
  40. #include "nrf_rtc.h"
  41. #include "nrf_drv_rtc.h"
  42. #include "nrf_delay.h"
  43. #include "nrf_pwr_mgmt.h"
  44. /**********************************************************************************************************************
  45. * MACROS
  46. *********************************************************************************************************************/
  47. /*********************************************************************************************************************
  48. * LOCAL DATA
  49. *********************************************************************************************************************/
  50. /// @cond hidden
  51. /// Callback function when timer elapses
  52. static volatile register_callback callback_registered = NULL;
  53. /// Pointer to store upper layer callback context (For example: Ifx i2c context)
  54. static void * callback_ctx;
  55. /// Flag to indicate to the delay function when the timer has elapsed
  56. static volatile bool timer_elapsed = false;
  57. /// Flag to indicate if the the RTC was already initialized, re-init. causes an NRF_ERROR
  58. static bool m_rtc2_is_initialized = false;
  59. static const nrf_drv_rtc_t rtc2 = NRF_DRV_RTC_INSTANCE(2);
  60. static nrf_drv_rtc_config_t m_rtc2_config = NRF_DRV_RTC_DEFAULT_CONFIG;
  61. #define RTC_CLOCK_FREQUENCY 32768
  62. // Set the prescaler to approximately get 0.25 ms intervals
  63. // 32768Hz/8 = 4096 Hz -> 0.2441us
  64. // it's a 24bit counter, so it will overflow every ~68min
  65. #define RTC_PRESCALER 8
  66. #define RTC_TICK_FREQ (RTC_CLOCK_FREQUENCY/RTC_PRESCALER)
  67. /**
  68. * Timer callback handler.
  69. *
  70. * This get called from the TIMER elapse event.<br>
  71. * Once the timer expires, the registered callback funtion gets called from the timer event handler, if
  72. * the call back is not NULL.<br>
  73. *
  74. *\param[in] args Callback argument
  75. *
  76. */
  77. static void ifx_rtc_handler(nrf_drv_rtc_int_type_t int_type)
  78. {
  79. volatile register_callback callback;
  80. (void)nrf_drv_rtc_cc_disable(&rtc2, int_type);
  81. switch(int_type)
  82. {
  83. case NRF_DRV_RTC_INT_COMPARE0:
  84. // handler for register_callback_oneshot
  85. if (callback_registered != NULL)
  86. {
  87. callback = callback_registered;
  88. callback_registered = NULL;
  89. callback(callback_ctx);
  90. }
  91. break;
  92. case NRF_DRV_RTC_INT_COMPARE1:
  93. // handler for delay_in_milliseconds
  94. timer_elapsed = true;
  95. break;
  96. default:
  97. break;
  98. }
  99. }
  100. /// @endcond
  101. void pal_os_event_init()
  102. {
  103. if (m_rtc2_is_initialized == true)
  104. {
  105. return;
  106. }
  107. // set prescaler so that a tick is approximately 1ms
  108. m_rtc2_config.prescaler = RTC_PRESCALER;
  109. // Initialize the RTC2 driver instance
  110. APP_ERROR_CHECK(nrf_drv_rtc_init(&rtc2, &m_rtc2_config, ifx_rtc_handler));
  111. // Power on RTC instance
  112. nrf_drv_rtc_enable(&rtc2);
  113. m_rtc2_is_initialized = true;
  114. }
  115. void pal_os_event_register_callback_oneshot(register_callback callback,
  116. void* callback_args,
  117. uint32_t time_us)
  118. {
  119. callback_registered = callback;
  120. callback_ctx = callback_args;
  121. // parentheses are set this way to avoid overflow when multiplying time_us with something
  122. uint32_t future_ticks = (time_us/(1000*1000/RTC_TICK_FREQ));
  123. // we can't reliably set an interrupt less than two ticks ahead, as per NRF52832 datasheet, p. 245
  124. // do busy waiting instead
  125. if(future_ticks < 2) {
  126. nrf_delay_us(time_us);
  127. ifx_rtc_handler(NRF_DRV_RTC_INT_COMPARE0);
  128. return;
  129. }
  130. // add current tick value
  131. future_ticks += nrf_drv_rtc_counter_get(&rtc2);
  132. // Set the compare register to trigger approximately at time_us
  133. APP_ERROR_CHECK(nrf_drv_rtc_cc_set(&rtc2, NRF_DRV_RTC_INT_COMPARE0, future_ticks, true));
  134. }
  135. uint32_t pal_os_timer_get_time_in_milliseconds(void)
  136. {
  137. return nrf_drv_rtc_counter_get(&rtc2)*1000/RTC_TICK_FREQ;
  138. }
  139. void pal_os_timer_delay_in_milliseconds(uint16_t milliseconds)
  140. {
  141. timer_elapsed = false;
  142. uint32_t future_ticks = milliseconds*(RTC_TICK_FREQ/1000);
  143. // we can't reliably set an interrupt less than two ticks ahead, as per NRF52832 datasheet, p. 245
  144. // do busy waiting instead
  145. if(future_ticks < 2) {
  146. nrf_delay_ms(milliseconds);
  147. return;
  148. }
  149. // add current tick value
  150. future_ticks += nrf_drv_rtc_counter_get(&rtc2);
  151. // Set the compare register to trigger in approximately milliseconds
  152. APP_ERROR_CHECK(nrf_drv_rtc_cc_set(&rtc2, NRF_DRV_RTC_INT_COMPARE1, future_ticks, true));
  153. while(!timer_elapsed)
  154. {
  155. nrf_pwr_mgmt_run();
  156. }
  157. timer_elapsed = false;
  158. }
  159. /**
  160. * @}
  161. */