1
6
7
13
14
15
16
21
22
23
24
25
26
27
28
29
30
31
32
44
48
49
50
62
63
64
65
66
67
68
69
70
71
72
73
78
79
80
90
91
92
93
94
95
96
97
98
99
105
106
107
108
109
110
111
112
113
114
115
116
117
122
123
124
129
130
131
138
139
144
145
146
147
148
149
150
154
155
156
157
158
161
162
163
164
170
171
177
178
/* ... */
#include "esp_check.h"
#include "esp_clk_tree.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/gptimer.h"
#include "gptimer_priv.h"
#include "soc/soc_caps.h"6 includes
static const char *TAG = "gptimer";
typedef struct gptimer_platform_t {
_lock_t mutex;
gptimer_group_t *groups[SOC_TIMER_GROUPS];
int group_ref_counts[SOC_TIMER_GROUPS];
}{ ... } gptimer_platform_t;
static gptimer_platform_t s_platform;
gptimer_group_t *gptimer_acquire_group_handle(int group_id)
{
bool new_group = false;
gptimer_group_t *group = NULL;
_lock_acquire(&s_platform.mutex);
if (!s_platform.groups[group_id]) {
group = heap_caps_calloc(1, sizeof(gptimer_group_t), GPTIMER_MEM_ALLOC_CAPS);
if (group) {
new_group = true;
s_platform.groups[group_id] = group;
group->group_id = group_id;
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
}{...}
}{...} else {
group = s_platform.groups[group_id];
}{...}
if (group) {
s_platform.group_ref_counts[group_id]++;
}{...}
_lock_release(&s_platform.mutex);
if (new_group) {
PERIPH_RCC_ACQUIRE_ATOMIC(timer_group_periph_signals.groups[group_id].module, ref_count) {
if (ref_count == 0) {
timer_ll_enable_bus_clock(group_id, true);
timer_ll_reset_register(group_id);
}{...}
}{...}
ESP_LOGD(TAG, "new group (%d) @%p", group_id, group);
}{...}
return group;
}{ ... }
void gptimer_release_group_handle(gptimer_group_t *group)
{
int group_id = group->group_id;
bool do_deinitialize = false;
_lock_acquire(&s_platform.mutex);
s_platform.group_ref_counts[group_id]--;
if (s_platform.group_ref_counts[group_id] == 0) {
assert(s_platform.groups[group_id]);
do_deinitialize = true;
s_platform.groups[group_id] = NULL;
}{...}
_lock_release(&s_platform.mutex);
if (do_deinitialize) {
PERIPH_RCC_RELEASE_ATOMIC(timer_group_periph_signals.groups[group_id].module, ref_count) {
if (ref_count == 0) {
timer_ll_enable_bus_clock(group_id, false);
}{...}
}{...}
free(group);
ESP_LOGD(TAG, "del group (%d)", group_id);
}{...}
}{ ... }
esp_err_t gptimer_select_periph_clock(gptimer_t *timer, gptimer_clock_source_t src_clk, uint32_t resolution_hz)
{
uint32_t counter_src_hz = 0;
int timer_id = timer->timer_id;
#if SOC_TIMER_GROUP_SUPPORT_RC_FAST
if (src_clk == GPTIMER_CLK_SRC_RC_FAST) {
periph_rtc_dig_clk8m_enable();
}{...}
#endif/* ... */
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)src_clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz),
TAG, "get clock source frequency failed");
#if CONFIG_PM_ENABLE
bool need_pm_lock = true;
esp_pm_lock_type_t pm_lock_type = ESP_PM_NO_LIGHT_SLEEP;
#if SOC_TIMER_GROUP_SUPPORT_RC_FAST
if (src_clk == GPTIMER_CLK_SRC_RC_FAST) {
need_pm_lock = false;
}{...}
#endif/* ... */
#if SOC_TIMER_GROUP_SUPPORT_APB
if (src_clk == GPTIMER_CLK_SRC_APB) {
pm_lock_type = ESP_PM_APB_FREQ_MAX;
}{...}
#endif/* ... */
#if CONFIG_IDF_TARGET_ESP32C2
if (src_clk == GPTIMER_CLK_SRC_PLL_F40M) {
pm_lock_type = ESP_PM_APB_FREQ_MAX;
}{...}
#endif/* ... */
if (need_pm_lock) {
sprintf(timer->pm_lock_name, "gptimer_%d_%d", timer->group->group_id, timer_id);
ESP_RETURN_ON_ERROR(esp_pm_lock_create(pm_lock_type, 0, timer->pm_lock_name, &timer->pm_lock),
TAG, "create pm lock failed");
}{...}
#endif/* ... */
esp_clk_tree_enable_src((soc_module_clk_t)src_clk, true);
GPTIMER_CLOCK_SRC_ATOMIC() {
timer_ll_set_clock_source(timer->hal.dev, timer_id, src_clk);
timer_ll_enable_clock(timer->hal.dev, timer_id, true);
}{...}
timer->clk_src = src_clk;
uint32_t prescale = counter_src_hz / resolution_hz;
timer_ll_set_clock_prescale(timer->hal.dev, timer_id, prescale);
timer->resolution_hz = counter_src_hz / prescale;
if (timer->resolution_hz != resolution_hz) {
ESP_LOGW(TAG, "resolution lost, expect %"PRIu32", real %"PRIu32, resolution_hz, timer->resolution_hz);
}{...}
return ESP_OK;
}{ ... }
esp_err_t gptimer_get_intr_handle(gptimer_handle_t timer, intr_handle_t *ret_intr_handle)
{
ESP_RETURN_ON_FALSE(timer && ret_intr_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
*ret_intr_handle = timer->intr;
return ESP_OK;
}{ ... }
esp_err_t gptimer_get_pm_lock(gptimer_handle_t timer, esp_pm_lock_handle_t *ret_pm_lock)
{
ESP_RETURN_ON_FALSE(timer && ret_pm_lock, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
*ret_pm_lock = timer->pm_lock;
return ESP_OK;
}{ ... }
int gptimer_get_group_id(gptimer_handle_t timer, int *group_id)
{
ESP_RETURN_ON_FALSE(timer && group_id, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
*group_id = timer->group->group_id;
return ESP_OK;
}{ ... }