Kaynağa Gözat

freertos(esp32s3): SysTick uses systimer

Konstantin Kondrashov 4 yıl önce
ebeveyn
işleme
29f581fc70

+ 5 - 4
components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c

@@ -151,16 +151,17 @@ extern const SEGGER_SYSVIEW_OS_API SYSVIEW_X_OS_TraceAPI;
 // The lowest RAM address used for IDs (pointers)
 #define SYSVIEW_RAM_BASE        (SOC_DROM_LOW)
 
-#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
+#ifdef CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
 #if CONFIG_FREERTOS_CORETIMER_0
     #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
 #endif
 #if CONFIG_FREERTOS_CORETIMER_1
     #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
 #endif
-#elif CONFIG_IDF_TARGET_ESP32C3
-    #define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
-#endif
+
+#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
+    #define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE)
+#endif // CONFIG_FREERTOS_TICK_SUPPORT_CORETIMER
 
 // SystemView is single core specific: it implies that SEGGER_SYSVIEW_LOCK()
 // disables IRQs (disables rescheduling globally). So we can not use finite timeouts for locks and return error

+ 1 - 1
components/efuse/test/test_efuse.c

@@ -854,7 +854,7 @@ static void reset_task(void* arg)
     ESP_LOGI(TAG, "Start reset task");
     while (!cmd_stop_reset_task) {
         esp_efuse_utility_reset();
-        vTaskDelay(1);
+        vTaskDelay(2);
     }
     vTaskDelete(NULL);
 }

+ 14 - 14
components/esp_pm/pm_impl.c

@@ -31,7 +31,7 @@
 
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
-#if __XTENSA__
+#if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 #include "freertos/xtensa_timer.h"
 #include "xtensa/core-macros.h"
 #endif
@@ -68,7 +68,7 @@
 
 #define MHZ (1000000)
 
-#if __XTENSA__
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 /* CCOMPARE update timeout, in CPU cycles. Any value above ~600 cycles will work
  * for the purpose of detecting a deadlock.
  */
@@ -78,7 +78,7 @@
  * than this. This is to prevent setting CCOMPARE below CCOUNT.
  */
 #define CCOMPARE_MIN_CYCLES_IN_FUTURE 1000
-#endif
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 
 /* When light sleep is used, wake this number of microseconds earlier than
  * the next tick.
@@ -184,7 +184,7 @@ static const char* s_mode_names[] = {
 };
 #endif // WITH_PROFILING
 
-#if __XTENSA__
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 /* Indicates to the ISR hook that CCOMPARE needs to be updated on the given CPU.
  * Used in conjunction with cross-core interrupt to update CCOMPARE on the other CPU.
  */
@@ -197,7 +197,7 @@ static uint32_t s_ccount_div;
 static uint32_t s_ccount_mul;
 
 static void update_ccompare(void);
-#endif // __XTENSA__
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 
 static const char* TAG = "pm";
 
@@ -425,7 +425,7 @@ static void IRAM_ATTR on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_p
         esp_timer_private_update_apb_freq(apb_ticks_per_us);
     }
 
-#if __XTENSA__
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 #ifdef XT_RTOS_TIMER_INT
     /* Calculate new tick divisor */
     _xt_tick_divisor = ticks_per_us * MHZ / XT_TICK_PER_SEC;
@@ -462,7 +462,7 @@ static void IRAM_ATTR on_freq_update(uint32_t old_ticks_per_us, uint32_t ticks_p
         s_ccount_div = 0;
         ESP_PM_TRACE_EXIT(CCOMPARE_UPDATE, core_id);
     }
-#endif // __XTENSA__
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 }
 
 /**
@@ -484,7 +484,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
             portEXIT_CRITICAL_ISR(&s_switch_lock);
             return;
         }
-#if __XTENSA__
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
         if (s_need_update_ccompare[core_id]) {
             s_need_update_ccompare[core_id] = false;
         }
@@ -529,7 +529,7 @@ static void IRAM_ATTR do_switch(pm_mode_t new_mode)
     portEXIT_CRITICAL_ISR(&s_switch_lock);
 }
 
-#if __XTENSA__
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 /**
  * @brief Calculate new CCOMPARE value based on s_ccount_{mul,div}
  *
@@ -550,7 +550,7 @@ static void IRAM_ATTR update_ccompare(void)
         }
     }
 }
-#endif // __XTENSA__
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 
 static void IRAM_ATTR leave_idle(void)
 {
@@ -656,7 +656,7 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
                 /* Adjust RTOS tick count based on the amount of time spent in sleep */
                 vTaskStepTick(slept_ticks);
 
