Skip to content

Commit e964cc3

Browse files
committed
Merge branch 'refactor/gptimer_isr_logs_opt_int' into 'master'
feat(gptimer): make start and stop function idempotent, also refactored the doc structure Closes IDFGH-11157, IDFGH-12474, IDF-12513, and IDFCI-2734 See merge request espressif/esp-idf!36983
2 parents 837311c + 5f70a52 commit e964cc3

File tree

20 files changed

+658
-552
lines changed

20 files changed

+658
-552
lines changed

components/esp_adc/test_apps/adc/main/test_adc_driver_iram.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extern void spi_flash_enable_interrupts_caches_and_other_cpu(void);
4343
__attribute__((unused))
4444
static void s_test_cache_disable_period_us(test_adc_iram_ctx_t *ctx, uint32_t period_us);
4545

46-
#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE
46+
#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_CACHE_SAFE
4747
/*---------------------------------------------------------------
4848
ADC oneshot work with cache safe ISR
4949
---------------------------------------------------------------*/
@@ -140,7 +140,7 @@ TEST_CASE("ADC oneshot fast work with ISR and Flash", "[adc_oneshot]")
140140
TEST_ESP_OK(gptimer_del_timer(timer));
141141
TEST_ESP_OK(adc_oneshot_del_unit(oneshot_handle));
142142
}
143-
#endif //#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_IRAM_SAFE
143+
#endif //#if CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM && CONFIG_GPTIMER_ISR_CACHE_SAFE
144144

145145
#if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE || CONFIG_GDMA_ISR_IRAM_SAFE
146146
#include "esp_adc/adc_continuous.h"

components/esp_adc/test_apps/adc/sdkconfig.ci.esp32c2_xtal26m_iram_safe

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ CONFIG_XTAL_FREQ_26=y
33

44
CONFIG_COMPILER_DUMP_RTL_FILES=y
55
CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y
6-
CONFIG_GPTIMER_ISR_IRAM_SAFE=y
6+
CONFIG_GPTIMER_ISR_CACHE_SAFE=y
77
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
88
CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y
99
CONFIG_COMPILER_OPTIMIZATION_SIZE=y

components/esp_adc/test_apps/adc/sdkconfig.ci.iram_safe

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CONFIG_COMPILER_DUMP_RTL_FILES=y
22
CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y
3-
CONFIG_GPTIMER_ISR_IRAM_SAFE=y
3+
CONFIG_GPTIMER_ISR_CACHE_SAFE=y
44
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
55
CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y
66
CONFIG_COMPILER_OPTIMIZATION_SIZE=y

components/esp_adc/test_apps/adc/sdkconfig.ci.pm_enable

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CONFIG_COMPILER_DUMP_RTL_FILES=y
22
CONFIG_ADC_ONESHOT_CTRL_FUNC_IN_IRAM=y
3-
CONFIG_GPTIMER_ISR_IRAM_SAFE=y
3+
CONFIG_GPTIMER_ISR_CACHE_SAFE=y
44
CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y
55
CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE=y
66
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,45 @@
11
menu "ESP-Driver:GPTimer Configurations"
22
depends on SOC_GPTIMER_SUPPORTED
3+
34
config GPTIMER_ISR_HANDLER_IN_IRAM
4-
bool "Place GPTimer ISR handler into IRAM"
5+
bool "Place GPTimer ISR handler in IRAM to reduce latency"
56
default y
7+
select GPTIMER_OBJ_CACHE_SAFE
68
help
7-
Place GPTimer ISR handler into IRAM for better performance and fewer cache misses.
9+
Place GPTimer ISR handler in IRAM to reduce latency caused by cache miss.
810

