Select one of the symbols to view example projects that use it.
 
Outline
#include "sdkconfig.h"
#include <stdint.h>
#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "esp_private/freertos_idf_additions_priv.h"
#define SYSTICK_INTR_ID
#define SYSTICK_INTR_ID
#define SYSTICK_INTR_ID
#include "soc/periph_defs.h"
#include "hal/systimer_hal.h"
#include "hal/systimer_ll.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
#include "esp_private/systimer.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/pm_trace.h"
vPortSetupTimer()
xPortSysTickHandler()
Files
loading...
SourceVuESP-IDF Framework and ExamplesFreeRTOSport_systick.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* * SPDX-FileCopyrightText: 2017-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */ #include "sdkconfig.h" #include <stdint.h> #include <stdlib.h> #include "FreeRTOS.h" #include "task.h"5 includes #if ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) /* Required for xTaskIncrementTickOtherCores() */ #include "esp_private/freertos_idf_additions_priv.h"/* ... */ #endif /* ( !CONFIG_FREERTOS_SMP && ( configNUM_CORES > 1 ) ) */ #if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT #if CONFIG_FREERTOS_CORETIMER_0 #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE + ETS_INTERNAL_INTR_SOURCE_OFF) #else /* CONFIG_FREERTOS_CORETIMER_1 */ #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE + ETS_INTERNAL_INTR_SOURCE_OFF) #endif/* ... */ #else /* CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER */ #define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_INTR_SOURCE) #endif /* CONFIG_FREERTOS_SYSTICK_USES_CCOUNT */ BaseType_t xPortSysTickHandler(void); /* --------------------------------------------- SYSTIMER Implementation ----------------------------------------------- * Implementation of a tick interrupt using the SYSTIMER perpiheral * Todo: Abstract setup and operation in a separate SYSTIMER driver (IDF-6976) * ------------------------------------------------------------------------------------------------------------------ *//* ... */ #if CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER #include "soc/periph_defs.h" #include "hal/systimer_hal.h" #include "hal/systimer_ll.h" #include "esp_err.h" #include "esp_intr_alloc.h" #include "esp_private/systimer.h" #include "esp_private/periph_ctrl.h"7 includes #ifdef CONFIG_PM_TRACE #include "esp_private/pm_trace.h" #endif //CONFIG_PM_TRACE _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[configNUM_CORES] = { 0 }; /** * @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 vSystimerSetup(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_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL)); if (cpuid == 0) { PERIPH_RCC_ACQUIRE_ATOMIC(PERIPH_SYSTIMER_MODULE, ref_count) { if (ref_count == 0) { systimer_ll_enable_bus_clock(true); systimer_ll_reset_register(); }{...} }{...} systimer_hal_init(&systimer_hal); systimer_hal_tick_rate_ops_t ops = { .ticks_to_us = systimer_ticks_to_us, .us_to_ticks = systimer_us_to_ticks, }{...}; systimer_hal_set_tick_rate_ops(&systimer_hal, &ops); systimer_ll_set_counter_value(systimer_hal.dev, SYSTIMER_COUNTER_OS_TICK, 0); systimer_ll_apply_counter_value(systimer_hal.dev, SYSTIMER_COUNTER_OS_TICK); for (cpuid = 0; cpuid < SOC_CPU_CORES_NUM; cpuid++) { // Set stall option and alarm mode to default state. Below they will be set to a required state. systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_COUNTER_OS_TICK, cpuid, false); uint32_t alarm_id = SYSTIMER_ALARM_OS_TICK_CORE0 + cpuid; systimer_hal_select_alarm_mode(&systimer_hal, alarm_id, SYSTIMER_ALARM_MODE_ONESHOT); }{...} for (cpuid = 0; cpuid < configNUM_CORES; ++cpuid) { uint32_t alarm_id = SYSTIMER_ALARM_OS_TICK_CORE0 + cpuid; /* configure the timer */ systimer_hal_connect_alarm_counter(&systimer_hal, alarm_id, SYSTIMER_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_COUNTER_OS_TICK, cpuid, true); if (cpuid == 0) { systimer_hal_enable_alarm_int(&systimer_hal, alarm_id); systimer_hal_enable_counter(&systimer_hal, SYSTIMER_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_COUNTER_OS_TICK, 1000000UL / CONFIG_FREERTOS_HZ / 2);/* ... */ #endif }{...} }{...} }{...} else { uint32_t alarm_id = SYSTIMER_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. *//* ... */ 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_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_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_SYSTIMER */ /* ------------------------------------------------ Common Port Tick --------------------------------------------------- * Tick related functions common across all ports * ------------------------------------------------------------------------------------------------------------------ *//* ... */ /** * @brief Initialize the tick interrupt timer * * - CCOUNT timer is used if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT is set * - SYSTIMER is used if CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER is set *//* ... */ void vPortSetupTimer(void) { #if CONFIG_FREERTOS_SYSTICK_USES_CCOUNT extern void _frxt_tick_timer_init(void); extern void _xt_tick_divisor_init(void); /* Init the tick divisor value */ _xt_tick_divisor_init(); _frxt_tick_timer_init();/* ... */ #else /* CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER */ vSystimerSetup(); #endif /* CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER */ }{ ... } /** * @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) { #if configBENCHMARK portbenchmarkIntLatency(); #endif //configBENCHMARK traceISR_ENTER(SYSTICK_INTR_ID); // Call IDF Tick Hook extern void esp_vApplicationTickHook(void); esp_vApplicationTickHook(); // Call FreeRTOS Increment tick function BaseType_t xSwitchRequired; #if CONFIG_FREERTOS_SMP UBaseType_t uxSavedStatus = taskENTER_CRITICAL_FROM_ISR(); // Amazon SMP FreeRTOS requires that only core 0 calls xTaskIncrementTick() #if ( configNUM_CORES > 1 ) if (portGET_CORE_ID() == 0) { xSwitchRequired = xTaskIncrementTick(); }{...} else { xSwitchRequired = pdFALSE; }{...} #else/* ... */ /* configNUM_CORES > 1 */ xSwitchRequired = xTaskIncrementTick(); #endif /* configNUM_CORES > 1 */ taskEXIT_CRITICAL_FROM_ISR(uxSavedStatus);/* ... */ #else /* !CONFIG_FREERTOS_SMP */ #if ( configNUM_CORES > 1 ) /* Multi-core IDF FreeRTOS requires that... - core 0 calls xTaskIncrementTick() - core 1 calls xTaskIncrementTickOtherCores() *//* ... */ if (xPortGetCoreID() == 0) { xSwitchRequired = xTaskIncrementTick(); }{...} else { xSwitchRequired = xTaskIncrementTickOtherCores(); }{...} #else/* ... */ /* configNUM_CORES > 1 */ /* Vanilla (single core) FreeRTOS expects that xTaskIncrementTick() cannot be interrupted (i.e., no nested interrupts). Thus we have to disable interrupts before calling it. *//* ... */ UBaseType_t uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); xSwitchRequired = xTaskIncrementTick(); portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus);/* ... */ #endif /* configNUM_CORES > 1 *//* ... */ #endif /* !CONFIG_FREERTOS_SMP */ // Check if yield is required if (xSwitchRequired != pdFALSE) { portYIELD_FROM_ISR(); }{...} else { traceISR_EXIT(); }{...} return xSwitchRequired; }{ ... }
Details