diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c new file mode 100644 index 000000000..a230a220b --- /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 c9fa72eee..30c7ca7f4 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -83,12 +83,18 @@ 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; } #endif // WITH_FRC1 +#if defined(WITH_RTC) || defined(WITH_FRC1) static void set_boot_time(uint64_t time_us) { _lock_acquire(&s_boot_time_lock); @@ -113,6 +119,7 @@ static uint64_t get_boot_time() _lock_release(&s_boot_time_lock); return result; } +#endif //defined(WITH_RTC) || defined(WITH_FRC1) void esp_setup_time_syscalls() {