911
config GPTIMER_CTRL_FUNC_IN_IRAM
10-
bool "Place GPTimer control functions into IRAM"
12+
bool "Place GPTimer control functions in IRAM"
1113
default n
14+
select GPTIMER_OBJ_CACHE_SAFE
1215
help
13-
Place GPTimer control functions (like start/stop) into IRAM,
14-
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
15-
Enabling this option can improve driver performance as well.
16+
Place GPTimer control functions (like start/stop) in IRAM, to reduce latency caused by cache miss.
17+
If enabled, these functions can also be called when cache is disabled.
1618

17-
config GPTIMER_ISR_IRAM_SAFE
18-
bool "GPTimer ISR IRAM-Safe"
19+
config GPTIMER_ISR_CACHE_SAFE
20+
bool "Allow GPTimer ISR to execute when cache is disabled"
1921
select GPTIMER_ISR_HANDLER_IN_IRAM
2022
default n
2123
help
22-
Ensure the GPTimer interrupt is IRAM-Safe by allowing the interrupt handler to be
23-
executable when the cache is disabled (e.g. SPI Flash write).
24+
Enable this option to allow the GPTimer Interrupt Service Routine (ISR)
25+
to execute even when the cache is disabled. This can be useful in scenarios where the cache
26+
might be turned off, but the GPTimer functionality is still required to operate correctly.
27+
28+
config GPTIMER_OBJ_CACHE_SAFE
29+
bool
30+
default n
31+
help
32+
This will ensure the GPTimer object will not be allocated from a memory region
33+
where its cache can be disabled.
2434

2535
config GPTIMER_ENABLE_DEBUG_LOG
26-
bool "Enable debug log"
36+
bool "Force enable debug log"
2737
default n
2838
help
29-
whether to enable the debug log message for GPTimer driver.
30-
Note that, this option only controls the GPTimer driver log, won't affect other drivers.
39+
If enabled, GPTimer component will:
40+
1. ignore the global logging settings
41+
2. compile all log messages into the binary
42+
3. set the runtime log level to VERBOSE
43+
Please enable this option by caution, as it will increase the binary size.
44+
3145
endmenu