-#if __XTENSA__
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
                 /* Trigger tick interrupt, since sleep time was longer
                  * than portTICK_PERIOD_MS. Note that setting INTSET does not
                  * work for timer interrupt, and changing CCOMPARE would clear
@@ -666,7 +666,7 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
                 while (!(XTHAL_GET_INTERRUPT() & BIT(XT_TIMER_INTNUM))) {
                     ;
                 }
-#elif __riscv
+#else
                 portYIELD_WITHIN_API();
 #endif
             }
@@ -810,7 +810,7 @@ void IRAM_ATTR esp_pm_impl_isr_hook(void)
      * from happening in this section, since they will also call into esp_pm_impl_isr_hook.
      */
     uint32_t state = portENTER_CRITICAL_NESTED();
-#if __XTENSA__ && (portNUM_PROCESSORS == 2)
+#if defined(CONFIG_FREERTOS_SYSTICK_USES_CCOUNT) && (portNUM_PROCESSORS == 2)
     if (s_need_update_ccompare[core_id]) {
         update_ccompare();
         s_need_update_ccompare[core_id] = false;
@@ -819,7 +819,7 @@ void IRAM_ATTR esp_pm_impl_isr_hook(void)
     }
 #else
     leave_idle();
-#endif // portNUM_PROCESSORS == 2
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT && portNUM_PROCESSORS == 2
     portEXIT_CRITICAL_NESTED(state);
     ESP_PM_TRACE_EXIT(ISR_HOOK, core_id);
 }

+ 1 - 1
components/esp_system/port/soc/esp32c3/system_internal.c

@@ -110,7 +110,7 @@ void IRAM_ATTR esp_restart_noos(void)
 
     // Reset timer/spi/uart
     SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG,
-                      SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST);
+                      SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST | SYSTEM_SYSTIMER_RST);
     REG_WRITE(SYSTEM_PERIP_RST_EN0_REG, 0);
     // Reset dma
     SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST);

+ 1 - 1
components/esp_system/port/soc/esp32h2/system_internal.c

@@ -94,7 +94,7 @@ void IRAM_ATTR esp_restart_noos(void)
 
     // Reset timer/spi/uart
     SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG,
-                      SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST);
+                      SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST | SYSTEM_SYSTIMER_RST);
     REG_WRITE(SYSTEM_PERIP_RST_EN0_REG, 0);
     // Reset dma
     SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN1_REG, SYSTEM_DMA_RST);

+ 1 - 1
components/esp_system/port/soc/esp32s3/system_internal.c

@@ -103,7 +103,7 @@ void IRAM_ATTR esp_restart_noos(void)
 
     // Reset timer/spi/uart
     SET_PERI_REG_MASK(SYSTEM_PERIP_RST_EN0_REG,
-                      SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST);
+                      SYSTEM_TIMERS_RST | SYSTEM_SPI01_RST | SYSTEM_UART_RST | SYSTEM_SYSTIMER_RST);
     REG_WRITE(SYSTEM_PERIP_RST_EN0_REG, 0);
 
     // Reset dma

+ 2 - 2
components/esp_timer/src/esp_timer_impl_systimer.c

@@ -133,7 +133,7 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
                                    &timer_alarm_isr, NULL, &s_timer_interrupt_handle);
 
     if (err != ESP_OK) {
-        ESP_EARLY_LOGE(TAG, "esp_intr_alloc failed (%#x)", err);
+        ESP_EARLY_LOGE(TAG, "esp_intr_alloc failed (0x%x)", err);
         goto err_intr_alloc;
     }
 
@@ -155,7 +155,7 @@ esp_err_t esp_timer_impl_init(intr_handler_t alarm_handler)
 
     err = esp_intr_enable(s_timer_interrupt_handle);
     if (err != ESP_OK) {
-        ESP_EARLY_LOGE(TAG, "esp_intr_enable failed (%#x)", err);
+        ESP_EARLY_LOGE(TAG, "esp_intr_enable failed (0x%x)", err);
         goto err_intr_en;
     }
     return ESP_OK;

