|
|
@@ -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;
|
|
|
+}
|