esp_timer_esp32.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // Copyright 2017 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "esp_err.h"
  15. #include "esp_timer.h"
  16. #include "esp_system.h"
  17. #include "esp_task.h"
  18. #include "esp_attr.h"
  19. #include "esp_intr_alloc.h"
  20. #include "esp_log.h"
  21. #include "esp_timer_impl.h"
  22. #include "soc/frc_timer_reg.h"
  23. #include "soc/rtc.h"
  24. #include "freertos/FreeRTOS.h"
  25. #include "freertos/task.h"
  26. #include "freertos/semphr.h"
  27. /**
  28. * @file esp_timer_esp32.c
  29. * @brief Implementation of chip-specific part of esp_timer
  30. *
  31. * This implementation uses FRC2 (legacy) timer of the ESP32. This timer is
  32. * a 32-bit up-counting timer, with a programmable compare value (called 'alarm'
  33. * hereafter). When the timer reaches compare value, interrupt is raised.
  34. * The timer can be configured to produce an edge or a level interrupt.
  35. *
  36. * In this implementation the timer is used for two purposes:
  37. * 1. To generate interrupts at certain moments — the upper layer of esp_timer
  38. * uses this to trigger callbacks of esp_timer objects.
  39. *
  40. * 2. To keep track of time relative to application start. This facility is
  41. * used both by the upper layer of esp_timer and by time functions, such as
  42. * gettimeofday.
  43. *
  44. * Whenever an esp_timer timer is armed (configured to fire once or
  45. * periodically), timer_insert function of the upper layer calls
  46. * esp_timer_impl_set_alarm to enable the interrupt at the required moment.
  47. * This implementation sets up the timer interrupt to fire at the earliest of
  48. * two moments:
  49. * a) the time requested by upper layer
  50. * b) the time when the timer count reaches 0xffffffff (i.e. is about to overflow)
  51. *
  52. * Whenever the interrupt fires and timer overflow is detected, interrupt hander
  53. * increments s_time_base_us variable, which is used for timekeeping.
  54. *
  55. * When the interrupt fires, the upper layer is notified, and it dispatches
  56. * the callbacks (if any timers have expired) and sets new alarm value (if any
  57. * timers are still active).
  58. *
  59. * At any point in time, esp_timer_impl_get_time will return the current timer
  60. * value (expressed in microseconds) plus s_time_base_us. To account for the
  61. * case when the timer counter has overflown, but the interrupt has not fired
  62. * yet (for example, because interupts are temporarily disabled),
  63. * esp_timer_impl_get_time will also check timer overflow flag, and will add
  64. * s_timer_us_per_overflow to the returned value.
  65. *
  66. */
  67. /* Timer is clocked from APB. To allow for integer scaling factor between ticks
  68. * and microseconds, divider 1 is used. 16 or 256 would not work for APB
  69. * frequencies such as 40 or 26 or 2 MHz.
  70. */
  71. #define TIMER_DIV 1
  72. #define TIMER_DIV_CFG FRC_TIMER_PRESCALER_1
  73. /* ALARM_OVERFLOW_VAL is used as timer alarm value when there are not timers
  74. * enabled which need to fire within the next timer overflow period. This alarm
  75. * is used to perform timekeeping (i.e. to track timer overflows).
  76. */
  77. #define ALARM_OVERFLOW_VAL UINT32_MAX
  78. static const char* TAG = "esp_timer_impl";
  79. // Interrupt handle retuned by the interrupt allocator
  80. static intr_handle_t s_timer_interrupt_handle;
  81. // Function from the upper layer to be called when the interrupt happens.
  82. // Registered in esp_timer_impl_init.
  83. static intr_handler_t s_alarm_handler;
  84. // Time in microseconds from startup to the moment
  85. // when timer counter was last equal to 0. This variable is updated each time
  86. // when timer overflows, and when APB frequency switch is performed.
  87. static uint64_t s_time_base_us;
  88. // Number of timer ticks per microsecond. Calculated from APB frequency.
  89. static uint32_t s_timer_ticks_per_us;
  90. // Period between timer overflows, in microseconds.
  91. // Equal to 2^32 / s_timer_ticks_per_us.
  92. static uint32_t s_timer_us_per_overflow;
  93. // When frequency switch happens, timer counter is reset to 0, s_time_base_us
  94. // is updated, and alarm value is re-calculated based on the new APB frequency.
  95. // However because the frequency switch can happen before the final
  96. // interrupt handler is invoked, interrupt handler may see a different alarm
  97. // value than the one which caused an interrupt. This can cause interrupt handler
  98. // to consider that the interrupt has happened due to timer overflow, incrementing
  99. // s_time_base_us. To avoid this, frequency switch hook sets this flag if
  100. // it needs to set timer alarm value to ALARM_OVERFLOW_VAL. Interrupt hanler
  101. // will not increment s_time_base_us if this flag is set.
  102. static bool s_mask_overflow;
  103. // Spinlock used to protect access to static variables above and to the hardware
  104. // registers.
  105. portMUX_TYPE s_time_update_lock = portMUX_INITIALIZER_UNLOCKED;
  106. // Check if timer overflow has happened (but was not handled by ISR yet)
  107. static inline bool IRAM_ATTR timer_overflow_happened()
  108. {
  109. return (REG_READ(FRC_TIMER_CTRL_REG(1)) & FRC_TIMER_INT_STATUS) != 0 &&
  110. REG_READ(FRC_TIMER_ALARM_REG(1)) == ALARM_OVERFLOW_VAL &&
  111. !s_mask_overflow;
  112. }
  113. uint64_t IRAM_ATTR esp_timer_impl_get_time()
  114. {
  115. uint32_t timer_val;
  116. uint64_t time_base;
  117. uint32_t ticks_per_us;
  118. bool overflow;
  119. uint64_t us_per_overflow;
  120. do {
  121. /* Read all values needed to calculate current time */
  122. timer_val = REG_READ(FRC_TIMER_COUNT_REG(1));
  123. time_base = s_time_base_us;
  124. overflow = timer_overflow_happened();
  125. ticks_per_us = s_timer_ticks_per_us;
  126. us_per_overflow = s_timer_us_per_overflow;
  127. /* Read them again and compare */
  128. if (REG_READ(FRC_TIMER_COUNT_REG(1)) > timer_val &&
  129. time_base == *((volatile uint64_t*) &s_time_base_us) &&
  130. ticks_per_us == *((volatile uint32_t*) &s_timer_ticks_per_us) &&
  131. overflow == timer_overflow_happened()) {
  132. break;
  133. }
  134. /* If any value has changed (other than the counter increasing), read again */
  135. } while(true);
  136. uint64_t result = time_base
  137. + (overflow ? us_per_overflow : 0)
  138. + timer_val / ticks_per_us;
  139. return result;
  140. }
  141. void IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
  142. {
  143. portENTER_CRITICAL(&s_time_update_lock);
  144. // Alarm time relative to the moment when counter was 0
  145. uint64_t time_after_timebase_us = timestamp - s_time_base_us;
  146. // Adjust current time if overflow has happened
  147. bool overflow = timer_overflow_happened();
  148. if (overflow) {
  149. assert(time_after_timebase_us > s_timer_us_per_overflow);
  150. time_after_timebase_us -= s_timer_us_per_overflow;
  151. }
  152. // Calculate desired timer compare value (may exceed 2^32-1)
  153. uint64_t compare_val = time_after_timebase_us * s_timer_ticks_per_us;
  154. uint32_t alarm_reg_val = ALARM_OVERFLOW_VAL;
  155. // Use calculated alarm value if it is less than 2^32-1
  156. if (compare_val < ALARM_OVERFLOW_VAL) {
  157. uint64_t cur_count = REG_READ(FRC_TIMER_COUNT_REG(1));
  158. // If we by the time we update ALARM_REG, COUNT_REG value is higher,
  159. // interrupt will not happen for another 2^32 timer ticks, so need to
  160. // check if alarm value is too close in the future (e.g. <1 us away).
  161. uint32_t offset = s_timer_ticks_per_us;
  162. if (compare_val < cur_count + offset) {
  163. compare_val = cur_count + offset;
  164. if (compare_val > UINT32_MAX) {
  165. compare_val = ALARM_OVERFLOW_VAL;
  166. }
  167. }
  168. alarm_reg_val = (uint32_t) compare_val;
  169. }
  170. REG_WRITE(FRC_TIMER_ALARM_REG(1), alarm_reg_val);
  171. portEXIT_CRITICAL(&s_time_update_lock);
  172. }
  173. static void IRAM_ATTR timer_alarm_isr(void *arg)
  174. {
  175. portENTER_CRITICAL(&s_time_update_lock);
  176. // Timekeeping: adjust s_time_base_us if counter has passed ALARM_OVERFLOW_VAL
  177. if (timer_overflow_happened()) {
  178. s_time_base_us += s_timer_us_per_overflow;
  179. }
  180. s_mask_overflow = false;
  181. // Clear interrupt status
  182. REG_WRITE(FRC_TIMER_INT_REG(1), FRC_TIMER_INT_CLR);
  183. // Set alarm to the next overflow moment. Later, upper layer function may
  184. // call esp_timer_impl_set_alarm to change this to an earlier value.
  185. REG_WRITE(FRC_TIMER_ALARM_REG(1), ALARM_OVERFLOW_VAL);
  186. portEXIT_CRITICAL(&s_time_update_lock);
  187. // Call the upper layer handler
  188. (*s_alarm_handler)(arg);
  189. }
  190. esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
  191. {
  192. s_alarm_handler = alarm_handler;
  193. esp_err_t err = esp_intr_alloc(ETS_TIMER2_INTR_SOURCE,
  194. ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM,
  195. &timer_alarm_isr, NULL, &s_timer_interrupt_handle);
  196. if (err != ESP_OK) {
  197. ESP_EARLY_LOGE(TAG, "esp_intr_alloc failed (0x%0x)", err);
  198. return err;
  199. }
  200. uint32_t apb_freq = rtc_clk_apb_freq_get();
  201. s_timer_ticks_per_us = apb_freq / 1000000 / TIMER_DIV;
  202. assert(s_timer_ticks_per_us > 0
  203. && apb_freq % TIMER_DIV == 0
  204. && "APB frequency does not result in a valid ticks_per_us value");
  205. s_timer_us_per_overflow = FRC_TIMER_LOAD_VALUE(1) / s_timer_ticks_per_us;
  206. s_time_base_us = 0;
  207. REG_WRITE(FRC_TIMER_ALARM_REG(1), ALARM_OVERFLOW_VAL);
  208. REG_WRITE(FRC_TIMER_LOAD_REG(1), 0);
  209. REG_WRITE(FRC_TIMER_CTRL_REG(1),
  210. TIMER_DIV_CFG | FRC_TIMER_ENABLE | FRC_TIMER_LEVEL_INT);
  211. REG_WRITE(FRC_TIMER_INT_REG(1), FRC_TIMER_INT_CLR);
  212. ESP_ERROR_CHECK( esp_intr_enable(s_timer_interrupt_handle) );
  213. return ESP_OK;
  214. }
  215. void esp_timer_impl_deinit()
  216. {
  217. esp_intr_disable(s_timer_interrupt_handle);
  218. REG_WRITE(FRC_TIMER_CTRL_REG(1), 0);
  219. REG_WRITE(FRC_TIMER_ALARM_REG(1), 0);
  220. REG_WRITE(FRC_TIMER_LOAD_REG(1), 0);
  221. esp_intr_free(s_timer_interrupt_handle);
  222. s_timer_interrupt_handle = NULL;
  223. }
  224. // FIXME: This value is safe for 80MHz APB frequency.
  225. // Should be modified to depend on clock frequency.
  226. uint64_t esp_timer_impl_get_min_period_us()
  227. {
  228. return 50;
  229. }