]> granicus.if.org Git - esp-idf/commitdiff
time: workaround for FRC_TIMER_INT_REG write issue
authorIvan Grokhotkov <ivan@espressif.com>
Mon, 16 Jan 2017 11:52:23 +0000 (19:52 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Tue, 17 Jan 2017 04:29:09 +0000 (12:29 +0800)
In some cases (when RTC register reads are performed from the APP CPU), a write to FRC_TIMER_INT_REG may be lost on the bus.
Writing to another DPORT register immediately before or after that works around the issue.
We write one dummy value to an address which doesn’t have any register associated with it.

Fixes https://github.com/espressif/arduino-esp32/issues/120

components/newlib/test/test_time.c [new file with mode: 0644]
components/newlib/time.c

diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c
new file mode 100644 (file)
index 0000000..a230a22
--- /dev/null
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <math.h>
+#include "unity.h"
+#include "driver/adc.h"
+#include <time.h>
+#include <sys/time.h>
+#include "soc/rtc_cntl_reg.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "sdkconfig.h"
+
+
+// https://github.com/espressif/arduino-esp32/issues/120
+TEST_CASE("Reading RTC registers on APP CPU doesn't affect clock", "[newlib]")
+{
+    // This runs on APP CPU:
+    void time_adc_test_task(void* arg)
+    {
+        for (int i = 0; i < 200000; ++i) {
+            // wait for 20us, reading one of RTC registers
+            uint32_t ccount = xthal_get_ccount();
+            while (xthal_get_ccount() - ccount < 20 * CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) {
+                volatile uint32_t val = REG_READ(RTC_CNTL_STATE0_REG);
+                (void) val;
+            }
+        }
+        SemaphoreHandle_t * p_done = (SemaphoreHandle_t *) arg;
+        xSemaphoreGive(*p_done);
+        vTaskDelay(1);
+        vTaskDelete(NULL);
+    }
+
+    SemaphoreHandle_t done = xSemaphoreCreateBinary();
+    xTaskCreatePinnedToCore(&time_adc_test_task, "time_adc", 4096, &done, 5, NULL, 1);
+
+    // This runs on PRO CPU:
+    for (int i = 0; i < 4; ++i) {
+        struct timeval tv_start;
+        gettimeofday(&tv_start, NULL);
+        vTaskDelay(1000/portTICK_PERIOD_MS);
+        struct timeval tv_stop;
+        gettimeofday(&tv_stop, NULL);
+        float time_sec = tv_stop.tv_sec - tv_start.tv_sec + 1e-6f * (tv_stop.tv_usec - tv_start.tv_usec);
+        printf("(0) time taken: %f sec\n", time_sec);
+        TEST_ASSERT_TRUE(fabs(time_sec - 1.0f) < 0.1);
+    }
+    TEST_ASSERT_TRUE(xSemaphoreTake(done, 5000 / portTICK_RATE_MS));
+}
+
index c9fa72eeee82b80a44f552218b6264b9b4615b53..004b7398c2a541a790c4af89f500adc64caf92ea 100644 (file)
@@ -83,6 +83,11 @@ static volatile uint64_t s_microseconds = 0;
 
 static void IRAM_ATTR frc_timer_isr()
 {
+    // Write to FRC_TIMER_INT_REG may not take effect in some cases (root cause TBD)
+    // This extra write works around this issue.
+    // There is no register at DR_REG_FRC_TIMER_BASE + 0x60 (in fact, any DPORT register address can be used).
+    WRITE_PERI_REG(DR_REG_FRC_TIMER_BASE + 0x60, 0xabababab);
+    // Clear interrupt status
     WRITE_PERI_REG(FRC_TIMER_INT_REG(0), FRC_TIMER_INT_CLR);
     s_microseconds += FRC1_ISR_PERIOD_US;
 }