systimer_hal.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stddef.h>
  7. #include <sys/param.h>
  8. #include "soc/soc_caps.h"
  9. #include "hal/systimer_hal.h"
  10. #include "hal/systimer_ll.h"
  11. #include "hal/systimer_types.h"
  12. #include "hal/assert.h"
  13. void systimer_hal_init(systimer_hal_context_t *hal)
  14. {
  15. hal->dev = &SYSTIMER;
  16. systimer_ll_enable_clock(hal->dev, true);
  17. }
  18. void systimer_hal_deinit(systimer_hal_context_t *hal)
  19. {
  20. systimer_ll_enable_clock(hal->dev, false);
  21. hal->dev = NULL;
  22. }
  23. void systimer_hal_set_tick_rate_ops(systimer_hal_context_t *hal, systimer_hal_tick_rate_ops_t *ops)
  24. {
  25. hal->ticks_to_us = ops->ticks_to_us;
  26. hal->us_to_ticks = ops->us_to_ticks;
  27. }
  28. uint64_t systimer_hal_get_counter_value(systimer_hal_context_t *hal, uint32_t counter_id)
  29. {
  30. uint32_t lo, lo_start, hi;
  31. /* Set the "update" bit and wait for acknowledgment */
  32. systimer_ll_counter_snapshot(hal->dev, counter_id);
  33. while (!systimer_ll_is_counter_value_valid(hal->dev, counter_id));
  34. /* Read LO, HI, then LO again, check that LO returns the same value.
  35. * This accounts for the case when an interrupt may happen between reading
  36. * HI and LO values, and this function may get called from the ISR.
  37. * In this case, the repeated read will return consistent values.
  38. */
  39. lo_start = systimer_ll_get_counter_value_low(hal->dev, counter_id);
  40. do {
  41. lo = lo_start;
  42. hi = systimer_ll_get_counter_value_high(hal->dev, counter_id);
  43. lo_start = systimer_ll_get_counter_value_low(hal->dev, counter_id);
  44. } while (lo_start != lo);
  45. systimer_counter_value_t result = {
  46. .lo = lo,
  47. .hi = hi
  48. };
  49. return result.val;
  50. }
  51. uint64_t systimer_hal_get_time(systimer_hal_context_t *hal, uint32_t counter_id)
  52. {
  53. return hal->ticks_to_us(systimer_hal_get_counter_value(hal, counter_id));
  54. }
  55. #if SOC_SYSTIMER_ALARM_MISS_COMPENSATE
  56. void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t target)
  57. {
  58. systimer_counter_value_t alarm = {
  59. .val = hal->us_to_ticks(target),
  60. };
  61. systimer_ll_enable_alarm(hal->dev, alarm_id, false);
  62. systimer_ll_set_alarm_target(hal->dev, alarm_id, alarm.val);
  63. systimer_ll_apply_alarm_value(hal->dev, alarm_id);
  64. systimer_ll_enable_alarm(hal->dev, alarm_id, true);
  65. }
  66. #else // SOC_SYSTIMER_ALARM_MISS_COMPENSATE
  67. void systimer_hal_set_alarm_target(systimer_hal_context_t *hal, uint32_t alarm_id, uint64_t timestamp)
  68. {
  69. int64_t offset = hal->us_to_ticks(1) * 2;
  70. uint64_t now_time = systimer_hal_get_counter_value(hal, 0);
  71. systimer_counter_value_t alarm = { .val = MAX(hal->us_to_ticks(timestamp), now_time + offset) };
  72. do {
  73. systimer_ll_enable_alarm(hal->dev, alarm_id, false);
  74. systimer_ll_set_alarm_target(hal->dev, alarm_id, alarm.val);
  75. systimer_ll_enable_alarm(hal->dev, alarm_id, true);
  76. now_time = systimer_hal_get_counter_value(hal, 0);
  77. int64_t delta = (int64_t)alarm.val - (int64_t)now_time;
  78. if (delta <= 0 && !systimer_ll_is_alarm_int_fired(hal->dev, alarm_id)) {
  79. // new alarm is less than the counter and the interrupt flag is not set
  80. offset += -1 * delta + hal->us_to_ticks(1) * 2;
  81. alarm.val = now_time + offset;
  82. } else {
  83. // finish if either (alarm > counter) or the interrupt flag is already set.
  84. break;
  85. }
  86. } while (1);
  87. }
  88. #endif // SOC_SYSTIMER_ALARM_MISS_COMPENSATE
  89. void systimer_hal_set_alarm_period(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t period)
  90. {
  91. systimer_ll_enable_alarm(hal->dev, alarm_id, false);
  92. systimer_ll_set_alarm_period(hal->dev, alarm_id, hal->us_to_ticks(period));
  93. systimer_ll_apply_alarm_value(hal->dev, alarm_id);
  94. systimer_ll_enable_alarm(hal->dev, alarm_id, true);
  95. }
  96. uint64_t systimer_hal_get_alarm_value(systimer_hal_context_t *hal, uint32_t alarm_id)
  97. {
  98. return systimer_ll_get_alarm_target(hal->dev, alarm_id);
  99. }
  100. void systimer_hal_enable_alarm_int(systimer_hal_context_t *hal, uint32_t alarm_id)
  101. {
  102. systimer_ll_enable_alarm_int(hal->dev, alarm_id, true);
  103. }
  104. void systimer_hal_counter_value_advance(systimer_hal_context_t *hal, uint32_t counter_id, int64_t time_us)
  105. {
  106. systimer_counter_value_t new_count = {
  107. .val = systimer_hal_get_counter_value(hal, counter_id) + hal->us_to_ticks(time_us),
  108. };
  109. systimer_ll_set_counter_value(hal->dev, counter_id, new_count.val);
  110. systimer_ll_apply_counter_value(hal->dev, counter_id);
  111. }
  112. void systimer_hal_enable_counter(systimer_hal_context_t *hal, uint32_t counter_id)
  113. {
  114. systimer_ll_enable_counter(hal->dev, counter_id, true);
  115. }
  116. void systimer_hal_select_alarm_mode(systimer_hal_context_t *hal, uint32_t alarm_id, systimer_alarm_mode_t mode)
  117. {
  118. switch (mode) {
  119. case SYSTIMER_ALARM_MODE_ONESHOT:
  120. systimer_ll_enable_alarm_oneshot(hal->dev, alarm_id);
  121. break;
  122. case SYSTIMER_ALARM_MODE_PERIOD:
  123. systimer_ll_enable_alarm_period(hal->dev, alarm_id);
  124. break;
  125. default:
  126. break;
  127. }
  128. }
  129. void systimer_hal_connect_alarm_counter(systimer_hal_context_t *hal, uint32_t alarm_id, uint32_t counter_id)
  130. {
  131. systimer_ll_connect_alarm_counter(hal->dev, alarm_id, counter_id);
  132. }
  133. void systimer_hal_counter_can_stall_by_cpu(systimer_hal_context_t *hal, uint32_t counter_id, uint32_t cpu_id, bool can)
  134. {
  135. systimer_ll_counter_can_stall_by_cpu(hal->dev, counter_id, cpu_id, can);
  136. }
  137. #if !SOC_SYSTIMER_FIXED_DIVIDER
  138. void systimer_hal_set_steps_per_tick(systimer_hal_context_t *hal, int clock_source, uint32_t steps)
  139. {
  140. /* Configure the counter:
  141. * - increment by 1 when running from PLL (80 ticks per microsecond),
  142. * - increment by 2 when running from XTAL (40 ticks per microsecond).
  143. * Note that if the APB frequency is derived from XTAL with divider != 1,
  144. * XTAL_STEP needs to be adjusted accordingly. For example, if
  145. * the APB frequency is XTAL/4 = 10 MHz, then XTAL_STEP should be set to 8.
  146. * This is handled in systimer_hal_on_apb_freq_update function.
  147. */
  148. switch (clock_source) {
  149. case 0:
  150. systimer_ll_set_step_for_xtal(hal->dev, steps);
  151. break;
  152. case 1:
  153. systimer_ll_set_step_for_pll(hal->dev, steps);
  154. default:
  155. break;
  156. }
  157. }
  158. void systimer_hal_on_apb_freq_update(systimer_hal_context_t *hal, uint32_t apb_ticks_per_us)
  159. {
  160. /* If this function was called when switching APB clock to PLL, don't need
  161. * do anything: the SYSTIMER_TIMER_PLL_STEP is already correct.
  162. * If this was called when switching APB clock to XTAL, need to adjust
  163. * XTAL_STEP value accordingly.
  164. */
  165. if (apb_ticks_per_us != hal->us_to_ticks(1)) {
  166. HAL_ASSERT((hal->us_to_ticks(1) % apb_ticks_per_us) == 0 && "TICK_PER_US should be divisible by APB frequency (in MHz)");
  167. systimer_ll_set_step_for_xtal(hal->dev, hal->us_to_ticks(1) / apb_ticks_per_us);
  168. }
  169. }
  170. #endif // !SOC_SYSTIMER_FIXED_DIVIDER