mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
gptimer: added enable/disable functions
This commit is contained in:
parent
3f66660444
commit
e7295c3577
@ -198,6 +198,7 @@ static void SEGGER_SYSVIEW_TS_Init(void)
|
||||
// pick any free GPTimer instance
|
||||
ESP_ERROR_CHECK(gptimer_new_timer(&config, &s_sv_gptimer));
|
||||
/* Start counting */
|
||||
gptimer_enable(s_sv_gptimer);
|
||||
gptimer_start(s_sv_gptimer);
|
||||
#endif // TS_USE_TIMERGROUP
|
||||
}
|
||||
|
@ -172,6 +172,7 @@ static void esp_apptrace_dummy_task(void *p)
|
||||
.on_alarm = arg->timers[i].isr_func,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(arg->timers[i].gptimer, &cbs, &arg->timers[i]));
|
||||
TEST_ESP_OK(gptimer_enable(arg->timers[i].gptimer));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(arg->timers[i].gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_start(arg->timers[i].gptimer));
|
||||
}
|
||||
@ -186,6 +187,7 @@ static void esp_apptrace_dummy_task(void *p)
|
||||
|
||||
for (int i = 0; i < arg->timers_num; i++) {
|
||||
TEST_ESP_OK(gptimer_stop(arg->timers[i].gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(arg->timers[i].gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(arg->timers[i].gptimer));
|
||||
}
|
||||
xSemaphoreGive(arg->done);
|
||||
@ -219,6 +221,7 @@ static void esp_apptrace_test_task(void *p)
|
||||
.on_alarm = arg->timers[i].isr_func,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(arg->timers[i].gptimer, &cbs, &arg->timers[i]));
|
||||
TEST_ESP_OK(gptimer_enable(arg->timers[i].gptimer));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(arg->timers[i].gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_start(arg->timers[i].gptimer));
|
||||
}
|
||||
@ -257,6 +260,7 @@ static void esp_apptrace_test_task(void *p)
|
||||
|
||||
for (int i = 0; i < arg->timers_num; i++) {
|
||||
TEST_ESP_OK(gptimer_stop(arg->timers[i].gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(arg->timers[i].gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(arg->timers[i].gptimer));
|
||||
}
|
||||
xSemaphoreGive(arg->done);
|
||||
@ -311,12 +315,14 @@ static void esp_apptrace_test_ts_init(void)
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &ts_gptimer));
|
||||
ESP_APPTRACE_TEST_LOGI("Use timer %x for TS", ts_gptimer);
|
||||
TEST_ESP_OK(gptimer_enable(ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_start(ts_gptimer));
|
||||
}
|
||||
|
||||
static void esp_apptrace_test_ts_cleanup(void)
|
||||
{
|
||||
TEST_ESP_OK(gptimer_stop(ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(ts_gptimer));
|
||||
ts_gptimer = NULL;
|
||||
}
|
||||
@ -729,6 +735,7 @@ static void esp_sysviewtrace_test_task(void *p)
|
||||
.on_alarm = esp_sysview_test_timer_isr,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(arg->timer->gptimer, &cbs, arg->timer));
|
||||
TEST_ESP_OK(gptimer_enable(arg->timer->gptimer));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(arg->timer->gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_start(arg->timer->gptimer));
|
||||
}
|
||||
@ -814,8 +821,10 @@ TEST_CASE("SysView trace test 1", "[trace][ignore]")
|
||||
xSemaphoreTake(arg2.done, portMAX_DELAY);
|
||||
vSemaphoreDelete(arg2.done);
|
||||
TEST_ESP_OK(gptimer_stop(tim_arg1.gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(tim_arg1.gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(tim_arg1.gptimer));
|
||||
TEST_ESP_OK(gptimer_stop(tim_arg2.gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(tim_arg2.gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(tim_arg2.gptimer));
|
||||
}
|
||||
|
||||
@ -907,8 +916,10 @@ TEST_CASE("SysView trace test 2", "[trace][ignore]")
|
||||
vSemaphoreDelete(arg4.done);
|
||||
vSemaphoreDelete(test_sync);
|
||||
TEST_ESP_OK(gptimer_stop(tim_arg1.gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(tim_arg1.gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(tim_arg1.gptimer));
|
||||
TEST_ESP_OK(gptimer_stop(tim_arg2.gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(tim_arg2.gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(tim_arg2.gptimer));
|
||||
}
|
||||
#endif // #if CONFIG_APPTRACE_SV_ENABLE == 0
|
||||
|
@ -64,9 +64,9 @@ struct gptimer_group_t {
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GPTIMER_FSM_STOP,
|
||||
GPTIMER_FSM_START,
|
||||
} gptimer_lifecycle_fsm_t;
|
||||
GPTIMER_FSM_INIT,
|
||||
GPTIMER_FSM_ENABLE,
|
||||
} gptimer_fsm_t;
|
||||
|
||||
struct gptimer_t {
|
||||
gptimer_group_t *group;
|
||||
@ -76,7 +76,7 @@ struct gptimer_t {
|
||||
unsigned long long alarm_count;
|
||||
gptimer_count_direction_t direction;
|
||||
timer_hal_context_t hal;
|
||||
gptimer_lifecycle_fsm_t fsm; // access to fsm should be protect by spinlock, as fsm is also accessed from ISR handler
|
||||
gptimer_fsm_t fsm;
|
||||
intr_handle_t intr;
|
||||
portMUX_TYPE spinlock; // to protect per-timer resources concurent accessed by task and ISR handler
|
||||
gptimer_alarm_cb_t on_alarm;
|
||||
@ -194,7 +194,7 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
// initialize other members of timer
|
||||
timer->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
timer->fsm = GPTIMER_FSM_STOP;
|
||||
timer->fsm = GPTIMER_FSM_INIT; // put the timer into init state
|
||||
timer->direction = config->direction;
|
||||
timer->flags.intr_shared = config->flags.intr_shared;
|
||||
ESP_LOGD(TAG, "new gptimer (%d,%d) at %p, resolution=%uHz", group_id, timer_id, timer, timer->resolution_hz);
|
||||
@ -211,16 +211,10 @@ err:
|
||||
esp_err_t gptimer_del_timer(gptimer_handle_t timer)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
|
||||
gptimer_group_t *group = timer->group;
|
||||
int group_id = group->group_id;
|
||||
int timer_id = timer->timer_id;
|
||||
|
||||
bool valid_state = true;
|
||||
portENTER_CRITICAL(&timer->spinlock);
|
||||
valid_state = timer->fsm == GPTIMER_FSM_STOP;
|
||||
portEXIT_CRITICAL(&timer->spinlock);
|
||||
ESP_RETURN_ON_FALSE(valid_state, ESP_ERR_INVALID_STATE, TAG, "can't delete timer as it's not stop yet");
|
||||
|
||||
ESP_LOGD(TAG, "del timer (%d,%d)", group_id, timer_id);
|
||||
// recycle memory resource
|
||||
ESP_RETURN_ON_ERROR(gptimer_destory(timer), TAG, "destory gptimer failed");
|
||||
@ -251,6 +245,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
|
||||
{
|
||||
gptimer_group_t *group = NULL;
|
||||
ESP_RETURN_ON_FALSE(timer && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
|
||||
group = timer->group;
|
||||
int group_id = group->group_id;
|
||||
int timer_id = timer->timer_id;
|
||||
@ -314,23 +309,50 @@ esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_c
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_start(gptimer_handle_t timer)
|
||||
esp_err_t gptimer_enable(gptimer_handle_t timer)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "timer not in init state");
|
||||
|
||||
// acquire power manager lock
|
||||
if (timer->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_pm_lock_acquire(timer->pm_lock), TAG, "acquire APB_FREQ_MAX lock failed");
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(timer->pm_lock), TAG, "acquire pm_lock failed");
|
||||
}
|
||||
// interrupt interupt service
|
||||
// enable interrupt interupt service
|
||||
if (timer->intr) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed");
|
||||
ESP_RETURN_ON_ERROR(esp_intr_enable(timer->intr), TAG, "enable interrupt service failed");
|
||||
}
|
||||
|
||||
timer->fsm = GPTIMER_FSM_ENABLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_disable(gptimer_handle_t timer)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(timer->fsm == GPTIMER_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "timer not in enable state");
|
||||
|
||||
// disable interrupt service
|
||||
if (timer->intr) {
|
||||
ESP_RETURN_ON_ERROR(esp_intr_disable(timer->intr), TAG, "disable interrupt service failed");
|
||||
}
|
||||
// release power manager lock
|
||||
if (timer->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_release(timer->pm_lock), TAG, "release pm_lock failed");
|
||||
}
|
||||
|
||||
timer->fsm = GPTIMER_FSM_INIT;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t gptimer_start(gptimer_handle_t timer)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(timer->fsm == GPTIMER_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "timer not enabled yet");
|
||||
|
||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||
timer_ll_enable_counter(timer->hal.dev, timer->timer_id, true);
|
||||
timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, timer->flags.alarm_en);
|
||||
timer->fsm = GPTIMER_FSM_START;
|
||||
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
@ -339,23 +361,14 @@ esp_err_t gptimer_start(gptimer_handle_t timer)
|
||||
esp_err_t gptimer_stop(gptimer_handle_t timer)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(timer, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(timer->fsm == GPTIMER_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "timer not enabled yet");
|
||||
|
||||
// disable counter, alarm, autoreload
|
||||
// disable counter, alarm, auto-reload
|
||||
portENTER_CRITICAL_SAFE(&timer->spinlock);
|
||||
timer_ll_enable_counter(timer->hal.dev, timer->timer_id, false);
|
||||
timer_ll_enable_alarm(timer->hal.dev, timer->timer_id, false);
|
||||
timer->fsm = GPTIMER_FSM_STOP;
|
||||
portEXIT_CRITICAL_SAFE(&timer->spinlock);
|
||||
|
||||
// disable interrupt service
|
||||
if (timer->intr) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_intr_disable(timer->intr), TAG, "disable interrupt service failed");
|
||||
}
|
||||
// release power manager lock
|
||||
if (timer->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_pm_lock_release(timer->pm_lock), TAG, "release APB_FREQ_MAX lock failed");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@ typedef bool (*gptimer_alarm_cb_t) (gptimer_handle_t timer, const gptimer_alarm_
|
||||
/**
|
||||
* @brief Group of supported GPTimer callbacks
|
||||
* @note The callbacks are all running under ISR environment
|
||||
* @note When CONFIG_GPTIMER_ISR_IRAM_SAFE is enabled, the callback itself and functions callbed by it should be placed in IRAM.
|
||||
*/
|
||||
typedef struct {
|
||||
gptimer_alarm_cb_t on_alarm; /*!< Timer alarm callback */
|
||||
@ -73,7 +74,7 @@ typedef struct {
|
||||
/**
|
||||
* @brief Create a new General Purpose Timer, and return the handle
|
||||
*
|
||||
* @note Once a timer is created, it is placed in the stopped state and will not start until `gptimer_start()` is called.
|
||||
* @note The newly created timer is put in the init state.
|
||||
*
|
||||
* @param[in] config GPTimer configuration
|
||||
* @param[out] ret_timer Returned timer handle
|
||||
@ -89,13 +90,14 @@ esp_err_t gptimer_new_timer(const gptimer_config_t *config, gptimer_handle_t *re
|
||||
/**
|
||||
* @brief Delete the GPTimer handle
|
||||
*
|
||||
* @note A timer must be in a stop state before it can be deleted.
|
||||
* @note A timer can't be in the enable state when this function is invoked.
|
||||
* See also `gptimer_disable()` for how to disable a timer.
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
* @return
|
||||
* - ESP_OK: Delete GPTimer successfully
|
||||
* - ESP_ERR_INVALID_ARG: Delete GPTimer failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Delete GPTimer failed because the timer has not stopped
|
||||
* - ESP_ERR_INVALID_STATE: Delete GPTimer failed because the timer is not in init state
|
||||
* - ESP_FAIL: Delete GPTimer failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_del_timer(gptimer_handle_t timer);
|
||||
@ -135,7 +137,8 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value);
|
||||
/**
|
||||
* @brief Set callbacks for GPTimer
|
||||
*
|
||||
* @note The user registered callbacks are expected to be runnable within ISR context
|
||||
* @note User registered callbacks are expected to be runnable within ISR context
|
||||
* @note This function should be called when the timer is in the init state (i.e. before calling `gptimer_enable()`)
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
* @param[in] cbs Group of callback functions
|
||||
@ -143,6 +146,7 @@ esp_err_t gptimer_get_raw_count(gptimer_handle_t timer, uint64_t *value);
|
||||
* @return
|
||||
* - ESP_OK: Set event callbacks successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set event callbacks failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Set event callbacks failed because the timer is not in init state
|
||||
* - ESP_FAIL: Set event callbacks failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer_event_callbacks_t *cbs, void *user_data);
|
||||
@ -150,7 +154,7 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
|
||||
/**
|
||||
* @brief Set alarm event actions for GPTimer.
|
||||
*
|
||||
* @note This function is allowed to run within ISR context
|
||||
* @note This function is allowed to run within ISR context, so that user can set new alarm action immediately in the ISR callback.
|
||||
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
@ -163,31 +167,65 @@ esp_err_t gptimer_register_event_callbacks(gptimer_handle_t timer, const gptimer
|
||||
esp_err_t gptimer_set_alarm_action(gptimer_handle_t timer, const gptimer_alarm_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Start GPTimer
|
||||
* @brief Enable GPTimer
|
||||
*
|
||||
* @note This function will transit the timer state from init to enable.
|
||||
* @note This function will enable the interrupt service, if it's lazy installed in `gptimer_register_event_callbacks()`.
|
||||
* @note This function will acquire a PM lock, if a specific source clock (e.g. APB) is selected in the `gptimer_config_t`, while `CONFIG_PM_ENABLE` is enabled.
|
||||
* @note Enable a timer doesn't mean to start it. See also `gptimer_start()` for how to make the timer start counting.
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
* @return
|
||||
* - ESP_OK: Enable GPTimer successfully
|
||||
* - ESP_ERR_INVALID_ARG: Enable GPTimer failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Enable GPTimer failed because the timer is already enabled
|
||||
* - ESP_FAIL: Enable GPTimer failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_enable(gptimer_handle_t timer);
|
||||
|
||||
/**
|
||||
* @brief Disable GPTimer
|
||||
*
|
||||
* @note This function will do the opposite work to the `gptimer_enable()`
|
||||
* @note Disable a timer doesn't mean to stop it. See also `gptimer_stop()` for how to make the timer stop counting.
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
* @return
|
||||
* - ESP_OK: Disable GPTimer successfully
|
||||
* - ESP_ERR_INVALID_ARG: Disable GPTimer failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Disable GPTimer failed because the timer is not enabled yet
|
||||
* - ESP_FAIL: Disable GPTimer failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_disable(gptimer_handle_t timer);
|
||||
|
||||
/**
|
||||
* @brief Start GPTimer (internal counter starts counting)
|
||||
*
|
||||
* @note This function should be called when the timer is in the enable state (i.e. after calling `gptimer_enable()`)
|
||||
* @note This function is allowed to run within ISR context
|
||||
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
|
||||
* @note This function will be placed into IRAM if `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
* @return
|
||||
* - ESP_OK: Start GPTimer successfully
|
||||
* - ESP_ERR_INVALID_ARG: Start GPTimer failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Start GPTimer failed because the timer is not in stop state
|
||||
* - ESP_ERR_INVALID_STATE: Start GPTimer failed because the timer is not enabled yet
|
||||
* - ESP_FAIL: Start GPTimer failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_start(gptimer_handle_t timer);
|
||||
|
||||
/**
|
||||
* @brief Stop GPTimer
|
||||
* @brief Stop GPTimer (internal counter stops counting)
|
||||
*
|
||||
* @note This function should be called when the timer is in the enable state (i.e. after calling `gptimer_enable()`)
|
||||
* @note This function is allowed to run within ISR context
|
||||
* @note This function is allowed to be executed when Cache is disabled, by enabling `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM`
|
||||
* @note This function will be placed into IRAM if `CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled
|
||||
*
|
||||
* @param[in] timer Timer handle created by `gptimer_new_timer()`
|
||||
* @return
|
||||
* - ESP_OK: Stop GPTimer successfully
|
||||
* - ESP_ERR_INVALID_ARG: Stop GPTimer failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Stop GPTimer failed because the timer is not in start state
|
||||
* - ESP_ERR_INVALID_STATE: Stop GPTimer failed because the timer is not enabled yet
|
||||
* - ESP_FAIL: Stop GPTimer failed because of other error
|
||||
*/
|
||||
esp_err_t gptimer_stop(gptimer_handle_t timer);
|
||||
|
@ -72,6 +72,12 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]")
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
// start timer before enable should fail
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gptimer_start(timers[0]));
|
||||
printf("enable timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
}
|
||||
printf("start timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
@ -109,6 +115,11 @@ TEST_CASE("gptimer_wallclock_with_various_clock_sources", "[gptimer]")
|
||||
printf("get raw count of gptimer %d: %llu\r\n", i, value);
|
||||
TEST_ASSERT_UINT_WITHIN(2000, 40000, value);
|
||||
}
|
||||
printf("disable timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
}
|
||||
printf("delete timers\r\n");
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
@ -149,6 +160,7 @@ TEST_CASE("gptimer_stop_on_alarm", "[gptimer]")
|
||||
alarm_config.alarm_count = 100000 * (i + 1);
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
printf("alarm value for gptimer %d: %llu\r\n", i, alarm_config.alarm_count);
|
||||
}
|
||||
@ -184,6 +196,7 @@ TEST_CASE("gptimer_stop_on_alarm", "[gptimer]")
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
@ -226,16 +239,18 @@ TEST_CASE("gptimer_auto_reload_on_alarm", "[gptimer]")
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
// delete should fail if timer is not stopped
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, gptimer_del_timer(timers[i]));
|
||||
// delete should fail if timer is not disabled
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, gptimer_del_timer(timers[i]));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
@ -276,6 +291,7 @@ TEST_CASE("gptimer_one_shot_alarm", "[gptimer]")
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
// no alarm event should trigger again, as auto-reload is not enabled and alarm value hasn't changed in the isr
|
||||
@ -296,6 +312,7 @@ TEST_CASE("gptimer_one_shot_alarm", "[gptimer]")
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
@ -337,6 +354,7 @@ TEST_CASE("gptimer_update_alarm_dynamically", "[gptimer]")
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// check the alarm event for multiple times
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(500)));
|
||||
@ -360,6 +378,7 @@ TEST_CASE("gptimer_update_alarm_dynamically", "[gptimer]")
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
@ -402,6 +421,7 @@ TEST_CASE("gptimer_count_down_reload", "[gptimer]")
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(timers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
// check twice, as it's a period event
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000)));
|
||||
@ -419,6 +439,7 @@ TEST_CASE("gptimer_count_down_reload", "[gptimer]")
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
@ -467,12 +488,14 @@ TEST_CASE("gptimer_overflow", "[gptimer]")
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(timers[i], &cbs, task_handle));
|
||||
// we start from the reload value
|
||||
TEST_ESP_OK(gptimer_set_raw_count(timers[i], reload_at));
|
||||
TEST_ESP_OK(gptimer_enable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_start(timers[i]));
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(400)));
|
||||
TEST_ESP_OK(gptimer_stop(timers[i]));
|
||||
}
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_disable(timers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ TEST_CASE("gptimer_iram_interrupt_safe", "[gptimer]")
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, &block_arg));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
xTaskCreatePinnedToCore(flash_read_task, "read_flash", 2048, &read_arg, 3, NULL, portNUM_PROCESSORS - 1);
|
||||
@ -93,6 +94,7 @@ TEST_CASE("gptimer_iram_interrupt_safe", "[gptimer]")
|
||||
TEST_ASSERT_GREATER_THAN(1000, block_arg.repeat_count);
|
||||
// delete gptimer
|
||||
TEST_ESP_OK(gptimer_stop(gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
vSemaphoreDelete(done_sem);
|
||||
free(buf);
|
||||
|
@ -2002,6 +2002,7 @@ TEST_CASE("can post events from interrupt handler", "[event]")
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, sem));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
TEST_SETUP();
|
||||
@ -2012,6 +2013,7 @@ TEST_CASE("can post events from interrupt handler", "[event]")
|
||||
xSemaphoreTake(sem, portMAX_DELAY);
|
||||
|
||||
TEST_TEARDOWN();
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ static void timer_test(int flags)
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimers[i], &cbs, &count[i]));
|
||||
alarm_config.alarm_count += 10000 * i;
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimers[i], &alarm_config));
|
||||
TEST_ESP_OK(gptimer_enable(gptimers[i]));
|
||||
TEST_ESP_OK(gptimer_start(gptimers[i]));
|
||||
TEST_ESP_OK(gptimer_get_intr_handle(gptimers[i], &inth[i]));
|
||||
printf("Interrupts allocated: %d\r\n", esp_intr_get_intno(inth[i]));
|
||||
@ -93,6 +94,7 @@ static void timer_test(int flags)
|
||||
|
||||
for (int i = 0; i < SOC_TIMER_GROUP_TOTAL_TIMERS; i++) {
|
||||
TEST_ESP_OK(gptimer_stop(gptimers[i]));
|
||||
TEST_ESP_OK(gptimer_disable(gptimers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimers[i]));
|
||||
}
|
||||
}
|
||||
|
@ -140,6 +140,7 @@ TEST_CASE("Automatic light occurs when tasks are suspended", "[pm]")
|
||||
.resolution_hz = 1000000, /* 1 us per tick */
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&config, &gptimer));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
// if GPTimer is clocked from APB, when PM is enabled, the driver will acquire the PM lock
|
||||
// causing the auto light sleep doesn't take effect
|
||||
@ -174,6 +175,7 @@ TEST_CASE("Automatic light occurs when tasks are suspended", "[pm]")
|
||||
light_sleep_disable();
|
||||
TEST_ESP_OK(esp_pm_lock_acquire(gptimer_pm_lock));
|
||||
TEST_ESP_OK(gptimer_stop(gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
}
|
||||
|
||||
|
@ -779,12 +779,14 @@ TEST_CASE("Test ring buffer ISR", "[esp_ringbuf]")
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
//Wait for ISR to complete multiple iterations
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY);
|
||||
|
||||
//Cleanup
|
||||
TEST_ESP_OK(gptimer_stop(gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
vSemaphoreDelete(done_sem);
|
||||
for (int i = 0; i < NO_OF_RB_TYPES; i++) {
|
||||
|
@ -176,6 +176,7 @@ TEST_CASE("FreeRTOS Event Group ISR", "[freertos]")
|
||||
.on_alarm = on_timer_alarm_cb,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
|
||||
//Test set bits
|
||||
@ -195,6 +196,7 @@ TEST_CASE("FreeRTOS Event Group ISR", "[freertos]")
|
||||
TEST_ASSERT_EQUAL(0, xEventGroupGetBits(eg)); //Check bits are cleared
|
||||
|
||||
//Clean up
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
vEventGroupDelete(eg);
|
||||
vSemaphoreDelete(done_sem);
|
||||
|
@ -63,10 +63,6 @@ static void test_gptimer_start(void *arg)
|
||||
.alarm_count = 1000,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_set_raw_count(gptimer, 0));
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = on_alarm_sender_cb,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
}
|
||||
@ -144,6 +140,11 @@ static void install_gptimer_on_core(void *arg)
|
||||
.resolution_hz = 1000000, // 1MHz, 1 tick = 1us
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &gptimers[core_id]));
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = on_alarm_sender_cb,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimers[core_id], &cbs, NULL));
|
||||
TEST_ESP_OK(gptimer_enable(gptimers[core_id]));
|
||||
test_gptimer_start(gptimers[core_id]);
|
||||
xSemaphoreGive(task_delete_semphr);
|
||||
vTaskDelete(NULL);
|
||||
@ -191,6 +192,7 @@ TEST_CASE("Test Task_Notify", "[freertos]")
|
||||
vSemaphoreDelete(task_delete_semphr);
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
TEST_ESP_OK(gptimer_stop(gptimers[i]));
|
||||
TEST_ESP_OK(gptimer_disable(gptimers[i]));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimers[i]));
|
||||
}
|
||||
}
|
||||
|
@ -86,6 +86,7 @@ TEST_CASE("Scheduler disabled can handle a pending context switch on resume", "[
|
||||
.on_alarm = on_timer_alarm_cb,
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, NULL));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
TEST_ESP_OK(gptimer_get_intr_handle(gptimer, &intr_handle));
|
||||
@ -130,6 +131,7 @@ TEST_CASE("Scheduler disabled can handle a pending context switch on resume", "[
|
||||
}
|
||||
|
||||
TEST_ESP_OK(gptimer_stop(gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
vTaskDelete(counter_task);
|
||||
vSemaphoreDelete(isr_semaphore);
|
||||
|
@ -173,6 +173,7 @@ static void test_resume_task_from_isr(int target_core)
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, suspend_task));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
// wait the timer interrupt fires up
|
||||
vTaskDelay(2);
|
||||
@ -184,6 +185,7 @@ static void test_resume_task_from_isr(int target_core)
|
||||
TEST_ASSERT_UINT32_WITHIN(100, alarm_config.alarm_count, (unsigned)resumed_counter);
|
||||
|
||||
// clean up
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
}
|
||||
|
||||
|
@ -241,6 +241,7 @@ TEST_CASE("eventfd signal from ISR", "[vfs][eventfd]")
|
||||
};
|
||||
TEST_ESP_OK(gptimer_register_event_callbacks(gptimer, &cbs, &fd));
|
||||
TEST_ESP_OK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
TEST_ESP_OK(gptimer_enable(gptimer));
|
||||
TEST_ESP_OK(gptimer_start(gptimer));
|
||||
|
||||
struct timeval wait_time;
|
||||
@ -258,6 +259,7 @@ TEST_CASE("eventfd signal from ISR", "[vfs][eventfd]")
|
||||
TEST_ASSERT(FD_ISSET(fd, &read_fds));
|
||||
TEST_ASSERT_EQUAL(0, close(fd));
|
||||
TEST_ESP_OK(esp_vfs_eventfd_unregister());
|
||||
TEST_ESP_OK(gptimer_disable(gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(gptimer));
|
||||
}
|
||||
|
||||
|
@ -4,14 +4,12 @@ General Purpose Timer (GPTimer)
|
||||
Introduction
|
||||
------------
|
||||
|
||||
A general purpose timer is a hardware timer with high resolution and flexible alarm action. The behavior when the internal counter of a timer reaches a specific target value is called timer alarm. When a timer alarms, a user registered per-timer callback would be called.
|
||||
The GPTimer (General Purpose Timer) is the driver of {IDF_TARGET_NAME} Timer Group peripheral. It features a hardware timer with high resolution and flexible alarm action. The behavior when the internal counter of a timer reaches a specific target value is called timer alarm. When a timer alarms, a user registered per-timer callback would be called.
|
||||
|
||||
Typically, a general purpose timer can be used in scenarios like:
|
||||
|
||||
- Free running as a wall clock, fetching a high-resolution time stamp at any time and any places
|
||||
|
||||
- Generate period alarms, trigger events periodically
|
||||
|
||||
- Generate one-shot alarm, respond in target time
|
||||
|
||||
Functional Overview
|
||||
@ -23,6 +21,7 @@ The following sections of this document cover the typical steps to install and o
|
||||
- `Set and Get count value <#set-and-get-count-value>`__ - covers how to force the timer counting from a start point and how to get the count value at anytime.
|
||||
- `Set Up Alarm Action <#set-up-alarm-action>`__ - covers the parameters that should be set up to enable the alarm event.
|
||||
- `Register Event Callbacks <#register-event-callbacks>`__ - covers how to hook user specific code to the alarm event callback function.
|
||||
- `Enable and Disable timer <#enable-and-disable-timer>`__ - covers how to enable and disable the timer.
|
||||
- `Start and Stop timer <#start-and-stop-timer>`__ - shows some typical use cases that start the timer with different alarm behavior.
|
||||
- `Power Management <#power-management>`__ - describes how different source clock selections can affect power consumption.
|
||||
- `IRAM Safe <#iram-safe>`__ - describes tips on how to make the timer interrupt and IO control functions work better along with a disabled cache.
|
||||
@ -32,13 +31,13 @@ The following sections of this document cover the typical steps to install and o
|
||||
Resource Allocation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The GPTimer is implemented using {IDF_TARGET_NAME} Timer Group module. Different ESP chips might have different number of independent timer groups, and within each group, there could also be several independent timers. Please refer to Chapter `Timer Group (TIMG) <{IDF_TARGET_TRM_EN_URL}#timg>`__ in {IDF_TARGET_NAME} Technical Reference Manual to find out how many hardware timers exist.
|
||||
Different ESP chips might have different numbers of independent timer groups, and within each group, there could also be several independent timers. [1]_
|
||||
|
||||
From driver's point of view, a GPTimer instance is represented by :cpp:type:`gptimer_handle_t`. The driver behind will manage all available hardware resources in a pool, so that users don't need to care about which timer and which group it belongs to.
|
||||
|
||||
To install a timer instance, there's a configuration structure that needs to be given in advance: :cpp:type:`gptimer_config_t`:
|
||||
|
||||
- :cpp:member:`gptimer_config_t::clk_src` selects the source clock for the timer. The available clocks are listed in :cpp:type:`gptimer_clock_source_t`, [1]_ you can only pick one of them. For the effect on power consumption of different clock source, please refer to `Power management <#power-management>`__ section.
|
||||
- :cpp:member:`gptimer_config_t::clk_src` selects the source clock for the timer. The available clocks are listed in :cpp:type:`gptimer_clock_source_t`, you can only pick one of them. For the effect on power consumption of different clock source, please refer to `Power management <#power-management>`__ section.
|
||||
|
||||
- :cpp:member:`gptimer_config_t::direction` sets the counting direction of the timer, supported directions are listed in :cpp:type:`gptimer_count_direction_t`, you can only pick one of them.
|
||||
|
||||
@ -50,7 +49,7 @@ With all the above configurations set in the structure, the structure can be pas
|
||||
|
||||
The function can fail due to various errors such as insufficient memory, invalid arguments, etc. Specifically, when there are no more free timers (i.e. all hardware resources have been used up), then :c:macro:`ESP_ERR_NOT_FOUND` will be returned. The total number of available timers is represented by the :c:macro:`SOC_TIMER_GROUP_TOTAL_TIMERS` and its value will depend on the ESP chip.
|
||||
|
||||
If a previously created GPTimer instance is no longer required, you should recycle the timer by calling :cpp:func:`gptimer_del_timer`. This will allow the underlying HW timer to be used for other purposes. Before deleting a GPTimer handle, you should stop it by :cpp:func:`gptimer_stop` in advance or make sure it has not started yet by :cpp:func:`gptimer_start`.
|
||||
If a previously created GPTimer instance is no longer required, you should recycle the timer by calling :cpp:func:`gptimer_del_timer`. This will allow the underlying HW timer to be used for other purposes. Before deleting a GPTimer handle, you should disable it by :cpp:func:`gptimer_disable` in advance or make sure it has not enabled yet by :cpp:func:`gptimer_enable`.
|
||||
|
||||
Creating a GPTimer Handle with Resolution of 1MHz
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -99,16 +98,30 @@ After the timer starts up, it can generate specific event (e.g. the "Alarm Event
|
||||
|
||||
One can save his own context to :cpp:func:`gptimer_register_event_callbacks` as well, via the parameter ``user_data``. The user data will be directly passed to the callback functions.
|
||||
|
||||
This function will lazy install interrupt service for the timer but not enable it. So user should call this function before :cpp:func:`gptimer_enable`, otherwise the :c:macro:`ESP_ERR_INVALID_STATE` error will be returned. See also `Enable and Disable timer <#enable-and-disable-timer>`__ for more information.
|
||||
|
||||
Enable and Disable Timer
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Before doing IO control to the timer, user needs to enable the timer first, by calling :cpp:func:`gptimer_enable`. Internally, this function will:
|
||||
|
||||
* switch the timer driver state from **init** to **enable**.
|
||||
* enable the interrupt service if it has been lazy installed by :cpp:func:`gptimer_register_event_callbacks`.
|
||||
* acquire a proper power management lock if a specific clock source (e.g. APB clock) is selected. See also `Power management <#power-management>`__ for more information.
|
||||
|
||||
On the contrary, calling :cpp:func:`gptimer_disable` will do the opposite, that is, put the timer driver back to the **init** state, disable the interrupts service and release the power management lock.
|
||||
|
||||
Start and Stop Timer
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To start a timer means to enable its internal counter, it can only be achieved by calling :cpp:func:`gptimer_start`. The timer can be stopped at any time (even in the interrupt context) by :cpp:func:`gptimer_stop`. One thing should be kept in mind, calling of :cpp:func:`gptimer_start` should have the same times of calling :cpp:func:`gptimer_stop` before you delete the timer, otherwise the driver might be put in an undetermined state. For example, the timer might keep a Power Management lock, which in return increase the power consumption. Also see `Power management <#power-management>`__ section.
|
||||
The basic IO operation of a timer is to start and stop. Calling :cpp:func:`gptimer_start` can make the internal counter work, while calling :cpp:func:`gptimer_stop` can make the counter stop working. The following will illustrate on how to start a timer with or without alarm event.
|
||||
|
||||
Start Timer As a Wall Clock
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
||||
// Retrieve timestamp at anytime
|
||||
uint64_t count;
|
||||
@ -150,7 +163,7 @@ Trigger Period Events
|
||||
.on_alarm = example_timer_on_alarm_cb, // register user callback
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
||||
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
||||
|
||||
Trigger One-Shot Event
|
||||
@ -187,6 +200,7 @@ Trigger One-Shot Event
|
||||
.on_alarm = example_timer_on_alarm_cb, // register user callback
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
||||
|
||||
Dynamic Alarm Update
|
||||
@ -228,6 +242,7 @@ Alarm value can be updated dynamically inside the ISR handler callback, by chang
|
||||
.on_alarm = example_timer_on_alarm_cb, // register user callback
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer, &alarm_config));
|
||||
|
||||
Power Management
|
||||
@ -235,7 +250,7 @@ Power Management
|
||||
|
||||
When power management is enabled (i.e. :ref:`CONFIG_PM_ENABLE` is on), the system will adjust the APB frequency before going into light sleep, thus potentially changing the period of a GPTimer's counting step and leading to inaccurate time keeping.
|
||||
|
||||
However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. Whenever the driver creates a GPTimer instance that has selected :cpp:enumerator:`GPTIMER_CLK_SRC_APB` as its clock source, the driver will guarantee that the power management lock is acquired when the timer is started by :cpp:func:`gptimer_start`. Likewise, the driver releases the lock when :cpp:func:`gptimer_stop` is called for that timer. This requires that the :cpp:func:`gptimer_start` and :cpp:func:`gptimer_stop` should appear in pairs.
|
||||
However, the driver can prevent the system from changing APB frequency by acquiring a power management lock of type :cpp:enumerator:`ESP_PM_APB_FREQ_MAX`. Whenever the driver creates a GPTimer instance that has selected :cpp:enumerator:`GPTIMER_CLK_SRC_APB` as its clock source, the driver will guarantee that the power management lock is acquired when enable the timer by :cpp:func:`gptimer_enable`. Likewise, the driver releases the lock when :cpp:func:`gptimer_disable` is called for that timer.
|
||||
|
||||
If the gptimer clock source is selected to others like :cpp:enumerator:`GPTIMER_CLK_SRC_XTAL`, then the driver won't install power management lock for it, which is more suitable for a low power application as long as the source clock can still provide sufficient resolution.
|
||||
|
||||
@ -247,9 +262,7 @@ By default, the GPTimer interrupt will be deferred when the Cache is disabled fo
|
||||
There's a Kconfig option :ref:`CONFIG_GPTIMER_ISR_IRAM_SAFE` that will:
|
||||
|
||||
1. Enable the interrupt being serviced even when cache is disabled
|
||||
|
||||
2. Place all functions that used by the ISR into IRAM [2]_
|
||||
|
||||
3. Place driver object into DRAM (in case it's mapped to PSRAM by accident)
|
||||
|
||||
This will allow the interrupt to run while the cache is disabled but will come at the cost of increased IRAM consumption.
|
||||
@ -295,7 +308,7 @@ API Reference
|
||||
.. include-build-file:: inc/timer_types.inc
|
||||
|
||||
.. [1]
|
||||
Some ESP chip might only support a sub-set of the clocks, if an unsupported clock source is specified, you will get a runtime error during timer installation.
|
||||
Different ESP chip series might have different numbers of GPTimer instances. Please refer to Chapter `Timer Group (TIMG) <{IDF_TARGET_TRM_EN_URL}#timg>`__ in {IDF_TARGET_NAME} Technical Reference Manual for more details. The driver won't forbid you from applying for more timers, but it will return error when all available hardware resources are used up. Please always check the return value when doing resource allocation (e.g. :cpp:func:`gptimer_new_timer`).
|
||||
|
||||
.. [2]
|
||||
:cpp:member:`gptimer_event_callbacks_t::on_alarm` callback and the functions invoked by itself should also be placed in IRAM, users need to take care of them by themselves.
|
||||
|
@ -58,10 +58,6 @@ static void iot_timer_start(gptimer_handle_t gptimer)
|
||||
.alarm_count = DUTY_SET_CYCLE / 1000 * GPTIMER_RESOLUTION_HZ,
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = fade_timercb,
|
||||
};
|
||||
gptimer_register_event_callbacks(gptimer, &cbs, NULL);
|
||||
gptimer_set_alarm_action(gptimer, &alarm_config);
|
||||
gptimer_start(gptimer);
|
||||
g_hw_timer_started = true;
|
||||
@ -336,6 +332,11 @@ esp_err_t iot_led_init(ledc_timer_t timer_num, ledc_mode_t speed_mode, uint32_t
|
||||
.resolution_hz = GPTIMER_RESOLUTION_HZ,
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &g_light_config->gptimer));
|
||||
gptimer_event_callbacks_t cbs = {
|
||||
.on_alarm = fade_timercb,
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(g_light_config->gptimer, &cbs, NULL));
|
||||
ESP_ERROR_CHECK(gptimer_enable(g_light_config->gptimer));
|
||||
} else {
|
||||
ESP_LOGE(TAG, "g_light_config has been initialized");
|
||||
}
|
||||
@ -349,8 +350,8 @@ esp_err_t iot_led_deinit(void)
|
||||
free(g_gamma_table);
|
||||
}
|
||||
|
||||
|
||||
if (g_light_config) {
|
||||
gptimer_disable(g_light_config->gptimer);
|
||||
gptimer_del_timer(g_light_config->gptimer);
|
||||
free(g_light_config);
|
||||
}
|
||||
|
@ -238,6 +238,7 @@ light_handle_t iot_light_create(ledc_timer_t timer, ledc_mode_t speed_mode, uint
|
||||
};
|
||||
gptimer_register_event_callbacks(light_ptr->gptimer, &cbs, NULL);
|
||||
gptimer_set_alarm_action(light_ptr->gptimer, &alarm_config);
|
||||
gptimer_enable(light_ptr->gptimer);
|
||||
gptimer_start(light_ptr->gptimer);
|
||||
g_hw_timer_started = true;
|
||||
}
|
||||
@ -285,6 +286,7 @@ esp_err_t iot_light_delete(light_handle_t light_handle)
|
||||
g_fade_installed = false;
|
||||
g_hw_timer_started = false;
|
||||
gptimer_stop(light->gptimer);
|
||||
gptimer_disable(light->gptimer);
|
||||
gptimer_del_timer(light->gptimer);
|
||||
FREE_MEM:
|
||||
free(light_handle);
|
||||
|
@ -245,6 +245,7 @@ void app_main(void)
|
||||
.flags.auto_reload_on_alarm = true,
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
||||
|
||||
printf("install console command line\r\n");
|
||||
|
@ -20,25 +20,31 @@ See the [ESP-IDF Getting Started Guide](https://idf.espressif.com/) for all the
|
||||
|
||||
```
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (323) example: Create timer handle
|
||||
I (323) example: Start timer, stop it at alarm event
|
||||
I (1333) example: Timer stopped, count=1000002
|
||||
I (1333) example: Set count value
|
||||
I (1333) example: Get count value
|
||||
I (1333) example: Timer count value=100
|
||||
I (1343) example: Start timer, auto-reload at alarm event
|
||||
I (2343) example: Timer reloaded, count=2
|
||||
I (3343) example: Timer reloaded, count=2
|
||||
I (4343) example: Timer reloaded, count=2
|
||||
I (5343) example: Timer reloaded, count=2
|
||||
I (5343) example: Stop timer
|
||||
I (5343) example: Update alarm value dynamically
|
||||
I (6353) example: Timer alarmed, count=1000002
|
||||
I (7353) example: Timer alarmed, count=2000002
|
||||
I (8353) example: Timer alarmed, count=3000002
|
||||
I (9353) example: Timer alarmed, count=4000002
|
||||
I (9353) example: Stop timer
|
||||
I (9353) example: Delete timer
|
||||
I (326) example: Create timer handle
|
||||
I (326) example: Enable timer
|
||||
I (336) example: Start timer, stop it at alarm event
|
||||
I (1336) example: Timer stopped, count=1000002
|
||||
I (1336) example: Set count value
|
||||
I (1336) example: Get count value
|
||||
I (1346) example: Timer count value=100
|
||||
I (1346) example: Disable timer
|
||||
I (1346) example: Enable timer
|
||||
I (1356) example: Start timer, auto-reload at alarm event
|
||||
I (2356) example: Timer reloaded, count=2
|
||||
I (3356) example: Timer reloaded, count=2
|
||||
I (4356) example: Timer reloaded, count=2
|
||||
I (5356) example: Timer reloaded, count=2
|
||||
I (5356) example: Stop timer
|
||||
I (5356) example: Disable timer
|
||||
I (5356) example: Enable timer
|
||||
I (5366) example: Start timer, update alarm value dynamically
|
||||
I (6366) example: Timer alarmed, count=1000002
|
||||
I (7366) example: Timer alarmed, count=2000002
|
||||
I (8366) example: Timer alarmed, count=3000002
|
||||
I (9366) example: Timer alarmed, count=4000002
|
||||
I (9376) example: Stop timer
|
||||
I (9376) example: Disable timer
|
||||
I (9376) example: Delete timer
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
@ -86,6 +86,9 @@ void app_main(void)
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
||||
|
||||
ESP_LOGI(TAG, "Enable timer");
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
|
||||
ESP_LOGI(TAG, "Start timer, stop it at alarm event");
|
||||
gptimer_alarm_config_t alarm_config1 = {
|
||||
.alarm_count = 1000000, // period = 1s
|
||||
@ -105,9 +108,16 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(gptimer_get_raw_count(gptimer, &count));
|
||||
ESP_LOGI(TAG, "Timer count value=%llu", count);
|
||||
|
||||
ESP_LOGI(TAG, "Start timer, auto-reload at alarm event");
|
||||
// before updating the alarm callback, we should make sure the timer is not in the enable state
|
||||
ESP_LOGI(TAG, "Disable timer");
|
||||
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
||||
// set a new callback function
|
||||
cbs.on_alarm = example_timer_on_alarm_cb_v2;
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
||||
ESP_LOGI(TAG, "Enable timer");
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
|
||||
ESP_LOGI(TAG, "Start timer, auto-reload at alarm event");
|
||||
gptimer_alarm_config_t alarm_config2 = {
|
||||
.reload_count = 0,
|
||||
.alarm_count = 1000000, // period = 1s
|
||||
@ -124,13 +134,17 @@ void app_main(void)
|
||||
ESP_LOGW(TAG, "Missed one count event");
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Stop timer");
|
||||
ESP_ERROR_CHECK(gptimer_stop(gptimer));
|
||||
|
||||
ESP_LOGI(TAG, "Update alarm value dynamically");
|
||||
ESP_LOGI(TAG, "Disable timer");
|
||||
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
||||
cbs.on_alarm = example_timer_on_alarm_cb_v3;
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, queue));
|
||||
ESP_LOGI(TAG, "Enable timer");
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
|
||||
ESP_LOGI(TAG, "Start timer, update alarm value dynamically");
|
||||
gptimer_alarm_config_t alarm_config3 = {
|
||||
.alarm_count = 1000000, // period = 1s
|
||||
};
|
||||
@ -148,6 +162,8 @@ void app_main(void)
|
||||
|
||||
ESP_LOGI(TAG, "Stop timer");
|
||||
ESP_ERROR_CHECK(gptimer_stop(gptimer));
|
||||
ESP_LOGI(TAG, "Disable timer");
|
||||
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
||||
ESP_LOGI(TAG, "Delete timer");
|
||||
ESP_ERROR_CHECK(gptimer_del_timer(gptimer));
|
||||
|
||||
|
@ -26,7 +26,7 @@ def test_gptimer_example(dut: Dut) -> None:
|
||||
assert 0 <= int(reloaded_count) < 10
|
||||
|
||||
dut.expect_exact('Stop timer')
|
||||
dut.expect_exact('Update alarm value dynamically')
|
||||
dut.expect_exact('Start timer, update alarm value dynamically')
|
||||
for i in range(1,5):
|
||||
res = dut.expect(r'Timer alarmed, count=(\d+)', timeout=5)
|
||||
alarm_count = res.group(1).decode('utf8')
|
||||
|
@ -116,6 +116,7 @@ void app_main(void)
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, raw_val));
|
||||
ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
||||
|
||||
while (1) {
|
||||
|
@ -63,6 +63,7 @@ static void eventfd_timer_init(void)
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(s_gptimer, &cbs, NULL));
|
||||
ESP_ERROR_CHECK(gptimer_set_alarm_action(s_gptimer, &alarm_config));
|
||||
ESP_ERROR_CHECK(gptimer_enable(s_gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(s_gptimer));
|
||||
}
|
||||
|
||||
@ -150,6 +151,7 @@ static void collector_task(void *arg)
|
||||
}
|
||||
|
||||
gptimer_stop(s_gptimer);
|
||||
gptimer_disable(s_gptimer);
|
||||
gptimer_del_timer(s_gptimer);
|
||||
close(s_timer_fd);
|
||||
close(s_progress_fd);
|
||||
|
@ -115,7 +115,7 @@ void app_main(void)
|
||||
};
|
||||
bool is_flash = true;
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, &is_flash));
|
||||
|
||||
ESP_ERROR_CHECK(gptimer_enable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(gptimer));
|
||||
|
||||
uint32_t erase_time = 0;
|
||||
@ -145,5 +145,6 @@ void app_main(void)
|
||||
ESP_LOGI(TAG, "During Erase, ISR callback function(in iram) response time:\n\t\t%0.2f us", GET_US_BY_CCOUNT(s_iram_func_t2 - s_t1));
|
||||
|
||||
ESP_LOGI(TAG, "Finish");
|
||||
ESP_ERROR_CHECK(gptimer_disable(gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_del_timer(gptimer));
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ static void example_task(void *p)
|
||||
};
|
||||
ESP_ERROR_CHECK(gptimer_register_event_callbacks(arg->gptimer, &cbs, arg));
|
||||
ESP_ERROR_CHECK(gptimer_set_alarm_action(arg->gptimer, &alarm_config));
|
||||
ESP_ERROR_CHECK(gptimer_enable(arg->gptimer));
|
||||
ESP_ERROR_CHECK(gptimer_start(arg->gptimer));
|
||||
while (1) {
|
||||
SYSVIEW_EXAMPLE_WAIT_EVENT_START();
|
||||
|
@ -18,12 +18,14 @@ void ref_clock_init(void)
|
||||
.resolution_hz = 1000000, // Resolution is configured to 1MHz
|
||||
};
|
||||
TEST_ESP_OK(gptimer_new_timer(&timer_config, &ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_enable(ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_start(ts_gptimer));
|
||||
}
|
||||
|
||||
void ref_clock_deinit(void)
|
||||
{
|
||||
TEST_ESP_OK(gptimer_stop(ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_disable(ts_gptimer));
|
||||
TEST_ESP_OK(gptimer_del_timer(ts_gptimer));
|
||||
ts_gptimer = NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user