components/esp_driver_gptimer/include/driver/gptimer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value);
135135
/**
136136
* @brief Group of supported GPTimer callbacks
137137
* @note The callbacks are all running under ISR environment
138-
* @note When CONFIG_GPTIMER_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
138+
* @note When CONFIG_GPTIMER_ISR_CACHE_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
139139
*/
140140
typedef struct {
141141
gptimer_alarm_cb_t on_alarm; /*!< Timer alarm callback */
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# sdkconfig replacement configurations for deprecated options formatted as
2+
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
3+
4+
CONFIG_GPTIMER_ISR_IRAM_SAFE CONFIG_GPTIMER_ISR_CACHE_SAFE

components/esp_driver_gptimer/src/gptimer.c

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

77
#include <stdlib.h>
88
#include <sys/lock.h>
9-
#include "sdkconfig.h"
10-
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
11-
// The local log level must be defined before including esp_log.h
12-
// Set the maximum log level for this source file
13-
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
14-
#endif
15-
#include "freertos/FreeRTOS.h"
16-
#include "esp_attr.h"
17-
#include "esp_err.h"
18-
#include "esp_log.h"
19-
#include "esp_check.h"
209
#include "driver/gptimer.h"
21-
#include "esp_memory_utils.h"
2210
#include "gptimer_priv.h"
23-
24-
static const char *TAG = "gptimer";
11+
#include "esp_memory_utils.h"
2512

2613
static void gptimer_default_isr(void *args);
2714

@@ -136,9 +123,6 @@ static esp_err_t gptimer_destroy(gptimer_t *timer)
136123

137124
esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *ret_timer)
138125
{
139-
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
140-
esp_log_level_set(TAG, ESP_LOG_DEBUG);
141-
#endif
142126
esp_err_t ret = ESP_OK;
143127
gptimer_t *timer = NULL;
144128
ESP_RETURN_ON_FALSE(config && ret_timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
@@ -188,7 +172,7 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
188172
timer->direction = config->direction;
189173
timer->intr_priority = config->intr_priority;
190174
timer->flags.intr_shared = config->flags.intr_shared;
191-
ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, resolution=%"PRIu32"Hz", group_id, timer_id, timer, timer->resolution_hz);
175+
ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, %zu bytes used", group_id, timer_id, timer, heap_caps_get_allocated_size(timer));
192176
*ret_timer = timer;
193177
return ESP_OK;
194178

@@ -231,7 +215,9 @@ esp_err_t gptimer_del_timer(gptimer_handle_t timer)
231215

232216
esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value)
233217
{
234-
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
218+
if (timer == NULL) {
219+
return ESP_ERR_INVALID_ARG;
220+
}
235221

236222
portENTER_CRITICAL_SAFE(&timer->spinlock);
237223
timer_hal_set_counter_value(&timer->hal, value);
@@ -241,7 +227,9 @@ esp_err_t gptimer_set_raw_count(gptimer_handle_t timer, unsigned long long value
241227

242228
esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, unsigned long long *value)
243229
{
244-
ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
230+
if (timer == NULL || value == NULL) {
231+
return ESP_ERR_INVALID_ARG;
232+
}
245233

246234
portENTER_CRITICAL_SAFE(&timer->spinlock);
247235
*value = timer_hal_capture_and_get_counter_value(&timer->hal);
@@ -258,7 +246,9 @@ esp_err_t gptimer_get_resolution(gptimer_handle_t timer, uint32_t *out_resolutio
258246

259247
esp_err_t gptimer_get_captured_count(gptimer_handle_t timer, uint64_t *value)
260248
{
261-
ESP_RETURN_ON_FALSE_ISR(timer && value, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
249+
if (timer == NULL || value == NULL) {
250+
return ESP_ERR_INVALID_ARG;
251+
}
262252

263253
portENTER_CRITICAL_SAFE(&timer->spinlock);
264254
*value = timer_ll_get_counter_value(timer->hal.dev, timer->timer_id);
@@ -274,7 +264,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
274264
int group_id = group->group_id;
275265
int timer_id = timer->timer_id;
276266

277-
#if CONFIG_GPTIMER_ISR_IRAM_SAFE
267+
#if CONFIG_GPTIMER_ISR_CACHE_SAFE
278268
if (cbs->on_alarm) {
279269
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_alarm), ESP_ERR_INVALID_ARG, TAG, "on_alarm callback not in IRAM");
280270
}
@@ -308,14 +298,22 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
308298

309299
esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config)
310300
{
311-
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
301+
if (timer == NULL) {
302+
return ESP_ERR_INVALID_ARG;
303+
}
312304
if (config) {
313305
#if CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM
314-
ESP_RETURN_ON_FALSE_ISR(esp_ptr_internal(config), ESP_ERR_INVALID_ARG, TAG, "alarm config struct not in internal RAM");
306+
// when the function is placed in IRAM, we expect the config struct is also placed in internal RAM
307+
// if the cache is disabled, the function can still access the config struct
308+
if (esp_ptr_internal(config) == false) {
309+
return ESP_ERR_INVALID_ARG;
310+
}
315311
#endif
316312
// When auto_reload is enabled, alarm_count should not be equal to reload_count
317313
bool valid_auto_reload = !config->flags.auto_reload_on_alarm || config->alarm_count != config->reload_count;
318-
ESP_RETURN_ON_FALSE_ISR(valid_auto_reload, ESP_ERR_INVALID_ARG, TAG, "reload count can't equal to alarm count");
314+
if (valid_auto_reload == false) {
315+
return ESP_ERR_INVALID_ARG;
316+
}
319317

320318
portENTER_CRITICAL_SAFE(&timer->spinlock);
321319
timer->reload_count = config->reload_count;
@@ -343,6 +341,7 @@ esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_c
343341
esp_err_t gptimer_enable(gptimer_handle_t timer)
344342
{
345343
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
344+
// the only acceptable FSM change: init->enable
346345
gptimer_fsm_t expected_fsm = GPTIMER_FSM_INIT;
347346
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE),
348347
ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
@@ -363,6 +362,7 @@ esp_err_t gptimer_enable(gptimer_handle_t timer)
363362
esp_err_t gptimer_disable(gptimer_handle_t timer)
364363
{
365364
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
365+
// the only acceptable FSM change: enable->init
366366
gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE;
367367
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_INIT),
368368
ESP_ERR_INVALID_STATE, TAG, "timer not in enable state");
@@ -382,7 +382,14 @@ esp_err_t gptimer_disable(gptimer_handle_t timer)
382382

383383
esp_err_t gptimer_start(gptimer_handle_t timer)
384384
{
385-
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
385+
if (timer == NULL) {
386+
return ESP_ERR_INVALID_ARG;
387+
}
388+
389+
// if the timer is already started, do nothing
390+
if (atomic_load(&timer->fsm) == GPTIMER_FSM_RUN) {
391+
return ESP_OK;
392+
}
386393

387394
gptimer_fsm_t expected_fsm = GPTIMER_FSM_ENABLE;
388395
if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_RUN_WAIT)) {
@@ -396,15 +403,24 @@ esp_err_t gptimer_start(gptimer_handle_t timer)
396403
atomic_store(&timer->fsm, GPTIMER_FSM_RUN);
397404
portEXIT_CRITICAL_SAFE(&timer->spinlock);
398405
} else {
399-
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "timer is not ready for a new start");
406+
// return error if the timer is not in the expected state
407+
return ESP_ERR_INVALID_STATE;
400408
}
401409

402410
return ESP_OK;
403411
}
404412

405413
esp_err_t gptimer_stop(gptimer_handle_t timer)
406414
{
407-
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
415+
if (timer == NULL) {
416+
// not printing error message here because the return value already indicates the error well
417+
return ESP_ERR_INVALID_ARG;
418+
}
419+
420+
// if the timer is not started, do nothing
421+
if (atomic_load(&timer->fsm) == GPTIMER_FSM_ENABLE) {
422+
return ESP_OK;
423+
}
408424

409425
gptimer_fsm_t expected_fsm = GPTIMER_FSM_RUN;
410426
if (atomic_compare_exchange_strong(&timer->fsm, &expected_fsm, GPTIMER_FSM_ENABLE_WAIT)) {
@@ -415,7 +431,8 @@ esp_err_t gptimer_stop(gptimer_handle_t timer)
415431
atomic_store(&timer->fsm, GPTIMER_FSM_ENABLE);
416432
portEXIT_CRITICAL_SAFE(&timer->spinlock);
417433
} else {
418-
ESP_RETURN_ON_FALSE_ISR(false, ESP_ERR_INVALID_STATE, TAG, "timer is not running");
434+
// return error if the timer is not in the expected state
435+
return ESP_ERR_INVALID_STATE;
419436
}
420437

421438
return ESP_OK;

components/esp_driver_gptimer/src/gptimer_common.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

77
#include <sys/lock.h>
8-
#include "esp_check.h"
98
#include "esp_clk_tree.h"
10-
#include "esp_private/esp_clk_tree_common.h"
119
#include "esp_private/gptimer.h"
1210
#include "gptimer_priv.h"
13-
#include "soc/soc_caps.h"
14-
15-
static const char *TAG = "gptimer";
11+
#include "esp_private/esp_clk_tree_common.h"
1612

1713
typedef struct gptimer_platform_t {
1814
_lock_t mutex; // platform level mutex lock
@@ -182,3 +178,11 @@ int gptimer_get_group_id(gptimer_handle_t timer, int *group_id)
182178
*group_id = timer->group->group_id;
183179
return ESP_OK;
184180
}
181+
182+
#if CONFIG_GPTIMER_ENABLE_DEBUG_LOG
183+
__attribute__((constructor))
184+
static void gptimer_override_default_log_level(void)
185+
{
186+
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
187+
}
188+
#endif

0 commit comments

Comments
 (0)