+ 9 - 6
components/freertos/CMakeLists.txt

@@ -6,8 +6,7 @@ endif()
 
 idf_build_get_property(target IDF_TARGET)
 
-# should test arch here not target, TODO ESP32-C3 IDF-1754
-if(NOT "${target}" STREQUAL "esp32c3" AND NOT "${target}" STREQUAL "esp32h2")
+if(CONFIG_IDF_TARGET_ARCH_XTENSA)
     set(srcs
         "port/xtensa/port.c"
         "port/xtensa/portasm.S"
@@ -25,10 +24,10 @@ if(NOT "${target}" STREQUAL "esp32c3" AND NOT "${target}" STREQUAL "esp32h2")
         include/freertos
         port/xtensa/include/freertos
         port/xtensa
+        port/priv_include
         .)
 
-    set(required_components app_trace esp_timer)
-else()  # RISC-V
+elseif(CONFIG_IDF_TARGET_ARCH_RISCV)
     set(srcs
         "port/riscv/port.c"
         "port/riscv/portasm.S")
@@ -41,13 +40,14 @@ else()  # RISC-V
         include/freertos
         port/riscv/include/freertos
         port/riscv
+        port/priv_include
         .)
 
-    set(required_components app_trace esp_timer)
 endif()
 
 list(APPEND srcs
     "port/port_common.c"
+    "port/port_systick.c"
     "croutine.c"
     "event_groups.c"
     "list.c"
@@ -62,8 +62,11 @@ if(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY)
     list(APPEND srcs "port/xtensa/xtensa_loadstore_handler.S")
 endif()
 
+# esp_timer is required by FreeRTOS because we use esp_tiemr_get_time() to do profiling
 # app_trace is required by FreeRTOS headers only when CONFIG_APPTRACE_SV_ENABLE=y,
-# but requirements can't depend on config options, so always require it.
+# REQUIRES can't depend on config options, so always require it.
+set(required_components app_trace esp_timer)
+
 idf_component_register(SRCS "${srcs}"
                     INCLUDE_DIRS ${include_dirs}
                     PRIV_INCLUDE_DIRS  ${private_include_dirs}

+ 38 - 1
components/freertos/Kconfig

@@ -18,9 +18,23 @@ menu "FreeRTOS"
         hex
         default 0x7FFFFFFF
 
+    config FREERTOS_TICK_SUPPORT_CORETIMER
+        bool
+        default y if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2
+
+    config FREERTOS_TICK_SUPPORT_SYSTIMER
+        bool
+        default y if !FREERTOS_TICK_SUPPORT_CORETIMER
+        # ESP32-S3, ESP32-C3 and ESP32-H2 can use Systimer for FreeRTOS SysTick
+        # ESP32S2 also has SYSTIMER but it can not be used for the FreeRTOS SysTick because:
+        # - It has only one counter, which already in use esp_timer.
+        #   A counter for SysTick should be stall in debug mode but work esp_timer.
+        # - It is not possible to allocate two handlers for esp_timer and SysTick.
+
     choice FREERTOS_CORETIMER
         prompt "Xtensa timer to use as the FreeRTOS tick source"
-        default FREERTOS_CORETIMER_0
+        default FREERTOS_CORETIMER_0 if FREERTOS_TICK_SUPPORT_CORETIMER
+        default FREERTOS_CORETIMER_SYSTIMER_LVL1 if FREERTOS_TICK_SUPPORT_SYSTIMER
         help
             FreeRTOS needs a timer with an associated interrupt to use as
             the main tick source to increase counters, run timers and do
@@ -29,16 +43,38 @@ menu "FreeRTOS"
 
         config FREERTOS_CORETIMER_0
             bool "Timer 0 (int 6, level 1)"
+            depends on FREERTOS_TICK_SUPPORT_CORETIMER
             help
                 Select this to use timer 0
 
         config FREERTOS_CORETIMER_1
             bool "Timer 1 (int 15, level 3)"
+            depends on FREERTOS_TICK_SUPPORT_CORETIMER
             help
                 Select this to use timer 1
 
+        config FREERTOS_CORETIMER_SYSTIMER_LVL1
+            bool "SYSTIMER 0 (level 1)"
+            depends on FREERTOS_TICK_SUPPORT_SYSTIMER
+            help
+                Select this to use systimer with the 1 interrupt priority.
+
+        config FREERTOS_CORETIMER_SYSTIMER_LVL3
+            bool "SYSTIMER 0 (level 3)"
+            depends on FREERTOS_TICK_SUPPORT_SYSTIMER
+            help
+                Select this to use systimer with the 3 interrupt priority.
+
     endchoice
 
+    config FREERTOS_SYSTICK_USES_SYSTIMER
+        bool
+        default y if FREERTOS_CORETIMER_SYSTIMER_LVL1 || FREERTOS_CORETIMER_SYSTIMER_LVL3
+
+    config FREERTOS_SYSTICK_USES_CCOUNT
+        bool
+        default y if FREERTOS_CORETIMER_0 || FREERTOS_CORETIMER_1
+
     config FREERTOS_OPTIMIZED_SCHEDULER
         bool "Enable FreeRTOS pĺatform optimized scheduler"
         depends on FREERTOS_UNICORE
@@ -343,6 +379,7 @@ menu "FreeRTOS"
 
         config FREERTOS_RUN_TIME_STATS_USING_CPU_CLK
             bool "Use CPU Clock for run time stats"
+            depends on FREERTOS_SYSTICK_USES_CCOUNT
             help
                 CPU Clock will be used as the clock source for the generation of run
                 time stats. The CPU Clock has a frequency dependent on

+ 1 - 1
components/freertos/component.mk

@@ -7,7 +7,7 @@ ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE
 endif
 
 COMPONENT_ADD_INCLUDEDIRS := include port/xtensa/include
-COMPONENT_PRIV_INCLUDEDIRS := include/freertos port/xtensa/include/freertos port/xtensa .
+COMPONENT_PRIV_INCLUDEDIRS := include/freertos port/xtensa/include/freertos port/xtensa port/priv_include .
 COMPONENT_SRCDIRS += port port/xtensa
 
 ifndef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY

+ 172 - 0
components/freertos/port/port_systick.c

@@ -0,0 +1,172 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "soc/cpu.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "esp_intr_alloc.h"
+#include "esp_err.h"
+#include "esp_log.h"
+#include "sdkconfig.h"
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
+#include "soc/periph_defs.h"
+#include "soc/system_reg.h"
+#include "hal/systimer_hal.h"
+#include "hal/systimer_ll.h"
+#endif
+
+BaseType_t xPortSysTickHandler(void);
+
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
+extern void _frxt_tick_timer_init(void);
+extern void _xt_tick_divisor_init(void);
+
+#ifdef CONFIG_FREERTOS_CORETIMER_0
+    #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
+#endif
+#ifdef CONFIG_FREERTOS_CORETIMER_1
+    #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
+#endif
+
+/**
+ * @brief Initialize CCONT timer to generate the tick interrupt
+ *
+ */
+void vPortSetupTimer(void)
+{
+    /* Init the tick divisor value */
+    _xt_tick_divisor_init();
+
+    _frxt_tick_timer_init();
+}
+
+
+#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
+
+
+void SysTickIsrHandler(void *arg);
+
+#ifdef CONFIG_FREERTOS_UNICORE
+static uint32_t s_handled_systicks[1] = { 0 };
+#else
+static uint32_t s_handled_systicks[2] = { 0 };
+#endif
+
+#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE)
+
+/**
+ * @brief Set up the systimer peripheral to generate the tick interrupt
+ *
+ * Both timer alarms are configured in periodic mode.
+ * It is done at the same time so SysTicks for both CPUs occur at the same time or very close.
+ * Shifts a time of triggering interrupts for core 0 and core 1.
+ */
+void vPortSetupTimer(void)
+{
+    unsigned cpuid = xPortGetCoreID();
+#ifdef CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3
+    const unsigned level = ESP_INTR_FLAG_LEVEL3;
+#else
+    const unsigned level = ESP_INTR_FLAG_LEVEL1;
+#endif
+#ifdef CONFIG_FREERTOS_UNICORE
+    const unsigned max_cpu = 1;
+#else
+    const unsigned max_cpu = 2;
+#endif
+    /* Systimer HAL layer object */
+    static systimer_hal_context_t systimer_hal;
+    /* set system timer interrupt vector */
+    ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL));
+
+    if (cpuid == 0) {
+        systimer_hal_init(&systimer_hal);
+        systimer_ll_set_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK, 0);
+        systimer_ll_apply_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK);
+
+        for (cpuid = 0; cpuid < max_cpu; ++cpuid) {
+            uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
+
+            /* configure the timer */
+            systimer_hal_connect_alarm_counter(&systimer_hal, alarm_id, SYSTIMER_LL_COUNTER_OS_TICK);
+            systimer_hal_set_alarm_period(&systimer_hal, alarm_id, 1000000UL / CONFIG_FREERTOS_HZ);
+            systimer_hal_select_alarm_mode(&systimer_hal, alarm_id, SYSTIMER_ALARM_MODE_PERIOD);
+            systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, true);
+            if (cpuid == 0) {
+                systimer_hal_enable_alarm_int(&systimer_hal, alarm_id);
+                systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK);
+                // SysTick of core 0 and core 1 are shifted by half of period
+                systimer_hal_counter_value_advance(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, 1000000UL / CONFIG_FREERTOS_HZ / 2);
+            }
+        }
+    } else {
+        uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
+        systimer_hal_enable_alarm_int(&systimer_hal, alarm_id);
+    }
+}
+
+/**
+ * @brief Systimer interrupt handler.
+ *
+ * The Systimer interrupt for SysTick works in periodic mode no need to calc the next alarm.
+ * If a timer interrupt is ever serviced more than one tick late, it is necessary to process multiple ticks.
+ */
+IRAM_ATTR void SysTickIsrHandler(void *arg)
+{
+    uint32_t cpuid = xPortGetCoreID();
+    systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg;
+#ifdef CONFIG_PM_TRACE
+    ESP_PM_TRACE_ENTER(TICK, cpuid);
+#endif
+
+    uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
+    do {
+        systimer_ll_clear_alarm_int(systimer_hal->dev, alarm_id);
+
+        uint32_t diff = systimer_hal_get_counter_value(systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK) / systimer_ll_get_alarm_period(systimer_hal->dev, alarm_id) - s_handled_systicks[cpuid];
+        if (diff > 0) {
+            if (s_handled_systicks[cpuid] == 0) {
+                s_handled_systicks[cpuid] = diff;
+                diff = 1;
+            } else {
+                s_handled_systicks[cpuid] += diff;
+            }
+
+            do {
+                xPortSysTickHandler();
+            } while (--diff);
+        }
+    } while (systimer_ll_is_alarm_int_fired(systimer_hal->dev, alarm_id));
+
+#ifdef CONFIG_PM_TRACE
+    ESP_PM_TRACE_EXIT(TICK, cpuid);
+#endif
+}
+
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
+
+/**
+ * @brief Handler of SysTick
+ *
+ * The function is called from:
+ *  - _frxt_timer_int for xtensa with CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
+ *  - SysTickIsrHandler for xtensa with CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
+ *  - SysTickIsrHandler for riscv
+ */
+BaseType_t xPortSysTickHandler(void)
+{
+    portbenchmarkIntLatency();
+    traceISR_ENTER(SYSTICK_INTR_ID);
+    BaseType_t ret = xTaskIncrementTick();
+    if(ret != pdFALSE) {
+        portYIELD_FROM_ISR();
+    } else {
+        traceISR_EXIT();
+    }
+    return ret;
+}

