static const char* TAG = "esp_timer_impl";
-// Interrupt handle retuned by the interrupt allocator
+// Interrupt handle returned by the interrupt allocator
static intr_handle_t s_timer_interrupt_handle;
// Function from the upper layer to be called when the interrupt happens.
// value than the one which caused an interrupt. This can cause interrupt handler
// to consider that the interrupt has happened due to timer overflow, incrementing
// s_time_base_us. To avoid this, frequency switch hook sets this flag if
-// it needs to set timer alarm value to ALARM_OVERFLOW_VAL. Interrupt hanler
+// it needs to set timer alarm value to ALARM_OVERFLOW_VAL. Interrupt handler
// will not increment s_time_base_us if this flag is set.
static bool s_mask_overflow;
static void setup_overflow()
{
s_old_overflow_val = esp_timer_impl_get_overflow_val();
- esp_timer_impl_set_overflow_val(0x7fffff); /* overflow every ~0.1 sec */}
+ /* Overflow every 0.1 sec.
+ * Chosen so that it is 0 modulo s_timer_ticks_per_us (which is 80),
+ * to prevent roundoff error on each overflow.
+ */
+ esp_timer_impl_set_overflow_val(8000000);
+}
static void teardown_overflow()
{
TEST_PERFORMANCE_LESS_THAN(ESP_TIMER_GET_TIME_PER_CALL, "%dns", ns_per_call);
}
+static int64_t IRAM_ATTR __attribute__((noinline)) get_clock_diff()
+{
+ uint64_t hs_time = esp_timer_get_time();
+ uint64_t ref_time = ref_clock_get();
+ return hs_time - ref_time;
+}
+
TEST_CASE("esp_timer_get_time returns monotonic values", "[esp_timer]")
{
typedef struct {
bool pass;
int test_cnt;
int error_cnt;
- int64_t total_sq_error;
int64_t max_error;
int64_t avg_diff;
int64_t dummy;
state->pass = true;
/* make sure both functions are in cache */
- state->dummy = esp_timer_get_time();
- state->dummy += ref_clock_get();
+ state->dummy = get_clock_diff();
/* calculate the difference between the two clocks */
portDISABLE_INTERRUPTS();
- int64_t hs_start_time = esp_timer_get_time();
- int64_t start_time = ref_clock_get();
+ int64_t delta = get_clock_diff();
portENABLE_INTERRUPTS();
- int64_t delta = hs_start_time - start_time;
-
- int64_t now = start_time;
+ int64_t start_time = ref_clock_get();
int error_repeat_cnt = 0;
- while (now - start_time < 10000000) { /* 10 seconds */
+ while (ref_clock_get() - start_time < 10000000) { /* 10 seconds */
/* Get values of both clocks again, and check that they are close to 'delta'.
* We don't disable interrupts here, because esp_timer_get_time doesn't lock
* interrupts internally, so we check if it can get "broken" by a well placed
* interrupt.
*/
- int64_t hs_now = esp_timer_get_time();
- now = ref_clock_get();
- int64_t diff = hs_now - (now + delta);
+ int64_t diff = get_clock_diff() - delta;
/* Allow some difference due to rtos tick interrupting task between
* getting 'hs_now' and 'now'.
*/
state->avg_diff += diff;
state->max_error = MAX(state->max_error, abs(diff));
state->test_cnt++;
- state->total_sq_error += diff * diff;
}
state->avg_diff /= state->test_cnt;
xSemaphoreGive(state->done);
for (int i = 0; i < portNUM_PROCESSORS; ++i) {
TEST_ASSERT_TRUE( xSemaphoreTake(done, portMAX_DELAY) );
- printf("CPU%d: %s test_cnt=%d error_cnt=%d std_error=%d avg_diff=%d |max_error|=%d\n",
+ printf("CPU%d: %s test_cnt=%d error_cnt=%d avg_diff=%d |max_error|=%d\n",
i, states[i].pass ? "PASS" : "FAIL",
states[i].test_cnt, states[i].error_cnt,
- (int) sqrt(states[i].total_sq_error / states[i].test_cnt),
(int) states[i].avg_diff, (int) states[i].max_error);
}