From 7726f343e8e124e0ad5cf320f1a8885c93348e0a Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 17 Jun 2022 09:11:02 +0200 Subject: [PATCH 1/3] freertos-smp: Update prvYieldCore() to fix compile warning prvYieldCore() leads to an array-out-of-bounds error when compiled with -Os optimization and configNUM_CORES = 1. This commit avoids this compile warning by compiling out the part of code which is unnecessary when configNUM_CORES is 1. --- components/freertos/FreeRTOS-Kernel-SMP/tasks.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c index 04984ece01..b76a6e1678 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/tasks.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/tasks.c @@ -709,11 +709,17 @@ static void prvYieldCore( BaseType_t xCoreID ) { xYieldPendings[ xCoreID ] = pdTRUE; } - else - { - portYIELD_CORE( xCoreID ); - pxCurrentTCBs[ xCoreID ]->xTaskRunState = taskTASK_YIELDING; - } + +#ifdef ESP_PLATFORM +// TODO: IDF-5256 + #if ( configNUM_CORES > 1 ) + else + { + portYIELD_CORE( xCoreID ); + pxCurrentTCBs[ xCoreID ]->xTaskRunState = taskTASK_YIELDING; + } + #endif /* ( configNUM_CORES > 1 ) */ +#endif /* ESP_PLATFORM */ } } From 55f1eca2484b335acda23f03f6e30e9acb4aa064 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 17 Jun 2022 09:18:46 +0200 Subject: [PATCH 2/3] freertos-smp: Fix build test errors for esp32c3 This commit fixes build test failures for esp32c3. --- .../include/freertos/FreeRTOSConfig_smp.h | 9 ------ .../riscv/include/freertos/portmacro.h | 32 ++++++++++++------- .../FreeRTOS-Kernel-SMP/portable/riscv/port.c | 7 ++-- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h index 35f7a61e9e..03c2e76d48 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h @@ -259,15 +259,6 @@ Default values for trace macros added by ESP-IDF and are not part of Vanilla Fre #define configTASKLIST_INCLUDE_COREID 1 #endif -#ifndef __ASSEMBLER__ -#if CONFIG_APPTRACE_SV_ENABLE -extern uint32_t port_switch_flag[]; -#define os_task_switch_is_pended(_cpu_) (port_switch_flag[_cpu_]) -#else -#define os_task_switch_is_pended(_cpu_) (false) -#endif -#endif - // ---------------------- Features ------------------------- /* These currently aren't required, but could be useful additions in the future */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h index 3fc6c99c52..5ef1066124 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h @@ -238,6 +238,9 @@ static inline BaseType_t xPortInIsrContext(void) return xPortCheckIfInISR(); } +// Added for backward compatibility with IDF +#define xPortInterruptedFromISRContext() xPortInIsrContext() + // ---------------------- Spinlocks ------------------------ /** @@ -279,21 +282,25 @@ static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t comp /* IDF style critical sections which are orthogonal to FreeRTOS critical sections. However, on single core, the IDF style critical sections simply disable interrupts, thus we discard the lock and timeout arguments. + +Note: The IDF Style critical sections are named differently to their counterparts present in the xtensa port as few IDF +examples such as esp_zigbee_gateway, when compiled for RISC-V targets, have a reference to vPortEnterCritical() +and vPortExitCritical() from precompiled libraries (.a) thereby failing linking. */ -void vPortEnterCriticalIDF(void); -void vPortExitCriticalIDF(void); +void vPortEnterCritical(void); +void vPortExitCritical(void); //IDF task critical sections -#define portTRY_ENTER_CRITICAL(lock, timeout) {((void) lock; (void) timeout; vPortEnterCriticalIDF(); pdPASS;)} -#define portENTER_CRITICAL_IDF(lock) ({(void) lock; vPortEnterCriticalIDF();}) -#define portEXIT_CRITICAL_IDF(lock) ({(void) lock; vPortExitCriticalIDF();}) +#define portTRY_ENTER_CRITICAL(lock, timeout) {((void) lock; (void) timeout; vPortEnterCritical(); pdPASS;)} +#define portENTER_CRITICAL_IDF(lock) ({(void) lock; vPortEnterCritical();}) +#define portEXIT_CRITICAL_IDF(lock) ({(void) lock; vPortExitCritical();}) //IDF ISR critical sections -#define portTRY_ENTER_CRITICAL_ISR(lock, timeout) {((void) lock; (void) timeout; vPortEnterCriticalIDF(); pdPASS;)} -#define portENTER_CRITICAL_ISR(lock) ({(void) lock; vPortEnterCriticalIDF();}) -#define portEXIT_CRITICAL_ISR(lock) ({(void) lock; vPortExitCriticalIDF();}) +#define portTRY_ENTER_CRITICAL_ISR(lock, timeout) {((void) lock; (void) timeout; vPortEnterCritical(); pdPASS;)} +#define portENTER_CRITICAL_ISR(lock) ({(void) lock; vPortEnterCritical();}) +#define portEXIT_CRITICAL_ISR(lock) ({(void) lock; vPortExitCritical();}) //IDF safe critical sections (they're the same) -#define portENTER_CRITICAL_SAFE(lock) ({(void) lock; vPortEnterCriticalIDF();}) -#define portEXIT_CRITICAL_SAFE(lock) ({(void) lock; vPortExitCriticalIDF();}) +#define portENTER_CRITICAL_SAFE(lock) ({(void) lock; vPortEnterCritical();}) +#define portEXIT_CRITICAL_SAFE(lock) ({(void) lock; vPortExitCritical();}) // ---------------------- Yielding ------------------------- @@ -307,6 +314,9 @@ static inline bool IRAM_ATTR xPortCanYield(void) return (threshold <= 1); } +// Added for backward compatibility with IDF +#define portYIELD_WITHIN_API() vTaskYieldWithinAPI() + // ----------------------- System -------------------------- void vPortSetStackWatchpoint(void *pxStackStart); @@ -329,7 +339,7 @@ void vPortSetStackWatchpoint(void *pxStackStart); // --------------------- App-Trace ------------------------- #if CONFIG_APPTRACE_SV_ENABLE -extern int xPortSwitchFlag; +extern volatile BaseType_t xPortSwitchFlag; #define os_task_switch_is_pended(_cpu_) (xPortSwitchFlag) #else #define os_task_switch_is_pended(_cpu_) (false) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index 2902e39c16..118b940cf5 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -38,6 +38,9 @@ #include "esp_private/pm_trace.h" #endif //CONFIG_PM_TRACE +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME +#include "esp_gdbstub.h" +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME /* ---------------------------------------------------- Variables ------------------------------------------------------ * @@ -63,7 +66,7 @@ static UBaseType_t port_uxCriticalOldInterruptStateIDF = 0; // ------------------ Critical Sections -------------------- -void vPortEnterCriticalIDF(void) +void vPortEnterCritical(void) { // Save current interrupt threshold and disable interrupts UBaseType_t old_thresh = ulPortSetInterruptMask(); @@ -75,7 +78,7 @@ void vPortEnterCriticalIDF(void) } } -void vPortExitCriticalIDF(void) +void vPortExitCritical(void) { if (port_uxCriticalNestingIDF > 0) { port_uxCriticalNestingIDF--; From c5d6f973319080fdd009cd4b878b09b991d65ea7 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty Date: Fri, 17 Jun 2022 09:21:46 +0200 Subject: [PATCH 3/3] freertos-smp: Fix build test errors for esp32s2 and esp32s3 This commit fixes build test errors for esp32s2 and esp32s3 with FreeRTOS SMP enabled. --- .../xtensa/include/freertos/portmacro.h | 3 + .../portable/xtensa/port.c | 112 ++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h index 85523a93c0..87d87c99b3 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h @@ -356,6 +356,9 @@ static inline bool IRAM_ATTR xPortCanYield(void) return ((ps_reg & PS_INTLEVEL_MASK) == 0); } +// Added for backward compatibility with IDF +#define portYIELD_WITHIN_API() vTaskYieldWithinAPI() + // ----------------------- System -------------------------- void vPortSetStackWatchpoint(void *pxStackStart); diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index 5a5d338911..08a1cc6d2c 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -27,6 +27,7 @@ #include "esp_task_wdt.h" #include "esp_heap_caps_init.h" #include "esp_freertos_hooks.h" +#include "esp_intr_alloc.h" #if CONFIG_SPIRAM /* Required by esp_psram_extram_reserve_dma_pool() */ #include "esp_psram.h" @@ -38,6 +39,12 @@ #ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME #include "esp_gdbstub.h" /* Required by esp_gdbstub_init() */ #endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME +#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 // CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER /* OS state variables @@ -148,6 +155,9 @@ void vPortSetStackWatchpoint( void *pxStackStart ) // ---------------------- Tick Timer ----------------------- +BaseType_t xPortSysTickHandler(void); + +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT extern void _frxt_tick_timer_init(void); extern void _xt_tick_divisor_init(void); @@ -163,6 +173,108 @@ void vPortSetupTimer(void) _frxt_tick_timer_init(); } +#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER + +_Static_assert(SOC_CPU_CORES_NUM <= SOC_SYSTIMER_ALARM_NUM - 1, "the number of cores must match the number of core alarms in SYSTIMER"); + +void SysTickIsrHandler(void *arg); + +static uint32_t s_handled_systicks[portNUM_PROCESSORS] = { 0 }; + +#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 + /* 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 < SOC_CPU_CORES_NUM; cpuid++) { + systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, false); + } + + for (cpuid = 0; cpuid < portNUM_PROCESSORS; ++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); +#ifndef CONFIG_FREERTOS_UNICORE + // 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); +#endif + } + } + } 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 + // --------------------- App Start-up ---------------------- static const char *TAG = "cpu_start";