+ 20 - 0
components/freertos/port/priv_include/port_systick.h

@@ -0,0 +1,20 @@
+/*
+ * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Set up the SysTick interrupt
+ */
+void vPortSetupTimer(void);
+
+#ifdef __cplusplus
+}
+#endif

+ 2 - 46
components/freertos/port/riscv/port.c

@@ -91,6 +91,7 @@
 #include "riscv/riscv_interrupts.h"
 #include "riscv/interrupt.h"
 
+#include "port_systick.h"
 #include "esp_system.h"
 #include "esp_intr_alloc.h"
 #include "esp_private/crosscore_int.h"
@@ -115,8 +116,6 @@ StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOIN
 
 static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
 
-static void vPortSysTickHandler(void *arg);
-static void vPortSetupTimer(void);
 static void prvTaskExitError(void);
 
 extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only
@@ -141,27 +140,6 @@ void vPortExitCritical(void)
     }
 }
 
-/**
- * @brief Set up the systimer peripheral to generate the tick interrupt
- *
- */
-void vPortSetupTimer(void)
-{
-    /* Systimer HAL layer object */
-    static systimer_hal_context_t systimer_hal;
-    /* set system timer interrupt vector */
-    ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, vPortSysTickHandler, &systimer_hal, NULL));
-
-    /* configure the timer */
-    systimer_hal_init(&systimer_hal);
-    systimer_hal_connect_alarm_counter(&systimer_hal, SYSTIMER_LL_ALARM_OS_TICK_CORE0, SYSTIMER_LL_COUNTER_OS_TICK);
-    systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK);
-    systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, 0, true);
-    systimer_hal_set_alarm_period(&systimer_hal, SYSTIMER_LL_ALARM_OS_TICK_CORE0, 1000000UL / CONFIG_FREERTOS_HZ);
-    systimer_hal_select_alarm_mode(&systimer_hal, SYSTIMER_LL_ALARM_OS_TICK_CORE0, SYSTIMER_ALARM_MODE_PERIOD);
-    systimer_hal_enable_alarm_int(&systimer_hal, SYSTIMER_LL_ALARM_OS_TICK_CORE0);
-}
-
 void prvTaskExitError(void)
 {
     /* A function that implements a task must not exit or attempt to return to
@@ -293,35 +271,13 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC
     return (StackType_t *)frame;
 }
 
-IRAM_ATTR void vPortSysTickHandler(void *arg)
-{
-    systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg;
-
-    systimer_ll_clear_alarm_int(systimer_hal->dev, SYSTIMER_LL_ALARM_OS_TICK_CORE0);
-
-#ifdef CONFIG_PM_TRACE
-    ESP_PM_TRACE_ENTER(TICK, xPortGetCoreID());
-#endif
-
-    if (!uxSchedulerRunning) {
-        return;
-    }
-
-    if (xTaskIncrementTick() != pdFALSE) {
-        vPortYieldFromISR();
-    }
-
-#ifdef CONFIG_PM_TRACE
-    ESP_PM_TRACE_EXIT(TICK, xPortGetCoreID());
-#endif
-}
-
 BaseType_t xPortStartScheduler(void)
 {
     uxInterruptNesting = 0;
     uxCriticalNesting = 0;
     uxSchedulerRunning = 0;
 
+	/* Setup the hardware to generate the tick. */
     vPortSetupTimer();
 
     esprv_intc_int_set_threshold(1); /* set global INTC masking level */

+ 3 - 0
components/freertos/port/xtensa/include/freertos/xtensa_rtos.h

@@ -50,6 +50,7 @@ Should be included by all Xtensa generic and RTOS port-specific sources.
 
 #include    <xtensa/corebits.h>
 #include    <xtensa/config/system.h>
+#include    "sdkconfig.h"
 
 /*
 Include any RTOS specific definitions that are needed by this header.
@@ -145,7 +146,9 @@ May be coded in or called from C or assembly, per ABI conventions.
 RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro).
 */
 // void XT_RTOS_TIMER_INT(void)
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 #define XT_RTOS_TIMER_INT   _frxt_timer_int
+#endif
 #define XT_TICK_PER_SEC     configTICK_RATE_HZ
 
 /*

+ 2 - 31
components/freertos/port/xtensa/port.c

@@ -130,25 +130,16 @@
 #include "esp32s3/spiram.h"
 #endif
 
+#include "port_systick.h"
 #include "esp_private/startup_internal.h" // [refactor-todo] for g_spiram_ok
 #include "esp_app_trace.h" // [refactor-todo] for esp_app_trace_init
 
-/* Defined in portasm.h */
-extern void _frxt_tick_timer_init(void);
-
 /* Defined in xtensa_context.S */
 extern void _xt_coproc_init(void);
 
 static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
 								// for now maintain the same log output
 
-#if CONFIG_FREERTOS_CORETIMER_0
-    #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
-#endif
-#if CONFIG_FREERTOS_CORETIMER_1
-    #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
-#endif
-
 _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value");
 
 /*-----------------------------------------------------------*/
@@ -303,11 +294,8 @@ BaseType_t xPortStartScheduler( void )
 	_xt_coproc_init();
 	#endif
 
-	/* Init the tick divisor value */
-	_xt_tick_divisor_init();
-
 	/* Setup the hardware to generate the tick. */
-	_frxt_tick_timer_init();
+	vPortSetupTimer();
 
 	port_xSchedulerRunning[xPortGetCoreID()] = 1;
 
@@ -319,23 +307,6 @@ BaseType_t xPortStartScheduler( void )
 }
 /*-----------------------------------------------------------*/
 
