diff --git a/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c b/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c index 965b74c5e2..268b389921 100644 --- a/components/app_trace/sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c +++ b/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 diff --git a/components/efuse/test/test_efuse.c b/components/efuse/test/test_efuse.c index 0cd39c0381..f94a0c58a4 100644 --- a/components/efuse/test/test_efuse.c +++ b/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); } diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index 6cc2c4b698..88e12b5875 100644 --- a/components/esp_pm/pm_impl.c +++ b/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); } diff --git a/components/esp_system/port/soc/esp32c3/system_internal.c b/components/esp_system/port/soc/esp32c3/system_internal.c index d915c769ae..77020b3a91 100644 --- a/components/esp_system/port/soc/esp32c3/system_internal.c +++ b/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); diff --git a/components/esp_system/port/soc/esp32h2/system_internal.c b/components/esp_system/port/soc/esp32h2/system_internal.c index e280343136..d3b451bd53 100644 --- a/components/esp_system/port/soc/esp32h2/system_internal.c +++ b/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); diff --git a/components/esp_system/port/soc/esp32s3/system_internal.c b/components/esp_system/port/soc/esp32s3/system_internal.c index 18dad4005a..551e90e724 100644 --- a/components/esp_system/port/soc/esp32s3/system_internal.c +++ b/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 diff --git a/components/esp_timer/src/esp_timer_impl_systimer.c b/components/esp_timer/src/esp_timer_impl_systimer.c index ead5d24cab..28bdb07212 100644 --- a/components/esp_timer/src/esp_timer_impl_systimer.c +++ b/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; diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index a91ad72674..0c64d68070 100644 --- a/components/freertos/CMakeLists.txt +++ b/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} diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index ffe2f4987e..3c8b0c1951 100644 --- a/components/freertos/Kconfig +++ b/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 diff --git a/components/freertos/component.mk b/components/freertos/component.mk index e72576cbcd..4225da69a9 100644 --- a/components/freertos/component.mk +++ b/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 diff --git a/components/freertos/port/port_systick.c b/components/freertos/port/port_systick.c new file mode 100644 index 0000000000..577305be3b --- /dev/null +++ b/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 +#include +#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; +} diff --git a/components/freertos/port/priv_include/port_systick.h b/components/freertos/port/priv_include/port_systick.h new file mode 100644 index 0000000000..a2418823bc --- /dev/null +++ b/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 diff --git a/components/freertos/port/riscv/port.c b/components/freertos/port/riscv/port.c index 2f9ada3f57..297fab1d2f 100644 --- a/components/freertos/port/riscv/port.c +++ b/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 */ diff --git a/components/freertos/port/xtensa/include/freertos/xtensa_rtos.h b/components/freertos/port/xtensa/include/freertos/xtensa_rtos.h index d1b4023799..b7793d6803 100644 --- a/components/freertos/port/xtensa/include/freertos/xtensa_rtos.h +++ b/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 #include +#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 /* diff --git a/components/freertos/port/xtensa/port.c b/components/freertos/port/xtensa/port.c index 3763f716ae..43ed1cfa4d 100644 --- a/components/freertos/port/xtensa/port.c +++ b/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 ); } diff --git a/components/freertos/port/xtensa/portasm.S b/components/freertos/port/xtensa/portasm.S index 86f452e12f..188454c164 100644 --- a/components/freertos/port/xtensa/portasm.S +++ b/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 /* ********************************************************************************************************** diff --git a/components/freertos/port/xtensa/xtensa_vectors.S b/components/freertos/port/xtensa/xtensa_vectors.S index 4fd27e45c0..fc239c72f5 100644 --- a/components/freertos/port/xtensa/xtensa_vectors.S +++ b/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 diff --git a/components/hal/esp32c3/include/hal/systimer_ll.h b/components/hal/esp32c3/include/hal/systimer_ll.h index 769f68703f..3628978f68 100644 --- a/components/hal/esp32c3/include/hal/systimer_ll.h +++ b/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; diff --git a/components/hal/esp32h2/include/hal/systimer_ll.h b/components/hal/esp32h2/include/hal/systimer_ll.h index 769f68703f..3628978f68 100644 --- a/components/hal/esp32h2/include/hal/systimer_ll.h +++ b/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; diff --git a/components/hal/esp32s2/include/hal/systimer_ll.h b/components/hal/esp32s2/include/hal/systimer_ll.h index f1c0ef0adf..6066674243 100644 --- a/components/hal/esp32s2/include/hal/systimer_ll.h +++ b/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; diff --git a/components/hal/esp32s3/include/hal/systimer_ll.h b/components/hal/esp32s3/include/hal/systimer_ll.h index 0c8dde75e2..7f171e92e3 100644 --- a/components/hal/esp32s3/include/hal/systimer_ll.h +++ b/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; diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c index 1f164d5b04..c97a08d723 100644 --- a/components/newlib/test/test_time.c +++ b/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; diff --git a/tools/unit-test-app/configs/pm_s3 b/tools/unit-test-app/configs/pm_s3 new file mode 100644 index 0000000000..f5ad9bedaf --- /dev/null +++ b/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