From 8c25a0fd9d530bfaf3d665ac4649e9e543411928 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 16 Jan 2017 19:52:23 +0800 Subject: [PATCH] time: workaround for FRC_TIMER_INT_REG write issue MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 | 50 ++++++++++++++++++++++++++++++ components/newlib/time.c | 5 +++ 2 files changed, 55 insertions(+) create mode 100644 components/newlib/test/test_time.c diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c new file mode 100644 index 0000000000..a230a220bc --- /dev/null +++ b/components/newlib/test/test_time.c @@ -0,0 +1,50 @@ +#include +#include +#include "unity.h" +#include "driver/adc.h" +#include +#include +#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)); +} + diff --git a/components/newlib/time.c b/components/newlib/time.c index c9fa72eeee..004b7398c2 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -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; } -- 2.40.0