-BaseType_t xPortSysTickHandler( void )
-{
-	BaseType_t ret;
-
-	portbenchmarkIntLatency();
-	traceISR_ENTER(SYSTICK_INTR_ID);
-	ret = xTaskIncrementTick();
-	if( ret != pdFALSE )
-	{
-		portYIELD_FROM_ISR();
-	} else {
-		traceISR_EXIT();
-	}
-	return ret;
-}
-
-
 void vPortYieldOtherCore( BaseType_t coreid ) {
 	esp_crosscore_int_send_yield( coreid );
 }

+ 5 - 1
components/freertos/port/xtensa/portasm.S

@@ -270,6 +270,7 @@ _frxt_int_exit:
 *
 **********************************************************************************************************
 */
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
     .globl  _frxt_timer_int
     .type   _frxt_timer_int,@function
     .align  4
@@ -321,7 +322,7 @@ _frxt_timer_int:
     s32i    a3, sp, 8
     #endif
 
-    /* Call the FreeRTOS tick handler (see port.c). */
+    /* Call the FreeRTOS tick handler (see port_systick.c). */
     #ifdef __XTENSA_CALL0_ABI__
     call0   xPortSysTickHandler
     #else
@@ -347,6 +348,7 @@ _frxt_timer_int:
 #endif // CONFIG_PM_TRACE
 
     RET(16)
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 
     /*
 **********************************************************************************************************
@@ -358,6 +360,7 @@ _frxt_timer_int:
 *
 **********************************************************************************************************
 */
