mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
The task dispatch method for the esp_timer could stall even if it is armed if ther ISR dispatch alarm triggers close to the task dispatch. This MR fixes a bug where the esp_timer cleared the incorrect cached array timer index and subsequently the timer task is never woken up. Closes https://github.com/espressif/esp-idf/issues/18808
84 lines
2.4 KiB
C
84 lines
2.4 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "esp_timer_impl.h"
|
|
#include "esp_timer.h"
|
|
#include "esp_err.h"
|
|
#include "esp_task.h"
|
|
#include "esp_attr.h"
|
|
|
|
/* Spinlock used to protect access to the hardware registers. */
|
|
portMUX_TYPE s_time_update_lock = portMUX_INITIALIZER_UNLOCKED;
|
|
|
|
/* Alarm values to generate interrupt on match
|
|
* [0] - for ESP_TIMER_TASK alarms,
|
|
* [1] - for ESP_TIMER_ISR alarms.
|
|
*/
|
|
uint64_t timestamp_id[2] = { UINT64_MAX, UINT64_MAX };
|
|
|
|
void esp_timer_impl_lock(void)
|
|
{
|
|
portENTER_CRITICAL(&s_time_update_lock);
|
|
}
|
|
|
|
void esp_timer_impl_unlock(void)
|
|
{
|
|
portEXIT_CRITICAL(&s_time_update_lock);
|
|
}
|
|
|
|
#ifndef CONFIG_IDF_TARGET_LINUX
|
|
void esp_timer_private_lock(void) __attribute__((alias("esp_timer_impl_lock")));
|
|
void esp_timer_private_unlock(void) __attribute__((alias("esp_timer_impl_unlock")));
|
|
#else // CONFIG_IDF_TARGET_LINUX
|
|
// Avoid using __attribute(alias) here since linux target builds on MacOS fail to compile.
|
|
void esp_timer_private_lock(void)
|
|
{
|
|
esp_timer_impl_lock();
|
|
}
|
|
|
|
void esp_timer_private_unlock(void)
|
|
{
|
|
esp_timer_impl_unlock();
|
|
}
|
|
#endif // CONFIG_IDF_TARGET_LINUX
|
|
|
|
void ESP_TIMER_IRAM_ATTR esp_timer_impl_set_alarm(uint64_t timestamp)
|
|
{
|
|
esp_timer_impl_set_alarm_id(timestamp, 0);
|
|
}
|
|
|
|
#ifdef CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD
|
|
/* Reprogram the hardware alarm to the nearest pending deadline,
|
|
* i.e. MIN(timestamp_id[0], timestamp_id[1]). The timestamp_id[] cache is not modified.
|
|
* Must be called with s_time_update_lock held. */
|
|
static inline void ESP_TIMER_IRAM_ATTR esp_timer_impl_rearm_alarm(void)
|
|
{
|
|
esp_timer_impl_set_alarm_id(timestamp_id[ESP_TIMER_TASK], ESP_TIMER_TASK);
|
|
}
|
|
|
|
uint32_t ESP_TIMER_IRAM_ATTR esp_timer_impl_claim_due_alarms(void)
|
|
{
|
|
portENTER_CRITICAL_ISR(&s_time_update_lock);
|
|
uint64_t now = esp_timer_impl_get_time();
|
|
uint32_t due_mask = 0;
|
|
for (unsigned alarm_id = 0; alarm_id < sizeof(timestamp_id) / sizeof(timestamp_id[0]); ++alarm_id) {
|
|
if (timestamp_id[alarm_id] <= now) {
|
|
due_mask |= 1U << alarm_id;
|
|
timestamp_id[alarm_id] = UINT64_MAX;
|
|
}
|
|
}
|
|
esp_timer_impl_rearm_alarm();
|
|
portEXIT_CRITICAL_ISR(&s_time_update_lock);
|
|
return due_mask;
|
|
}
|
|
#endif
|
|
|
|
/* FIXME: This value is safe for 80MHz APB frequency, should be modified to depend on clock frequency. */
|
|
uint64_t ESP_TIMER_IRAM_ATTR esp_timer_impl_get_min_period_us(void)
|
|
{
|
|
return 50;
|
|
}
|