+#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
     .globl  _frxt_tick_timer_init
     .type   _frxt_tick_timer_init,@function
     .align  4
@@ -391,6 +394,7 @@ _frxt_tick_timer_init:
     #endif
 
     RET(16)
+#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
 
 /*
 **********************************************************************************************************

+ 6 - 0
components/freertos/port/xtensa/xtensa_vectors.S

@@ -289,9 +289,13 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     rsil    a3, \level - 1                  /* lower interrupt level by 1 */
     #endif
 
+    #ifdef XT_RTOS_TIMER_INT
     movi    a3, XT_TIMER_INTEN              /* a3 = timer interrupt bit */
     wsr     a4, INTCLEAR                    /* clear sw or edge-triggered interrupt */
     beq     a3, a4, 7f                      /* if timer interrupt then skip table */
+    #else
+    wsr     a4, INTCLEAR                    /* clear sw or edge-triggered interrupt */
+    #endif // XT_RTOS_TIMER_INT
 
     find_ms_setbit a3, a4, a3, 0            /* a3 = interrupt number */
 
@@ -316,6 +320,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     j       .L_xt_user_int_&level&          /* check for more interrupts */
     #endif
 
+    #ifdef XT_RTOS_TIMER_INT
 7:
 
     .ifeq XT_TIMER_INTPRI - \level
@@ -335,6 +340,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     call4   XT_RTOS_TIMER_INT
     #endif
     .endif
+    #endif // XT_RTOS_TIMER_INT
 
     #ifdef XT_USE_SWPRI
     j       8f

+ 5 - 0
components/hal/esp32c3/include/hal/systimer_ll.h

@@ -124,6 +124,11 @@ __attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(s
     dev->target_conf[alarm_id].target_period = period;
 }
 
+__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
+{
+    return dev->target_conf[alarm_id].target_period;
+}
+
 __attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
 {
     dev->comp_load[alarm_id].val = 0x01;

+ 5 - 0
components/hal/esp32h2/include/hal/systimer_ll.h

@@ -124,6 +124,11 @@ __attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(s
     dev->target_conf[alarm_id].target_period = period;
 }
 
+__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
+{
+    return dev->target_conf[alarm_id].target_period;
+}
+
 __attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
 {
     dev->comp_load[alarm_id].val = 0x01;

+ 5 - 0
components/hal/esp32s2/include/hal/systimer_ll.h

@@ -135,6 +135,11 @@ __attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(s
     dev->target_conf[alarm_id].target_period = period;
 }
 
+__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
+{
+    return dev->target_conf[alarm_id].target_period;
+}
+
 __attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
 {
     (void)dev;

+ 5 - 0
components/hal/esp32s3/include/hal/systimer_ll.h

@@ -125,6 +125,11 @@ __attribute__((always_inline)) static inline void systimer_ll_set_alarm_period(s
     dev->target_conf[alarm_id].target_period = period;
 }
 
+__attribute__((always_inline)) static inline uint32_t systimer_ll_get_alarm_period(systimer_dev_t *dev, uint32_t alarm_id)
+{
+    return dev->target_conf[alarm_id].target_period;
+}
+
 __attribute__((always_inline)) static inline void systimer_ll_apply_alarm_value(systimer_dev_t *dev, uint32_t alarm_id)
 {
     dev->comp_load[alarm_id].val = 0x01;

+ 8 - 11
components/newlib/test/test_time.c

@@ -251,6 +251,7 @@ static void get_time_task(void *pvParameters)
     // although exit flag is set in another task, checking (exit_flag == false) is safe
     while (exit_flag == false) {
         gettimeofday(&tv_time, NULL);
+        vTaskDelay(1500 / portTICK_PERIOD_MS);
     }
     xSemaphoreGive(*sema);
     vTaskDelete(NULL);
@@ -259,13 +260,9 @@ static void get_time_task(void *pvParameters)
 static void start_measure(int64_t* sys_time, int64_t* real_time)
 {
     struct timeval tv_time;
-    int64_t t1, t2;
-    do {
-        t1 = esp_timer_get_time();
-        gettimeofday(&tv_time, NULL);
-        t2 = esp_timer_get_time();
-    } while (t2 - t1 > 40);
-    *real_time = t2;
+    // there shouldn't be much time between gettimeofday and esp_timer_get_time
+    gettimeofday(&tv_time, NULL);
+    *real_time = esp_timer_get_time();
     *sys_time = (int64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec;
 }
 
@@ -301,7 +298,7 @@ static void measure_time_task(void *pvParameters)
         int64_t sys_time_us[2] = { main_sys_time_us[0], 0};
         // although exit flag is set in another task, checking (exit_flag == false) is safe
         while (exit_flag == false) {
-            esp_rom_delay_us(2 * 1000000); // 2 sec
+            vTaskDelay(2000 / portTICK_PERIOD_MS);
 
             start_measure(&sys_time_us[1], &real_time_us[1]);
             result_adjtime_correction_us[1] += calc_correction("measure", sys_time_us, real_time_us);
@@ -322,7 +319,7 @@ static void measure_time_task(void *pvParameters)
     vTaskDelete(NULL);
 }
 
-TEST_CASE("test time adjustment happens linearly", "[newlib][timeout=35]")
+TEST_CASE("test time adjustment happens linearly", "[newlib][timeout=15]")
 {
     exit_flag = false;
 
@@ -335,8 +332,8 @@ TEST_CASE("test time adjustment happens linearly", "[newlib][timeout=35]")
     xTaskCreatePinnedToCore(get_time_task, "get_time_task", 4096, &exit_sema[0], UNITY_FREERTOS_PRIORITY - 1, NULL, 0);
     xTaskCreatePinnedToCore(measure_time_task, "measure_time_task", 4096, &exit_sema[1], UNITY_FREERTOS_PRIORITY - 1, NULL, 1);
 
-    printf("start waiting for 30 seconds\n");
-    vTaskDelay(30000 / portTICK_PERIOD_MS);
+    printf("start waiting for 10 seconds\n");
+    vTaskDelay(10000 / portTICK_PERIOD_MS);
 
     // set exit flag to let thread exit
     exit_flag = true;

+ 4 - 0
tools/unit-test-app/configs/pm_s3

@@ -0,0 +1,4 @@
+CONFIG_IDF_TARGET="esp32s3"
+TEST_COMPONENTS=esp_pm
+CONFIG_PM_ENABLE=y
+CONFIG_FREERTOS_USE_TICKLESS_IDLE=y