mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/driver_ng_enable_disable_logic' into 'master'
driver_ng: added explicit enable/disable functions Closes IDF-4204 See merge request espressif/esp-idf!17885
This commit is contained in:
commit
06e071ba4b
@ -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);
|
||||
|
@ -86,7 +86,7 @@ typedef struct {
|
||||
/**
|
||||
* @brief Create a new PCNT unit, and return the handle
|
||||
*
|
||||
* @note The newly created PCNT unit is put into the stopped state.
|
||||
* @note The newly created PCNT unit is put in the init state.
|
||||
*
|
||||
* @param[in] config PCNT unit configuration
|
||||
* @param[out] ret_unit Returned PCNT unit handle
|
||||
@ -102,13 +102,14 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
|
||||
/**
|
||||
* @brief Delete the PCNT unit handle
|
||||
*
|
||||
* @note Users must ensure that the PCNT unit is stopped before deleting the unit. Users can force a working unit into the stopped state via `pcnt_unit_stop()`.
|
||||
* @note A PCNT unit can't be in the enable state when this function is invoked.
|
||||
* See also `pcnt_unit_disable()` for how to disable a unit.
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @return
|
||||
* - ESP_OK: Delete the PCNT unit successfully
|
||||
* - ESP_ERR_INVALID_ARG: Delete the PCNT unit failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Delete the PCNT unit failed because corresponding PCNT channels and/or watch points are still in working
|
||||
* - ESP_ERR_INVALID_STATE: Delete the PCNT unit failed because the unit is not in init state or some PCNT channel is still in working
|
||||
* - ESP_FAIL: Delete the PCNT unit failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit);
|
||||
@ -118,29 +119,63 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit);
|
||||
*
|
||||
* @note The glitch filter module is clocked from APB, and APB frequency can be changed during DFS, which in return make the filter out of action.
|
||||
* So this function will lazy-install a PM lock internally when the power management is enabled. With this lock, the APB frequency won't be changed.
|
||||
* The PM lock can only be uninstalled in `pcnt_del_unit()`.
|
||||
* The PM lock can be uninstalled in `pcnt_del_unit()`.
|
||||
* @note This function should be called when the PCNT unit is in the init state (i.e. before calling `pcnt_unit_enable()`)
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @param[in] config PCNT filter configuration, set config to NULL means disabling the filter function
|
||||
* @return
|
||||
* - ESP_OK: Set glitch filter successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set glitch filter failed because of invalid argument (e.g. glitch width is too big)
|
||||
* - ESP_ERR_INVALID_STATE: Set glitch filter failed because the unit is not in the init state
|
||||
* - ESP_FAIL: Set glitch filter failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_set_glitch_filter(pcnt_unit_handle_t unit, const pcnt_glitch_filter_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Enable the PCNT unit
|
||||
*
|
||||
* @note This function will transit the unit state from init to enable.
|
||||
* @note This function will enable the interrupt service, if it's lazy installed in `pcnt_unit_register_event_callbacks()`.
|
||||
* @note This function will acquire the PM lock if it's lazy installed in `pcnt_unit_set_glitch_filter()`.
|
||||
* @note Enable a PCNT unit doesn't mean to start it. See also `pcnt_unit_start()` for how to start the PCNT counter.
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @return
|
||||
* - ESP_OK: Enable PCNT unit successfully
|
||||
* - ESP_ERR_INVALID_ARG: Enable PCNT unit failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Enable PCNT unit failed because the unit is already enabled
|
||||
* - ESP_FAIL: Enable PCNT unit failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_enable(pcnt_unit_handle_t unit);
|
||||
|
||||
/**
|
||||
* @brief Disable the PCNT unit
|
||||
*
|
||||
* @note This function will do the opposite work to the `pcnt_unit_enable()`
|
||||
* @note Disable a PCNT unit doesn't mean to stop it. See also `pcnt_unit_stop()` for how to stop the PCNT counter.
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @return
|
||||
* - ESP_OK: Disable PCNT unit successfully
|
||||
* - ESP_ERR_INVALID_ARG: Disable PCNT unit failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Disable PCNT unit failed because the unit is not enabled yet
|
||||
* - ESP_FAIL: Disable PCNT unit failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_disable(pcnt_unit_handle_t unit);
|
||||
|
||||
/**
|
||||
* @brief Start the PCNT unit, the counter will start to count according to the edge and/or level input signals
|
||||
*
|
||||
* @note This function will acquire the PM lock when power management is enabled. Also see `pcnt_unit_set_glitch_filter()` for the condition of PM lock installation.
|
||||
* @note The number of calls to this function should be equal to the number of calls to `pcnt_unit_stop()`.
|
||||
* @note This function should be called when the unit is in the enable state (i.e. after calling `pcnt_unit_enable()`)
|
||||
* @note This function is allowed to run within ISR context
|
||||
* @note This function will be placed into IRAM if `CONFIG_PCNT_CTRL_FUNC_IN_IRAM`, so that it's allowed to be executed when Cache is disabled
|
||||
* @note This function will be placed into IRAM if `CONFIG_PCNT_CTRL_FUNC_IN_IRAM` is on, so that it's allowed to be executed when Cache is disabled
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @return
|
||||
* - ESP_OK: Start PCNT unit successfully
|
||||
* - ESP_ERR_INVALID_ARG: Start PCNT unit failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Start PCNT unit failed because the unit is not enabled yet
|
||||
* - ESP_FAIL: Start PCNT unit failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_start(pcnt_unit_handle_t unit);
|
||||
@ -148,10 +183,8 @@ esp_err_t pcnt_unit_start(pcnt_unit_handle_t unit);
|
||||
/**
|
||||
* @brief Stop PCNT from counting
|
||||
*
|
||||
* @note If power management is enabled, this function will release the PM lock acquired in `pcnt_unit_start()`.
|
||||
* Also see `pcnt_unit_set_glitch_filter()` for the condition of PM lock installation.
|
||||
* @note This function should be called when the unit is in the enable state (i.e. after calling `pcnt_unit_enable()`)
|
||||
* @note The stop operation won't clear the counter. Also see `pcnt_unit_clear_count()` for how to clear pulse count value.
|
||||
* @note The number of calls to this function should be equal to the number of calls to `pcnt_unit_start()`.
|
||||
* @note This function is allowed to run within ISR context
|
||||
* @note This function will be placed into IRAM if `CONFIG_PCNT_CTRL_FUNC_IN_IRAM`, so that it is allowed to be executed when Cache is disabled
|
||||
*
|
||||
@ -159,6 +192,7 @@ esp_err_t pcnt_unit_start(pcnt_unit_handle_t unit);
|
||||
* @return
|
||||
* - ESP_OK: Stop PCNT unit successfully
|
||||
* - ESP_ERR_INVALID_ARG: Stop PCNT unit failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Stop PCNT unit failed because the unit is not enabled yet
|
||||
* - ESP_FAIL: Stop PCNT unit failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_stop(pcnt_unit_handle_t unit);
|
||||
@ -196,7 +230,8 @@ esp_err_t pcnt_unit_get_count(pcnt_unit_handle_t unit, int *value);
|
||||
/**
|
||||
* @brief Set event callbacks for PCNT unit
|
||||
*
|
||||
* @note User can deregister the previous callback by calling this function with an empty `cbs`.
|
||||
* @note User registered callbacks are expected to be runnable within ISR context
|
||||
* @note This function is only allowed to be called when the unit is in the init state (i.e. before calling `pcnt_unit_enable()`)
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @param[in] cbs Group of callback functions
|
||||
@ -204,6 +239,7 @@ esp_err_t pcnt_unit_get_count(pcnt_unit_handle_t unit, int *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 unit is not in init state
|
||||
* - ESP_FAIL: Set event callbacks failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt_event_callbacks_t *cbs, void *user_data);
|
||||
@ -211,8 +247,6 @@ esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt
|
||||
/**
|
||||
* @brief Add a watch point for PCNT unit, PCNT will generate an event when the counter value reaches the watch point value
|
||||
*
|
||||
* @note The number of calls to this function should be equal to the number of calls to `pcnt_unit_remove_watch_point()`, otherwise the unit can't be deleted
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @param[in] watch_point Value to be watched
|
||||
* @return
|
||||
@ -227,8 +261,6 @@ esp_err_t pcnt_unit_add_watch_point(pcnt_unit_handle_t unit, int watch_point);
|
||||
/**
|
||||
* @brief Remove a watch point for PCNT unit
|
||||
*
|
||||
* @note The number of calls to this function should be equal to the number of calls to `pcnt_unit_add_watch_point()`, otherwise the unit can't be deleted
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @param[in] watch_point Watch point value
|
||||
* @return
|
||||
@ -242,6 +274,8 @@ esp_err_t pcnt_unit_remove_watch_point(pcnt_unit_handle_t unit, int watch_point)
|
||||
/**
|
||||
* @brief Create PCNT channel for specific unit, each PCNT has several channels associated with it
|
||||
*
|
||||
* @note This function should be called when the unit is in init state (i.e. before calling `pcnt_unit_enable()`)
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @param[in] config PCNT channel configuration
|
||||
* @param[out] ret_chan Returned channel handle
|
||||
@ -250,6 +284,7 @@ esp_err_t pcnt_unit_remove_watch_point(pcnt_unit_handle_t unit, int watch_point)
|
||||
* - ESP_ERR_INVALID_ARG: Create PCNT channel failed because of invalid argument
|
||||
* - ESP_ERR_NO_MEM: Create PCNT channel failed because of insufficient memory
|
||||
* - ESP_ERR_NOT_FOUND: Create PCNT channel failed because all PCNT channels are used up and no more free one
|
||||
* - ESP_ERR_INVALID_STATE: Create PCNT channel failed because the unit is not in the init state
|
||||
* - ESP_FAIL: Create PCNT channel failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_new_channel(pcnt_unit_handle_t unit, const pcnt_chan_config_t *config, pcnt_channel_handle_t *ret_chan);
|
||||
|
@ -61,24 +61,24 @@ esp_err_t temperature_sensor_install(const temperature_sensor_config_t *tsens_co
|
||||
esp_err_t temperature_sensor_uninstall(temperature_sensor_handle_t tsens);
|
||||
|
||||
/**
|
||||
* @brief Start temperature measurement.
|
||||
* @brief Enable the temperature sensor
|
||||
*
|
||||
* @param tsens The handle created by `temperature_sensor_install()`.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE if temperature sensor is started already.
|
||||
* - ESP_ERR_INVALID_STATE if temperature sensor is enabled already.
|
||||
*/
|
||||
esp_err_t temperature_sensor_start(temperature_sensor_handle_t tsens);
|
||||
esp_err_t temperature_sensor_enable(temperature_sensor_handle_t tsens);
|
||||
|
||||
/**
|
||||
* @brief Stop temperature sensor measure.
|
||||
* @brief Disable temperature sensor
|
||||
*
|
||||
* @param tsens The handle created by `temperature_sensor_install()`.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_STATE if temperature sensor is stopped already.
|
||||
* - ESP_ERR_INVALID_STATE if temperature sensor is not enabled yet.
|
||||
*/
|
||||
esp_err_t temperature_sensor_stop(temperature_sensor_handle_t tsens);
|
||||
esp_err_t temperature_sensor_disable(temperature_sensor_handle_t tsens);
|
||||
|
||||
/**
|
||||
* @brief Read temperature sensor data that is converted to degrees Celsius.
|
||||
@ -88,8 +88,9 @@ esp_err_t temperature_sensor_stop(temperature_sensor_handle_t tsens);
|
||||
* @param out_celsius The measure output value.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG ARG is NULL.
|
||||
* - ESP_ERR_INVALID_STATE The ambient temperature is out of range.
|
||||
* - ESP_ERR_INVALID_ARG invalid arguments
|
||||
* - ESP_ERR_INVALID_STATE Temperature sensor is not enabled yet.
|
||||
* - ESP_FAIL Parse the sensor data into ambient temperature failed (e.g. out of the range).
|
||||
*/
|
||||
esp_err_t temperature_sensor_get_celsius(temperature_sensor_handle_t tsens, float *out_celsius);
|
||||
|
||||
|
@ -72,9 +72,9 @@ typedef struct {
|
||||
} pcnt_watch_point_t;
|
||||
|
||||
typedef enum {
|
||||
PCNT_FSM_STOP,
|
||||
PCNT_FSM_START,
|
||||
} pcnt_lifecycle_fsm_t;
|
||||
PCNT_UNIT_FSM_INIT,
|
||||
PCNT_UNIT_FSM_ENABLE,
|
||||
} pcnt_unit_fsm_t;
|
||||
|
||||
struct pcnt_unit_t {
|
||||
pcnt_group_t *group; // which group the pcnt unit belongs to
|
||||
@ -89,7 +89,7 @@ struct pcnt_unit_t {
|
||||
#if CONFIG_PM_ENABLE
|
||||
char pm_lock_name[PCNT_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||
#endif
|
||||
pcnt_lifecycle_fsm_t fsm; // access to fsm should be protect by spinlock, as fsm can also accessed from ISR handler
|
||||
pcnt_unit_fsm_t fsm; // record PCNT unit's driver state
|
||||
pcnt_watch_cb_t on_reach; // user registered callback function
|
||||
void *user_data; // user data registered by user, which would be passed to the right callback function
|
||||
};
|
||||
@ -152,8 +152,6 @@ static void pcnt_unregister_from_group(pcnt_unit_t *unit)
|
||||
static esp_err_t pcnt_destory(pcnt_unit_t *unit)
|
||||
{
|
||||
if (unit->pm_lock) {
|
||||
// if pcnt_unit_start and pcnt_unit_stop are not called the same number of times, deleting pm_lock will return invalid state
|
||||
// which in return also reflects an invalid state of PCNT driver
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(unit->pm_lock), TAG, "delete pm lock failed");
|
||||
}
|
||||
if (unit->intr) {
|
||||
@ -206,7 +204,7 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
|
||||
unit->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
unit->fsm = PCNT_FSM_STOP;
|
||||
unit->fsm = PCNT_UNIT_FSM_INIT;
|
||||
for (int i = 0; i < PCNT_LL_WATCH_EVENT_MAX; i++) {
|
||||
unit->watchers[i].event_id = PCNT_LL_WATCH_EVENT_INVALID; // invalid all watch point
|
||||
}
|
||||
@ -224,23 +222,14 @@ err:
|
||||
esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
|
||||
pcnt_group_t *group = unit->group;
|
||||
int group_id = group->group_id;
|
||||
int unit_id = unit->unit_id;
|
||||
|
||||
bool valid_state = true;
|
||||
portENTER_CRITICAL(&unit->spinlock);
|
||||
valid_state = unit->fsm == PCNT_FSM_STOP;
|
||||
portEXIT_CRITICAL(&unit->spinlock);
|
||||
ESP_RETURN_ON_FALSE(valid_state, ESP_ERR_INVALID_STATE, TAG, "can't delete unit as it's not stop yet");
|
||||
|
||||
for (int i = 0; i < SOC_PCNT_CHANNELS_PER_UNIT; i++) {
|
||||
ESP_RETURN_ON_FALSE(!unit->channels[i], ESP_ERR_INVALID_STATE, TAG, "channel %d still in working", i);
|
||||
}
|
||||
for (int i = 0; i < PCNT_LL_WATCH_EVENT_MAX; i++) {
|
||||
ESP_RETURN_ON_FALSE(unit->watchers[i].event_id == PCNT_LL_WATCH_EVENT_INVALID, ESP_ERR_INVALID_STATE, TAG,
|
||||
"watch point %d still in working", unit->watchers[i].watch_point_value);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "del unit (%d,%d)", group_id, unit_id);
|
||||
// recycle memory resource
|
||||
@ -253,6 +242,8 @@ esp_err_t pcnt_unit_set_glitch_filter(pcnt_unit_handle_t unit, const pcnt_glitch
|
||||
pcnt_group_t *group = NULL;
|
||||
uint32_t glitch_filter_thres = 0;
|
||||
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
// glitch filter should be set only when unit is in init state
|
||||
ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
|
||||
group = unit->group;
|
||||
if (config) {
|
||||
glitch_filter_thres = esp_clk_apb_freq() / 1000000 * config->max_glitch_ns / 1000;
|
||||
@ -281,57 +272,67 @@ esp_err_t pcnt_unit_set_glitch_filter(pcnt_unit_handle_t unit, const pcnt_glitch
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_unit_start(pcnt_unit_handle_t unit)
|
||||
esp_err_t pcnt_unit_enable(pcnt_unit_handle_t unit)
|
||||
{
|
||||
pcnt_group_t *group = NULL;
|
||||
ESP_RETURN_ON_FALSE_ISR(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
group = unit->group;
|
||||
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
|
||||
|
||||
// acquire power manager lock
|
||||
if (unit->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_pm_lock_acquire(unit->pm_lock), TAG, "acquire APB_FREQ_MAX lock failed");
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(unit->pm_lock), TAG, "acquire pm_lock failed");
|
||||
}
|
||||
// enable interupt service
|
||||
if (unit->intr) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_intr_enable(unit->intr), TAG, "enable interrupt service failed");
|
||||
ESP_RETURN_ON_ERROR(esp_intr_enable(unit->intr), TAG, "enable interrupt service failed");
|
||||
}
|
||||
|
||||
unit->fsm = PCNT_UNIT_FSM_ENABLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_unit_disable(pcnt_unit_handle_t unit)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(unit->fsm = PCNT_UNIT_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "unit not in enable state");
|
||||
|
||||
// disable interrupt service
|
||||
if (unit->intr) {
|
||||
ESP_RETURN_ON_ERROR(esp_intr_disable(unit->intr), TAG, "disable interrupt service failed");
|
||||
}
|
||||
// release power manager lock
|
||||
if (unit->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR(esp_pm_lock_release(unit->pm_lock), TAG, "release APB_FREQ_MAX lock failed");
|
||||
}
|
||||
|
||||
unit->fsm = PCNT_UNIT_FSM_INIT;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_unit_start(pcnt_unit_handle_t unit)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE_ISR(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE_ISR(unit->fsm == PCNT_UNIT_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "unit not enabled yet");
|
||||
pcnt_group_t *group = unit->group;
|
||||
|
||||
// all PCNT units share the same register to control counter
|
||||
portENTER_CRITICAL_SAFE(&group->spinlock);
|
||||
pcnt_ll_start_count(group->hal.dev, unit->unit_id);
|
||||
portEXIT_CRITICAL_SAFE(&group->spinlock);
|
||||
|
||||
portENTER_CRITICAL_SAFE(&unit->spinlock);
|
||||
unit->fsm = PCNT_FSM_START;
|
||||
portEXIT_CRITICAL_SAFE(&unit->spinlock);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t pcnt_unit_stop(pcnt_unit_handle_t unit)
|
||||
{
|
||||
pcnt_group_t *group = NULL;
|
||||
ESP_RETURN_ON_FALSE_ISR(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
group = unit->group;
|
||||
ESP_RETURN_ON_FALSE_ISR(unit->fsm == PCNT_UNIT_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "unit not enabled yet");
|
||||
pcnt_group_t *group = unit->group;
|
||||
|
||||
// all PCNT units share the same register to control counter
|
||||
portENTER_CRITICAL_SAFE(&group->spinlock);
|
||||
pcnt_ll_stop_count(group->hal.dev, unit->unit_id);
|
||||
portEXIT_CRITICAL_SAFE(&group->spinlock);
|
||||
|
||||
portENTER_CRITICAL_SAFE(&unit->spinlock);
|
||||
unit->fsm = PCNT_FSM_STOP;
|
||||
portEXIT_CRITICAL_SAFE(&unit->spinlock);
|
||||
|
||||
// disable interrupt service
|
||||
if (unit->intr) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_intr_disable(unit->intr), TAG, "disable interrupt service failed");
|
||||
}
|
||||
// release power manager lock
|
||||
if (unit->pm_lock) {
|
||||
ESP_RETURN_ON_ERROR_ISR(esp_pm_lock_release(unit->pm_lock), TAG, "release APB_FREQ_MAX lock failed");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -361,9 +362,10 @@ esp_err_t pcnt_unit_get_count(pcnt_unit_handle_t unit, int *value)
|
||||
|
||||
esp_err_t pcnt_unit_register_event_callbacks(pcnt_unit_handle_t unit, const pcnt_event_callbacks_t *cbs, void *user_data)
|
||||
{
|
||||
pcnt_group_t *group = NULL;
|
||||
ESP_RETURN_ON_FALSE(unit && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
group = unit->group;
|
||||
// unit event callbacks should be registered in init state
|
||||
ESP_RETURN_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "unit not in init state");
|
||||
pcnt_group_t *group = unit->group;
|
||||
int group_id = group->group_id;
|
||||
int unit_id = unit->unit_id;
|
||||
|
||||
@ -520,6 +522,7 @@ esp_err_t pcnt_new_channel(pcnt_unit_handle_t unit, const pcnt_chan_config_t *co
|
||||
pcnt_chan_t *channel = NULL;
|
||||
pcnt_group_t *group = NULL;
|
||||
ESP_GOTO_ON_FALSE(unit && config && ret_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_GOTO_ON_FALSE(unit->fsm == PCNT_UNIT_FSM_INIT, ESP_ERR_INVALID_STATE, err, TAG, "unit not in init state");
|
||||
group = unit->group;
|
||||
int group_id = group->group_id;
|
||||
int unit_id = unit->unit_id;
|
||||
|
@ -1,19 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_TEMP_SENSOR_ENABLE_DEBUG_LOG
|
||||
// The local log level must be defined before including esp_log.h
|
||||
// Set the maximum log level for this source file
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "sys/lock.h"
|
||||
#include "soc/rtc.h"
|
||||
@ -25,7 +24,6 @@
|
||||
#include "driver/temperature_sensor.h"
|
||||
#include "esp_efuse_rtc_calib.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "hal/temperature_sensor_types.h"
|
||||
#include "hal/temperature_sensor_ll.h"
|
||||
|
||||
static const char *TAG = "temperature_sensor";
|
||||
@ -35,10 +33,9 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
|
||||
#define TEMPERATURE_SENSOR_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
|
||||
|
||||
typedef enum {
|
||||
TSENS_HW_STATE_UNCONFIGURED,
|
||||
TSENS_HW_STATE_CONFIGURED,
|
||||
TSENS_HW_STATE_STARTED,
|
||||
} temp_sensor_state_t;
|
||||
TEMP_SENSOR_FSM_INIT,
|
||||
TEMP_SENSOR_FSM_ENABLE,
|
||||
} temp_sensor_fsm_t;
|
||||
|
||||
static float s_deltaT = NAN; // unused number
|
||||
|
||||
@ -46,7 +43,7 @@ typedef struct temperature_sensor_obj_t temperature_sensor_obj_t;
|
||||
|
||||
struct temperature_sensor_obj_t {
|
||||
const temp_sensor_ll_attribute_t *tsens_attribute;
|
||||
temp_sensor_state_t tsens_hw_state;
|
||||
temp_sensor_fsm_t fsm;
|
||||
temperature_sensor_clk_src_t clk_src;
|
||||
};
|
||||
|
||||
@ -89,9 +86,9 @@ esp_err_t temperature_sensor_install(const temperature_sensor_config_t *tsens_co
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_RETURN_ON_FALSE((tsens_config && ret_tsens), ESP_ERR_INVALID_ARG, TAG, "Invalid argument");
|
||||
ESP_RETURN_ON_FALSE((s_tsens_attribute_copy == NULL), ESP_ERR_INVALID_STATE, TAG, "Already installed");
|
||||
temperature_sensor_handle_t tsens;
|
||||
temperature_sensor_handle_t tsens = NULL;
|
||||
tsens = (temperature_sensor_obj_t *) heap_caps_calloc(1, sizeof(temperature_sensor_obj_t), MALLOC_CAP_DEFAULT);
|
||||
ESP_GOTO_ON_FALSE(tsens != NULL, ESP_ERR_NO_MEM, err, TAG, "install fail...");
|
||||
ESP_GOTO_ON_FALSE(tsens != NULL, ESP_ERR_NO_MEM, err, TAG, "no mem for temp sensor");
|
||||
tsens->clk_src = tsens_config->clk_src;
|
||||
|
||||
periph_module_enable(PERIPH_TEMPSENSOR_MODULE);
|
||||
@ -103,10 +100,13 @@ esp_err_t temperature_sensor_install(const temperature_sensor_config_t *tsens_co
|
||||
tsens->tsens_attribute->range_min,
|
||||
tsens->tsens_attribute->range_max,
|
||||
tsens->tsens_attribute->error_max);
|
||||
|
||||
TEMPERATURE_SENSOR_ENTER_CRITICAL();
|
||||
temperature_sensor_ll_set_range(tsens->tsens_attribute->reg_val);
|
||||
temperature_sensor_ll_enable(false); // disable the sensor by default
|
||||
TEMPERATURE_SENSOR_EXIT_CRITICAL();
|
||||
tsens->tsens_hw_state = TSENS_HW_STATE_CONFIGURED;
|
||||
|
||||
tsens->fsm = TEMP_SENSOR_FSM_INIT;
|
||||
*ret_tsens = tsens;
|
||||
return ESP_OK;
|
||||
err:
|
||||
@ -116,52 +116,50 @@ err:
|
||||
|
||||
esp_err_t temperature_sensor_uninstall(temperature_sensor_handle_t tsens)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "Has already been uninstalled");
|
||||
ESP_RETURN_ON_FALSE(tsens->tsens_hw_state != TSENS_HW_STATE_STARTED, ESP_ERR_INVALID_STATE, TAG, "Has not been stopped");
|
||||
ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "tsens not in init state");
|
||||
|
||||
if (s_tsens_attribute_copy) {
|
||||
free(s_tsens_attribute_copy);
|
||||
}
|
||||
s_tsens_attribute_copy = NULL;
|
||||
tsens->tsens_hw_state = TSENS_HW_STATE_UNCONFIGURED;
|
||||
heap_caps_free(tsens);
|
||||
tsens = NULL;
|
||||
|
||||
periph_module_disable(PERIPH_TEMPSENSOR_MODULE);
|
||||
free(tsens);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temperature_sensor_start(temperature_sensor_handle_t tsens)
|
||||
esp_err_t temperature_sensor_enable(temperature_sensor_handle_t tsens)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "Has not been installed");
|
||||
ESP_RETURN_ON_FALSE(tsens->tsens_hw_state == TSENS_HW_STATE_CONFIGURED, ESP_ERR_INVALID_STATE, TAG, "Is already running or has not been configured");
|
||||
ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "tsens not in init state");
|
||||
|
||||
#if SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
|
||||
if (tsens->clk_src == TEMPERATURE_SENSOR_CLK_SRC_RC_FAST) {
|
||||
periph_rtc_dig_clk8m_enable();
|
||||
}
|
||||
#endif
|
||||
|
||||
temperature_sensor_ll_clk_enable(true);
|
||||
temperature_sensor_ll_clk_sel(tsens->clk_src);
|
||||
temperature_sensor_ll_enable(true);
|
||||
tsens->tsens_hw_state = TSENS_HW_STATE_STARTED;
|
||||
tsens->fsm = TEMP_SENSOR_FSM_ENABLE;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t temperature_sensor_stop(temperature_sensor_handle_t tsens)
|
||||
esp_err_t temperature_sensor_disable(temperature_sensor_handle_t tsens)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tsens->tsens_hw_state == TSENS_HW_STATE_STARTED, ESP_ERR_INVALID_STATE, TAG, "Has not been started");
|
||||
ESP_RETURN_ON_FALSE(tsens, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "tsens not enabled yet");
|
||||
|
||||
temperature_sensor_ll_enable(false);
|
||||
#if SOC_TEMPERATURE_SENSOR_SUPPORT_FAST_RC
|
||||
if (tsens->clk_src == TEMPERATURE_SENSOR_CLK_SRC_RC_FAST) {
|
||||
periph_rtc_dig_clk8m_disable();
|
||||
}
|
||||
#endif
|
||||
periph_module_disable(PERIPH_TEMPSENSOR_MODULE);
|
||||
tsens->tsens_hw_state = TSENS_HW_STATE_CONFIGURED;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t temp_sensor_read_raw(uint32_t *tsens_out)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(tsens_out != NULL, ESP_ERR_INVALID_ARG, TAG, "No tsens_out specified");
|
||||
*tsens_out = temperature_sensor_ll_get_raw_value();
|
||||
tsens->fsm = TEMP_SENSOR_FSM_INIT;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -187,14 +185,15 @@ esp_err_t temperature_sensor_get_celsius(temperature_sensor_handle_t tsens, floa
|
||||
{
|
||||
ESP_RETURN_ON_FALSE((tsens != NULL), ESP_ERR_INVALID_ARG, TAG, "Has not been installed");
|
||||
ESP_RETURN_ON_FALSE(out_celsius != NULL, ESP_ERR_INVALID_ARG, TAG, "Celsius points to nothing");
|
||||
ESP_RETURN_ON_FALSE(tsens->tsens_hw_state == TSENS_HW_STATE_STARTED, ESP_ERR_INVALID_ARG, TAG, "Has not been started");
|
||||
uint32_t tsens_out = 0;
|
||||
temp_sensor_read_raw(&tsens_out);
|
||||
ESP_RETURN_ON_FALSE(tsens->fsm == TEMP_SENSOR_FSM_ENABLE, ESP_ERR_INVALID_STATE, TAG, "tsens not enabled yet");
|
||||
|
||||
uint32_t tsens_out = temperature_sensor_ll_get_raw_value();
|
||||
ESP_LOGV(TAG, "tsens_out %d", tsens_out);
|
||||
|
||||
*out_celsius = parse_temp_sensor_raw_value(tsens_out, tsens->tsens_attribute->offset);
|
||||
if (*out_celsius < tsens->tsens_attribute->range_min || *out_celsius > tsens->tsens_attribute->range_max) {
|
||||
ESP_LOGW(TAG, "Temperature range exceeded!");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
ESP_LOGW(TAG, "value out of range, probably invalid");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -422,10 +422,12 @@ static void setup_testbench(void)
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit, &chan_config, &pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_unit_enable(pcnt_unit));
|
||||
}
|
||||
|
||||
static void tear_testbench(void)
|
||||
{
|
||||
TEST_ESP_OK(pcnt_unit_disable(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_del_unit(pcnt_unit));
|
||||
}
|
||||
@ -496,7 +498,7 @@ TEST_CASE("LEDC set and get frequency", "[ledc][timeout=60][ignore]")
|
||||
}
|
||||
|
||||
static void timer_set_clk_src_and_freq_test(ledc_mode_t speed_mode, ledc_clk_cfg_t clk_src, uint32_t duty_res,
|
||||
uint32_t freq_hz)
|
||||
uint32_t freq_hz)
|
||||
{
|
||||
ledc_timer_config_t ledc_time_config = {
|
||||
.speed_mode = speed_mode,
|
||||
|
@ -112,6 +112,7 @@ static void pcnt_setup_testbench(void)
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit_a, &chan_a_config, &pcnt_chan_a));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan_a, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan_a, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
TEST_ESP_OK(pcnt_unit_enable(pcnt_unit_a));
|
||||
|
||||
// PWMB <--> PCNT UNIT1
|
||||
pcnt_unit_config_t unit_b_config = {
|
||||
@ -126,10 +127,13 @@ static void pcnt_setup_testbench(void)
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit_b, &chan_b_config, &pcnt_chan_b));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan_b, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan_b, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
TEST_ESP_OK(pcnt_unit_enable(pcnt_unit_b));
|
||||
}
|
||||
|
||||
static void pcnt_tear_testbench(void)
|
||||
{
|
||||
TEST_ESP_OK(pcnt_unit_disable(pcnt_unit_a));
|
||||
TEST_ESP_OK(pcnt_unit_disable(pcnt_unit_b));
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan_a));
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan_b));
|
||||
TEST_ESP_OK(pcnt_del_unit(pcnt_unit_a));
|
||||
|
@ -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);
|
||||
|
@ -1,5 +1,7 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_pulse_cnt.c")
|
||||
"test_pulse_cnt_simulator.c"
|
||||
"test_pulse_cnt.c"
|
||||
"test_pulse_cnt_iram.c")
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
|
@ -13,43 +13,7 @@
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#define TEST_PCNT_GPIO_A 0
|
||||
#define TEST_PCNT_GPIO_B 2
|
||||
|
||||
#if CONFIG_PCNT_ISR_IRAM_SAFE
|
||||
#define TEST_PCNT_CALLBACK_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define TEST_PCNT_CALLBACK_ATTR
|
||||
#endif // CONFIG_PCNT_ISR_IRAM_SAFE
|
||||
|
||||
// helper function to simulate several rising edges on gpio
|
||||
static void test_gpio_simulate_rising_edge(int gpio_sig, size_t times)
|
||||
{
|
||||
while (times--) {
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig, 0));
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig, 1));
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to simulate several groups of quadrature signals
|
||||
static void test_gpio_simulate_quadrature_signals(int gpio_sig_a, int gpio_sig_b, size_t times)
|
||||
{
|
||||
while (times--) {
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_a, 1));
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_b, 0));
|
||||
vTaskDelay(1);
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_a, 0));
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_b, 0));
|
||||
vTaskDelay(1);
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_a, 0));
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_b, 1));
|
||||
vTaskDelay(1);
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_a, 1));
|
||||
TEST_ESP_OK(gpio_set_level(gpio_sig_b, 1));
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
||||
#include "test_pulse_cnt_board.h"
|
||||
|
||||
TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]")
|
||||
{
|
||||
@ -80,18 +44,28 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]")
|
||||
filter_config.max_glitch_ns = 500000;
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, pcnt_unit_set_glitch_filter(units[0], &filter_config));
|
||||
|
||||
printf("enable pcnt units\r\n");
|
||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_enable(units[i]));
|
||||
}
|
||||
|
||||
printf("start pcnt units\r\n");
|
||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_start(units[i]));
|
||||
}
|
||||
// can't uninstall unit before stop it
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_del_unit(units[0]));
|
||||
|
||||
printf("stop pcnt units\r\n");
|
||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_stop(units[i]));
|
||||
}
|
||||
|
||||
// can't uninstall unit before disable it
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_del_unit(units[0]));
|
||||
printf("disable pcnt units\r\n");
|
||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(pcnt_unit_disable(units[i]));
|
||||
}
|
||||
|
||||
printf("uninstall pcnt units\r\n");
|
||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(pcnt_del_unit(units[i]));
|
||||
@ -125,6 +99,7 @@ TEST_CASE("pcnt_channel_install_uninstall", "[pcnt]")
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(chans[i][j], PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, pcnt_new_channel(units[i], &chan_config, &chans[i][0]));
|
||||
TEST_ESP_OK(pcnt_unit_enable(units[i]));
|
||||
}
|
||||
|
||||
printf("start units\r\n");
|
||||
@ -174,6 +149,7 @@ TEST_CASE("pcnt_channel_install_uninstall", "[pcnt]")
|
||||
for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
|
||||
// stop unit
|
||||
TEST_ESP_OK(pcnt_unit_stop(units[i]));
|
||||
TEST_ESP_OK(pcnt_unit_disable(units[i]));
|
||||
// can't uninstall unit when channel is still alive
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_del_unit(units[i]));
|
||||
for (int j = 0; j < SOC_PCNT_CHANNELS_PER_UNIT; j++) {
|
||||
@ -257,6 +233,9 @@ TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
|
||||
|
||||
// Clear internal counter, and make the watch points take effect
|
||||
TEST_ESP_OK(pcnt_unit_clear_count(unit));
|
||||
// start unit should fail if it's not enabled yet
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, pcnt_unit_start(unit));
|
||||
TEST_ESP_OK(pcnt_unit_enable(unit));
|
||||
TEST_ESP_OK(pcnt_unit_start(unit));
|
||||
|
||||
printf("simulating quadrature signals\r\n");
|
||||
@ -300,6 +279,7 @@ TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
|
||||
TEST_ESP_OK(pcnt_del_channel(channelA));
|
||||
TEST_ESP_OK(pcnt_del_channel(channelB));
|
||||
TEST_ESP_OK(pcnt_unit_stop(unit));
|
||||
TEST_ESP_OK(pcnt_unit_disable(unit));
|
||||
TEST_ESP_OK(pcnt_del_unit(unit));
|
||||
}
|
||||
|
||||
@ -354,6 +334,9 @@ TEST_CASE("pcnt_zero_cross_mode", "[pcnt]")
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(channelB, PCNT_CHANNEL_EDGE_ACTION_HOLD, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(channelB, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
|
||||
printf("enable unit\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_enable(unit));
|
||||
|
||||
printf("start unit\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_start(unit));
|
||||
|
||||
@ -397,6 +380,7 @@ TEST_CASE("pcnt_zero_cross_mode", "[pcnt]")
|
||||
TEST_ASSERT_EQUAL(PCNT_UNIT_ZERO_CROSS_NEG_ZERO, user_data.mode);
|
||||
|
||||
TEST_ESP_OK(pcnt_unit_stop(unit));
|
||||
TEST_ESP_OK(pcnt_unit_disable(unit));
|
||||
TEST_ESP_OK(pcnt_unit_remove_watch_point(unit, 0));
|
||||
TEST_ESP_OK(pcnt_del_channel(channelA));
|
||||
TEST_ESP_OK(pcnt_del_channel(channelB));
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TEST_PCNT_GPIO_A 0
|
||||
#define TEST_PCNT_GPIO_B 2
|
||||
|
||||
#if CONFIG_PCNT_ISR_IRAM_SAFE
|
||||
#define TEST_PCNT_CALLBACK_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define TEST_PCNT_CALLBACK_ATTR
|
||||
#endif // CONFIG_PCNT_ISR_IRAM_SAFE
|
||||
|
||||
void test_gpio_simulate_rising_edge(int gpio_sig, size_t times);
|
||||
void test_gpio_simulate_quadrature_signals(int gpio_sig_a, int gpio_sig_b, size_t times);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
104
components/driver/test_apps/pulse_cnt/main/test_pulse_cnt_iram.c
Normal file
104
components/driver/test_apps/pulse_cnt/main/test_pulse_cnt_iram.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "driver/pulse_cnt.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "test_pulse_cnt_board.h"
|
||||
|
||||
#if CONFIG_PCNT_ISR_IRAM_SAFE
|
||||
|
||||
static bool IRAM_ATTR test_pcnt_iram_safe_callback(pcnt_unit_handle_t unit, pcnt_watch_event_data_t *event_data, void *user_data)
|
||||
{
|
||||
uint32_t *data = (uint32_t *)user_data;
|
||||
(*data)++;
|
||||
// PCNT control function can still work in ISR
|
||||
pcnt_unit_stop(unit);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void IRAM_ATTR test_pcnt_iram_simulation(int gpio_sig)
|
||||
{
|
||||
// disable flash cache
|
||||
spi_flash_guard_get()->start();
|
||||
test_gpio_simulate_rising_edge(gpio_sig, 2);
|
||||
// enable flash cache
|
||||
spi_flash_guard_get()->end();
|
||||
}
|
||||
|
||||
TEST_CASE("pcnt_iram_interrupt_safe", "[pcnt]")
|
||||
{
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -100,
|
||||
.high_limit = 100
|
||||
};
|
||||
|
||||
printf("install pcnt unit\r\n");
|
||||
pcnt_unit_handle_t unit = NULL;
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &unit));
|
||||
|
||||
printf("add watch point and event callback\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_add_watch_point(unit, 2));
|
||||
pcnt_event_callbacks_t cbs = {
|
||||
.on_reach = test_pcnt_iram_safe_callback,
|
||||
};
|
||||
uint32_t num_of_event_triggered = 0;
|
||||
TEST_ESP_OK(pcnt_unit_register_event_callbacks(unit, &cbs, &num_of_event_triggered));
|
||||
|
||||
printf("install pcnt channels\r\n");
|
||||
pcnt_chan_config_t channel_config = {
|
||||
.edge_gpio_num = TEST_PCNT_GPIO_A,
|
||||
.level_gpio_num = -1,
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
pcnt_channel_handle_t channelA = NULL;
|
||||
pcnt_channel_handle_t channelB = NULL;
|
||||
TEST_ESP_OK(pcnt_new_channel(unit, &channel_config, &channelA));
|
||||
TEST_ESP_OK(pcnt_new_channel(unit, &channel_config, &channelB));
|
||||
|
||||
printf("enable unit\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_enable(unit));
|
||||
|
||||
printf("Set pcnt actions for channels\r\n");
|
||||
// both channels increase on pulse edge
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(channelA, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(channelA, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(channelA, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(channelB, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
|
||||
printf("start unit\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_start(unit));
|
||||
|
||||
printf("disable cache and check interrupt triggered\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_clear_count(unit));
|
||||
// the function that will disable the flash must be placed in the IRAM
|
||||
test_pcnt_iram_simulation(TEST_PCNT_GPIO_A);
|
||||
// check if the interrupt has fired up
|
||||
TEST_ASSERT_EQUAL(1, num_of_event_triggered);
|
||||
|
||||
printf("check current count value\r\n");
|
||||
int cur_count = 0;
|
||||
TEST_ESP_OK(pcnt_unit_get_count(unit, &cur_count));
|
||||
// when the watch point got triggered, we disabled the PCNT unit in thr `test_pcnt_iram_safe_callback()`
|
||||
// so the finally count value should equal to the watch point value
|
||||
TEST_ASSERT_EQUAL(2, cur_count);
|
||||
|
||||
printf("delete channels and unit\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_disable(unit));
|
||||
TEST_ESP_OK(pcnt_del_channel(channelA));
|
||||
TEST_ESP_OK(pcnt_del_channel(channelB));
|
||||
TEST_ESP_OK(pcnt_del_unit(unit));
|
||||
}
|
||||
|
||||
#endif // CONFIG_PCNT_ISR_IRAM_SAFE
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_attr.h"
|
||||
#include "test_pulse_cnt_board.h"
|
||||
|
||||
// helper function to simulate several rising edges on gpio
|
||||
IRAM_ATTR void test_gpio_simulate_rising_edge(int gpio_sig, size_t times)
|
||||
{
|
||||
while (times--) {
|
||||
gpio_set_level(gpio_sig, 0);
|
||||
gpio_set_level(gpio_sig, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// helper function to simulate several groups of quadrature signals
|
||||
IRAM_ATTR void test_gpio_simulate_quadrature_signals(int gpio_sig_a, int gpio_sig_b, size_t times)
|
||||
{
|
||||
while (times--) {
|
||||
gpio_set_level(gpio_sig_a, 1);
|
||||
gpio_set_level(gpio_sig_b, 0);
|
||||
vTaskDelay(1);
|
||||
gpio_set_level(gpio_sig_a, 0);
|
||||
gpio_set_level(gpio_sig_b, 0);
|
||||
vTaskDelay(1);
|
||||
gpio_set_level(gpio_sig_a, 0);
|
||||
gpio_set_level(gpio_sig_b, 1);
|
||||
vTaskDelay(1);
|
||||
gpio_set_level(gpio_sig_a, 1);
|
||||
gpio_set_level(gpio_sig_b, 1);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||
CONFIG_PCNT_CTRL_FUNC_IN_IRAM=y
|
||||
CONFIG_PCNT_ISR_IRAM_SAFE=y
|
||||
CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y
|
||||
|
||||
# silent the error check, as the error string are stored in rodata, causing RTL check failure
|
||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
||||
|
@ -36,5 +36,17 @@ void tearDown(void)
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// _____ ____
|
||||
// |_ _|__ _ __ ___ _ __ / ___| ___ _ __ ___ ___ _ __
|
||||
// | |/ _ \ '_ ` _ \| '_ \ \___ \ / _ \ '_ \/ __|/ _ \| '__|
|
||||
// | | __/ | | | | | |_) | ___) | __/ | | \__ \ (_) | |
|
||||
// |_|\___|_| |_| |_| .__/ |____/ \___|_| |_|___/\___/|_|
|
||||
// |_|
|
||||
printf(" _____ ____\r\n");
|
||||
printf("|_ _|__ _ __ ___ _ __ / ___| ___ _ __ ___ ___ _ __\r\n");
|
||||
printf(" | |/ _ \\ '_ ` _ \\| '_ \\ \\___ \\ / _ \\ '_ \\/ __|/ _ \\| '__|\r\n");
|
||||
printf(" | | __/ | | | | | |_) | ___) | __/ | | \\__ \\ (_) | |\r\n");
|
||||
printf(" |_|\\___|_| |_| |_| .__/ |____/ \\___|_| |_|___/\\___/|_|\r\n");
|
||||
printf(" |_|\r\n");
|
||||
unity_run_menu();
|
||||
}
|
||||
|
@ -16,21 +16,25 @@ TEST_CASE("Temperature_sensor_driver_workflow_test", "[temperature_sensor]")
|
||||
temperature_sensor_config_t temp_sensor = TEMPERAUTRE_SENSOR_CONFIG_DEFAULT(10, 50);
|
||||
temperature_sensor_handle_t temp_handle = NULL;
|
||||
TEST_ESP_OK(temperature_sensor_install(&temp_sensor, &temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_start(temp_handle));
|
||||
// read sensor before enable it should fail
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
TEST_ESP_OK(temperature_sensor_enable(temp_handle));
|
||||
printf("Temperature sensor started\n");
|
||||
TEST_ESP_OK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
printf("Temperature out celsius %f°C\n", tsens_out);
|
||||
TEST_ESP_OK(temperature_sensor_stop(temp_handle));
|
||||
// uninstall driver before disable it should fail
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, temperature_sensor_uninstall(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_disable(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_uninstall(temp_handle));
|
||||
// Reconfig the temperature sensor.
|
||||
temp_sensor.range_min = -20;
|
||||
temp_sensor.range_max = 45;
|
||||
TEST_ESP_OK(temperature_sensor_install(&temp_sensor, &temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_start(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_enable(temp_handle));
|
||||
printf("Temperature sensor started again\n");
|
||||
TEST_ESP_OK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
printf("Temperature out celsius %f°C\n", tsens_out);
|
||||
TEST_ESP_OK(temperature_sensor_stop(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_disable(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_uninstall(temp_handle));
|
||||
}
|
||||
|
||||
@ -50,9 +54,9 @@ TEST_CASE("Double start error cause test", "[temperature_sensor]")
|
||||
temperature_sensor_config_t temp_sensor = TEMPERAUTRE_SENSOR_CONFIG_DEFAULT(10, 50);
|
||||
temperature_sensor_handle_t temp_handle = NULL;
|
||||
TEST_ESP_OK(temperature_sensor_install(&temp_sensor, &temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_start(temp_handle));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, temperature_sensor_start(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_stop(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_enable(temp_handle));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, temperature_sensor_enable(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_disable(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_uninstall(temp_handle));
|
||||
}
|
||||
|
||||
@ -63,15 +67,15 @@ TEST_CASE("Double Start-Stop test", "[temperature_sensor]")
|
||||
temperature_sensor_config_t temp_sensor = TEMPERAUTRE_SENSOR_CONFIG_DEFAULT(10, 50);
|
||||
temperature_sensor_handle_t temp_handle = NULL;
|
||||
TEST_ESP_OK(temperature_sensor_install(&temp_sensor, &temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_start(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_enable(temp_handle));
|
||||
printf("Temperature sensor started\n");
|
||||
TEST_ESP_OK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
printf("Temperature out celsius %f°C\n", tsens_out);
|
||||
TEST_ESP_OK(temperature_sensor_stop(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_start(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_disable(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_enable(temp_handle));
|
||||
printf("Temperature sensor started again\n");
|
||||
TEST_ESP_OK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
printf("Temperature out celsius %f°C\n", tsens_out);
|
||||
TEST_ESP_OK(temperature_sensor_stop(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_disable(temp_handle));
|
||||
TEST_ESP_OK(temperature_sensor_uninstall(temp_handle));
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,6 @@ api-reference/peripherals/secure_element
|
||||
api-reference/peripherals/temp_sensor
|
||||
api-reference/peripherals/spi_slave_hd
|
||||
api-reference/peripherals/i2c
|
||||
api-reference/peripherals/dedic_gpio
|
||||
api-reference/peripherals/index
|
||||
api-reference/kconfig
|
||||
api-reference/network/esp_openthread
|
||||
|
@ -72,20 +72,47 @@ GPIO Bundle Operations
|
||||
* - Read the value that output from bundle
|
||||
- :cpp:func:`dedic_gpio_bundle_read_in`
|
||||
|
||||
.. note::
|
||||
Using the above functions might not get a high GPIO flip speed because of the overhead of function calls and the bit operations involved inside. Users can try `Manipulate GPIOs by Assembly Code <#manipulate-gpios-by-writing-assembly-code>`__ instead to reduce the overhead but should take care of the thread safety by themselves.
|
||||
|
||||
Manipulate GPIOs by Writing Assembly Code
|
||||
------------------------------------------
|
||||
|
||||
For advanced users, they can always manipulate the GPIOs by writing assembly code or invoking CPU Low Level APIs. The usual procedure could be:
|
||||
|
||||
1. Allocate a GPIO bundle: :cpp:func:`dedic_gpio_new_bundle`
|
||||
2. Query the mask occupied by that bundle: :cpp:func:`dedic_gpio_get_out_mask` or/and :cpp:func:`dedic_gpio_get_in_mask`
|
||||
3. Call CPU LL apis (e.g. `cpu_ll_write_dedic_gpio_mask`) or write assembly code with that mask
|
||||
4. The fasted way of toggling IO is to use the dedicated "set/clear" instructions:
|
||||
|
||||
.. only:: esp32s2 or esp32s3
|
||||
|
||||
- Set bits of GPIO: ``set_bit_gpio_out imm[7:0]``
|
||||
- Clear bits of GPIO: ``clr_bit_gpio_out imm[7:0]``
|
||||
- Note: Immediate value width depends on the number of dedicated GPIO channels
|
||||
|
||||
.. only:: esp32c2 or esp32c3
|
||||
|
||||
- Set bits of GPIO: ``csrrsi rd, csr, imm[4:0]``
|
||||
- Clear bits of GPIO: ``csrrci rd, csr, imm[4:0]``
|
||||
- Note: Can only control the lowest 4 GPIO channels
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
.. note::
|
||||
The functions above just wrap the customized instructions defined for {IDF_TARGET_NAME}, for the details of those instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__].
|
||||
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__].
|
||||
|
||||
.. only:: esp32s3
|
||||
|
||||
.. note::
|
||||
The functions above just wrap the customized instructions defined for {IDF_TARGET_NAME}, for the details of those instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *Processor Instruction Extensions (PIE) (to be added later)* [`PDF <{IDF_TARGET_TRM_EN_URL}#pie>`__].
|
||||
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *Processor Instruction Extensions (PIE) (to be added later)* [`PDF <{IDF_TARGET_TRM_EN_URL}#pie>`__].
|
||||
|
||||
.. only:: esp32c2 or esp32c3
|
||||
|
||||
.. note::
|
||||
The functions above just wrap the customized instructions defined for {IDF_TARGET_NAME}, for the details of those instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *ESP-RISC-V CPU* [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__].
|
||||
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *ESP-RISC-V CPU* [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__].
|
||||
|
||||
Some of the dedicated CPU instructions are also wrapped inside `soc/cpu_ll.h` as helper inline functions.
|
||||
|
||||
.. note::
|
||||
Writing assembly code in application could make your code hard to port between targets, because those customized instructions are not guaranteed to remain the same format on different targets.
|
||||
|
||||
.. only:: SOC_DEDIC_GPIO_HAS_INTERRUPT
|
||||
|
||||
@ -115,47 +142,7 @@ GPIO Bundle Operations
|
||||
// wait for done semaphore
|
||||
xSemaphoreTake(sem, portMAX_DELAY);
|
||||
|
||||
|
||||
Manipulate GPIOs by Writing Assembly Code
|
||||
------------------------------------------
|
||||
|
||||
For advanced users, they can always manipulate the GPIOs by writing assembly code or invoking CPU Low Level APIs. The usual procedure could be:
|
||||
|
||||
1. Allocate a GPIO bundle: :cpp:func:`dedic_gpio_new_bundle`
|
||||
2. Query the mask occupied by that bundle: :cpp:func:`dedic_gpio_get_out_mask` or/and :cpp:func:`dedic_gpio_get_in_mask`
|
||||
3. Call CPU LL apis (e.g. `cpu_ll_write_dedic_gpio_mask`) or write assembly code with that mask
|
||||
4. The fasted way of toggling IO is to use the dedicated "set/clear" instructions:
|
||||
|
||||
.. only:: esp32s2 or esp32s3
|
||||
|
||||
- Set bits of GPIO: ``set_bit_gpio_out imm[7:0]``
|
||||
- Clear bits of GPIO: ``clr_bit_gpio_out imm[7:0]``
|
||||
- Note: Immediate value width depends on the number of dedicated GPIO channels
|
||||
|
||||
.. only:: esp32c2 or esp32c3
|
||||
|
||||
- Set bits of GPIO: ``csrrsi rd, csr, imm[4:0]``
|
||||
- Clear bits of GPIO: ``csrrci rd, csr, imm[4:0]``
|
||||
- Note: Can only control the lowest 4 GPIO channels
|
||||
|
||||
.. only:: esp32s2
|
||||
|
||||
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *IO MUX and GPIO Matrix (GPIO, IO_MUX)* [`PDF <{IDF_TARGET_TRM_EN_URL}#iomuxgpio>`__].
|
||||
|
||||
.. only:: esp32s3
|
||||
|
||||
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *Processor Instruction Extensions (PIE) (to be added later)* [`PDF <{IDF_TARGET_TRM_EN_URL}#pie>`__].
|
||||
|
||||
.. only:: esp32c2 or esp32c3
|
||||
|
||||
For details of supported dedicated GPIO instructions, please refer to *{IDF_TARGET_NAME} Technical Reference Manual* > *ESP-RISC-V CPU* [`PDF <{IDF_TARGET_TRM_EN_URL}#riscvcpu>`__].
|
||||
|
||||
The supported dedicated CPU instructions are also wrapped inside `soc/cpu_ll.h` as helper inline functions.
|
||||
|
||||
.. note::
|
||||
Writing assembly code in application could make your code hard to port between targets, because those customized instructions are not guaranteed to remain the same format on different targets.
|
||||
|
||||
.. only:: esp32s2
|
||||
.. only:: SOC_DEDIC_GPIO_HAS_INTERRUPT
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
@ -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.
|
||||
|
@ -25,6 +25,8 @@ Description of the PCNT functionality is divided into into the following section
|
||||
- `Set Up Channel Actions <#set-up-channel-actions>`__ - covers how to configure the PCNT channel to behave on different signal edges and levels.
|
||||
- `Watch Points <#watch-points>`__ - describes how to configure PCNT watch points (i.e., tell PCNT unit to trigger an event when the count reaches a certain value).
|
||||
- `Register Event Callbacks <#register-event-callbacks>`__ - describes how to hook user specific code to the watch point event callback function.
|
||||
- `Set Glitch Filter <#set-glitch-filter>`__ - describes how to enable and set the timing parameters for the internal glitch filter.
|
||||
- `Enable and Disable Unit <#enable-and-disable-unit>`__ - describes how to enable and disable the PCNT unit.
|
||||
- `Unit IO Control <#unit-io-control>`__ - describes IO control functions of PCNT unit, like enable glitch filter, start and stop unit, get and clear count value.
|
||||
- `Power Management <#power-management>`__ - describes what functionality will prevent the chip from going into low power mode.
|
||||
- `IRAM Safe <#iram-safe>`__ - describes tips on how to make the PCNT interrupt and IO control functions work better along with a disabled cache.
|
||||
@ -47,8 +49,8 @@ Unit allocation and initialization is done by calling a function :cpp:func:`pcnt
|
||||
|
||||
If a previously created PCNT unit is no longer needed, it's recommended to recycle the resource by calling :cpp:func:`pcnt_del_unit`. Which in return allows the underlying unit hardware to be used for other purposes. Before deleting a PCNT unit, one should ensure the following prerequisites:
|
||||
|
||||
- The unit is in a stop state, in other words, the unit either is stopped by :cpp:func:`pcnt_unit_stop` or not started yet.
|
||||
- The unit ought to stop watching any "watch point". See `Watch Points <#watch-points>`__ for how to removing a watch point.
|
||||
- The unit is in the init state, in other words, the unit is either disabled by :cpp:func:`pcnt_unit_disable` or not enabled yet.
|
||||
- The attached PCNT channels are all removed by :cpp:func:`pcnt_del_channel`.
|
||||
|
||||
.. code:: c
|
||||
|
||||
@ -71,7 +73,7 @@ To install a PCNT channel, there's a configuration structure that needs to be gi
|
||||
- :cpp:member:`pcnt_chan_config_t::invert_edge_input` and :cpp:member:`pcnt_chan_config_t::invert_level_input` are used to decide whether to invert the input signals before they going into PCNT hardware. The invert is done by GPIO matrix instead of PCNT hardware.
|
||||
- :cpp:member:`pcnt_chan_config_t::io_loop_back` is for debug only, which enables both the GPIO's input and output paths. This can help to simulate the pulse signals by function :cpp:func:`gpio_set_level` on the same GPIO.
|
||||
|
||||
Channel allocating and initialization is done by calling a function :cpp:func:`pcnt_new_channel` with the above :cpp:type:`pcnt_chan_config_t` input parameter plus a PCNT unit handle returned from :cpp:func:`pcnt_new_unit`. This function will return a PCNT channel handle if it runs correctly. Specifically, when there are no more free PCNT channel within the unit (i.e. channel resources have been used up), then this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. The total number of available PCNT channels within the unit is recorded by :c:macro:`SOC_PCNT_CHANNELS_PER_UNIT` for reference.
|
||||
Channel allocating and initialization is done by calling a function :cpp:func:`pcnt_new_channel` with the above :cpp:type:`pcnt_chan_config_t` input parameter plus a PCNT unit handle returned from :cpp:func:`pcnt_new_unit`. This function will return a PCNT channel handle if it runs correctly. Specifically, when there are no more free PCNT channel within the unit (i.e. channel resources have been used up), then this function will return :c:macro:`ESP_ERR_NOT_FOUND` error. The total number of available PCNT channels within the unit is recorded by :c:macro:`SOC_PCNT_CHANNELS_PER_UNIT` for reference. Note that, when install a PCNT channel for a specific unit, one should ensure the unit is in the init state, otherwise this function will return :c:macro:`ESP_ERR_INVALID_STATE` error.
|
||||
|
||||
If a previously created PCNT channel is no longer needed, it's recommended to recycle the resources by calling :cpp:func:`pcnt_del_channel`. Which in return allows the underlying channel hardware to be used for other purposes.
|
||||
|
||||
@ -109,7 +111,7 @@ Each PCNT unit can be configured to watch several different values that you're i
|
||||
|
||||
The watch point can be added and removed by :cpp:func:`pcnt_unit_add_watch_point` and :cpp:func:`pcnt_unit_remove_watch_point`. The commonly used watch points are: **zero cross**, **maximum / minimum count** and other threshold values. The number of available watch point is limited, :cpp:func:`pcnt_unit_add_watch_point` will return error :c:macro:`ESP_ERR_NOT_FOUND` if it can't find any free hardware resource to save the watch point. User can't add the same watch point for multiple times, otherwise it will return error :c:macro:`ESP_ERR_INVALID_STATE`.
|
||||
|
||||
It is recommended to remove the unused watch point by :cpp:func:`pcnt_unit_remove_watch_point` to recycle the watch point resources. Be careful when you recycle the PCNT unit by :cpp:func:`pcnt_del_unit`, the using watch points must be removed from the unit in advance.
|
||||
It is recommended to remove the unused watch point by :cpp:func:`pcnt_unit_remove_watch_point` to recycle the watch point resources.
|
||||
|
||||
.. code:: c
|
||||
|
||||
@ -132,6 +134,8 @@ In the callback function, the driver will fill in the event data of specific eve
|
||||
- :cpp:member:`pcnt_watch_event_data_t::watch_point_value` saves the watch point value that triggers the event.
|
||||
- :cpp:member:`pcnt_watch_event_data_t::zero_cross_mode` saves how the PCNT unit crosses the zero point in the latest time. The possible zero cross modes are listed in the :cpp:type:`pcnt_unit_zero_cross_mode_t`. Usually different zero cross mode means different **counting direction** and **counting step size**.
|
||||
|
||||
Registering callback function will result in lazy installation of interrupt service, thus this function should only be called before the unit is enabled by :cpp:func:`pcnt_unit_enable`. Otherwise, it can return :c:macro:`ESP_ERR_INVALID_STATE` error.
|
||||
|
||||
.. code:: c
|
||||
|
||||
static bool example_pcnt_on_reach(pcnt_unit_handle_t unit, pcnt_watch_event_data_t *edata, void *user_ctx)
|
||||
@ -150,11 +154,8 @@ In the callback function, the driver will fill in the event data of specific eve
|
||||
QueueHandle_t queue = xQueueCreate(10, sizeof(int));
|
||||
ESP_ERROR_CHECK(pcnt_unit_register_event_callbacks(pcnt_unit, &cbs, queue));
|
||||
|
||||
Unit IO Control
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Set Glitch Filter
|
||||
~~~~~~~~~~~~~~~~~
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
The PCNT unit features filters to ignore possible short glitches in the signals. The parameters that can be configured for the glitch filter are listed in :cpp:type:`pcnt_glitch_filter_config_t`:
|
||||
|
||||
@ -162,6 +163,8 @@ The PCNT unit features filters to ignore possible short glitches in the signals.
|
||||
|
||||
User can enable the glitch filter for PCNT unit by calling :cpp:func:`pcnt_unit_set_glitch_filter` with the filter configuration provided above. Particularly, user can disable the glitch filter later by calling :cpp:func:`pcnt_unit_set_glitch_filter` with a `NULL` filter configuration.
|
||||
|
||||
This function should be called when the the unit is in the init state. Otherwise, it will return :c:macro:`ESP_ERR_INVALID_STATE` error.
|
||||
|
||||
.. note::
|
||||
|
||||
The glitch filter is clocked from APB. For the counter not to miss any pulses, the maximum glitch width should be longer than one APB_CLK cycle (usually 12.5 ns if APB equals 80MHz). As the APB frequency would be changed after DFS (Dynamic Frequency Scaling) enabled, which means the filter won't work as expect in that case. So the driver will install a PM lock for PCNT unit during the first time user enables the glitch filter. For more information related to power management strategy used in PCNT driver, please see `Power Management <#power-management>`__.
|
||||
@ -173,11 +176,31 @@ User can enable the glitch filter for PCNT unit by calling :cpp:func:`pcnt_unit_
|
||||
};
|
||||
ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(pcnt_unit, &filter_config));
|
||||
|
||||
Enable and Disable Unit
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Before doing IO control to the PCNT unit, user needs to enable it first, by calling :cpp:func:`pcnt_unit_enable`. Internally, this function will:
|
||||
|
||||
* switch the PCNT driver state from **init** to **enable**.
|
||||
* enable the interrupt service if it has been lazy installed in :cpp:func:`pcnt_unit_register_event_callbacks`.
|
||||
* acquire a proper power management lock if it has been lazy installed in :cpp:func:`pcnt_unit_set_glitch_filter`. See also `Power management <#power-management>`__ for more information.
|
||||
|
||||
On the contrary, calling :cpp:func:`pcnt_unit_disable` will do the opposite, that is, put the PCNT driver back to the **init** state, disable the interrupts service and release the power management lock.
|
||||
|
||||
.. code::c
|
||||
|
||||
ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit));
|
||||
|
||||
Unit IO Control
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
Start/Stop and Clear
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Calling :cpp:func:`pcnt_unit_start` will make the PCNT unit start to work, increase or decrease counter according to pulse signals. On the contrary, calling :cpp:func:`pcnt_unit_stop` will stop the PCNT unit but retain current count value. Instead, clearing counter can only be done by calling :cpp:func:`pcnt_unit_clear_count`.
|
||||
|
||||
Note, :cpp:func:`pcnt_unit_start` and :cpp:func:`pcnt_unit_stop` should be called when the unit has been enabled by :cpp:func:`pcnt_unit_enable`. Otherwise, it will return :c:macro:`ESP_ERR_INVALID_STATE` error.
|
||||
|
||||
.. code::c
|
||||
|
||||
ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit));
|
||||
@ -202,7 +225,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 behavior of PCNT glitch filter and leading to valid signal being treated as noise.
|
||||
|
||||
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 user enables the glitch filter by :cpp:func:`pcnt_unit_set_glitch_filter`, the driver will guarantee that the power management lock is acquired after the PCNT unit is started by :cpp:func:`pcnt_unit_start`. Likewise, the driver releases the lock after :cpp:func:`pcnt_unit_stop` is called. This requires that the :cpp:func:`pcnt_unit_start` and :cpp:func:`pcnt_unit_stop` should appear in pairs, otherwise the power management will be out of action.
|
||||
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 user enables the glitch filter by :cpp:func:`pcnt_unit_set_glitch_filter`, the driver will guarantee that the power management lock is acquired after the PCNT unit is enabled by :cpp:func:`pcnt_unit_enable`. Likewise, the driver releases the lock after :cpp:func:`pcnt_unit_disable` is called.
|
||||
|
||||
IRAM Safe
|
||||
^^^^^^^^^
|
||||
@ -212,9 +235,7 @@ By default, the PCNT interrupt will be deferred when the Cache is disabled for r
|
||||
There's a Kconfig option :ref:`CONFIG_PCNT_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.
|
||||
|
@ -30,13 +30,9 @@ Functional Overview
|
||||
-------------------
|
||||
|
||||
- `Resource Allocation <#resource-allocation>`__ - covers which parameters should be set up to get a temperature sensor handle and how to recycle the resources when temperature sensor finishes working.
|
||||
|
||||
- `Start and Stop Temperature <#start-and-stop-temperature>`__ - covers how to start or stop the temperature sensor.
|
||||
|
||||
- `Enable and Disable Temperature Sensor <#enable-and-disable-temperature-sensor>`__ - covers how to enable and disable the temperature sensor.
|
||||
- `Get Temperature Value <#get-temperature-value>`__ - covers how to get the real-time temperature value.
|
||||
|
||||
- `Power Management <#power-management>`__ - covers how temperature sensor is affected when changing power mode (i.e. light sleep).
|
||||
|
||||
- `Thread Safety <#thread-safety>`__ - covers how to make the driver to be thread safe.
|
||||
|
||||
Resource Allocation
|
||||
@ -48,7 +44,6 @@ In order to install a built-in temperature sensor instance, the first thing is t
|
||||
:cpp:type:`temperature_sensor_config_t`:
|
||||
|
||||
- :cpp:member:`range_min`. The minimum value of testing range you have evaluated.
|
||||
|
||||
- :cpp:member:`range_max`. The maximum value of testing range you have evaluated.
|
||||
|
||||
After the ranges are set, the structure could be passed to :cpp:func:`temperature_sensor_install`, which will instantiate the temperature sensor instance and return a handle.
|
||||
@ -61,7 +56,6 @@ Creating a Temperature Sensor Handle
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Step1: Evaluate the testing range. In this example, the range is 20 °C ~ 50 °C.
|
||||
|
||||
* Step2: Configure the range and obtain a handle
|
||||
|
||||
.. code:: c
|
||||
@ -73,28 +67,27 @@ Creating a Temperature Sensor Handle
|
||||
};
|
||||
ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor, &temp_handle));
|
||||
|
||||
Start and Stop Temperature
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Enable and Disable Temperature Sensor
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Start the temperature sensor by calling :cpp:func:`temperature_sensor_start`. The temperature sensor will now measure the temperature.
|
||||
|
||||
2. To stop the temperature sensor, please call :cpp:func:`temperature_sensor_stop`.
|
||||
1. Enable the temperature sensor by calling :cpp:func:`temperature_sensor_enable`. The internal temperature sensor circuit will start to work. The driver state will transit from init to enable.
|
||||
2. To Disable the temperature sensor, please call :cpp:func:`temperature_sensor_disable`.
|
||||
|
||||
Get Temperature Value
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
After the temperature sensor has been installed, you can get the temperature value by following the steps below.
|
||||
|
||||
1. To get the current temperature, please call :cpp:func:`temperature_sensor_get_celsius`.
|
||||
After the temperature sensor is enabled by :cpp:func:`temperature_sensor_enable`, user can get the current temperature by calling :cpp:func:`temperature_sensor_get_celsius`.
|
||||
|
||||
.. code:: c
|
||||
|
||||
ESP_ERROR_CHECK(temperature_sensor_start(temp_handle));
|
||||
printf("Temperature sensor started\n");
|
||||
// Enable temperature sensor
|
||||
ESP_ERROR_CHECK(temperature_sensor_enable(temp_handle));
|
||||
// Get converted sensor data
|
||||
float tsens_out;
|
||||
ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
printf("Temperature in %f °C\n", tsens_out);
|
||||
ESP_ERROR_CHECK(temperature_sensor_stop(temp_handle));
|
||||
// Disable the temperature sensor if it's not needed and save the power
|
||||
ESP_ERROR_CHECK(temperature_sensor_disable(temp_handle));
|
||||
|
||||
Power Management
|
||||
^^^^^^^^^^^^^^^^
|
||||
@ -114,12 +107,12 @@ Unexpected Behaviors
|
||||
2. When installing the temperature sensor, the driver gives a 'the boundary you gave cannot meet the range of internal temperature sensor' error feedback. It is because the built-in temperature sensor has testing limit. The error due to setting :cpp:type:`temperature_sensor_config_t`:
|
||||
|
||||
(1) Totally out of range, like 200 °C ~ 300 °C.
|
||||
(2) Cross the boundary of each predefined measurement. like 40 °C ~ 110 °C.
|
||||
(2) Cross the boundary of each predefined measurement. like 40 °C ~ 110 °C.
|
||||
|
||||
Application Example
|
||||
-------------------
|
||||
|
||||
Temperature sensor reading example: :example:`peripherals/temp_sensor`.
|
||||
* Temperature sensor reading example: :example:`peripherals/temp_sensor`.
|
||||
|
||||
API Reference
|
||||
----------------------------------
|
||||
|
@ -12,6 +12,35 @@ esp_bt_defs.inc:line: WARNING: Duplicate C declaration, also defined at api-refe
|
||||
Declaration is '.. c:macro:: ESP_BD_ADDR_LEN'.
|
||||
esp_bt_defs.inc:line: WARNING: Duplicate C++ declaration, also defined at api-reference/bluetooth/esp_blufi:line.
|
||||
Declaration is '.. cpp:type:: uint8_t esp_bd_addr_t [ESP_BD_ADDR_LEN]'.
|
||||
esp_hidd_api.inc:line: WARNING: Error in type declaration.
|
||||
If typedef-like declaration:
|
||||
Type must be either just a name or a typedef-like declaration.
|
||||
If just a name:
|
||||
Error in declarator or parameters-and-qualifiers
|
||||
Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 4]
|
||||
void() esp_hd_cb_t (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
|
||||
----^
|
||||
If typedef-like declaration:
|
||||
Error in declarator
|
||||
If declarator-id with parameters-and-qualifiers:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 4]
|
||||
void() esp_hd_cb_t (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
|
||||
----^
|
||||
If parenthesis in noptr-declarator:
|
||||
Error in declarator or parameters-and-qualifiers
|
||||
If pointer to member declarator:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 5]
|
||||
void() esp_hd_cb_t (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
|
||||
-----^
|
||||
If declarator-id:
|
||||
Invalid C++ declaration: Expected identifier in nested name. [error at 5]
|
||||
void() esp_hd_cb_t (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
|
||||
-----^
|
||||
If type alias or template alias:
|
||||
Invalid C++ declaration: Expected identifier in nested name, got keyword: void [error at 4]
|
||||
void() esp_hd_cb_t (esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
|
||||
----^
|
||||
|
||||
esp_spp_api.inc:line: WARNING: Error in type declaration.
|
||||
If typedef-like declaration:
|
||||
Type must be either just a name or a typedef-like declaration.
|
||||
|
@ -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);
|
||||
|
@ -207,6 +207,7 @@ void app_main(void)
|
||||
.on_reach = example_pcnt_on_reach,
|
||||
};
|
||||
ESP_ERROR_CHECK(pcnt_unit_register_event_callbacks(pcnt_unit, &pcnt_cbs, &my_timer_ctx));
|
||||
ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit));
|
||||
ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit));
|
||||
ESP_ERROR_CHECK(pcnt_unit_start(pcnt_unit));
|
||||
|
||||
@ -245,6 +246,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");
|
||||
|
@ -74,6 +74,8 @@ void app_main(void)
|
||||
QueueHandle_t queue = xQueueCreate(10, sizeof(int));
|
||||
ESP_ERROR_CHECK(pcnt_unit_register_event_callbacks(pcnt_unit, &cbs, queue));
|
||||
|
||||
ESP_LOGI(TAG, "enable pcnt unit");
|
||||
ESP_ERROR_CHECK(pcnt_unit_enable(pcnt_unit));
|
||||
ESP_LOGI(TAG, "clear pcnt unit");
|
||||
ESP_ERROR_CHECK(pcnt_unit_clear_count(pcnt_unit));
|
||||
ESP_LOGI(TAG, "start pcnt unit");
|
||||
|
@ -3,9 +3,9 @@
|
||||
|
||||
# Temperature Sensor Example
|
||||
|
||||
The ESP32-S2/C3/S3 has a built-in temperature sensor. The temperature sensor module contains an 8-bit Sigma-Delta ADC and a temperature offset DAC.
|
||||
The ESP32-S2/C3/S3 has a built-in temperature sensor. The temperature sensor module contains an 8-bit Sigma-Delta ADC and a temperature offset DAC.
|
||||
|
||||
The conversion relationship is the first two columns of the table below. Among them, `offset = 0`(default) is the main measurement option, and other values are extended measurement options.
|
||||
The conversion relationship is the first two columns of the table below. Among them, `offset = 0`(default) is the main measurement option, and other values are extended measurement options.
|
||||
|
||||
| DAC level | offset | measure range(℃) | measure error(℃) |
|
||||
| :-------: | :----: | :--------------: | :--------------: |
|
||||
@ -37,18 +37,17 @@ See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/l
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (276) example: Initializing Temperature sensor
|
||||
I (276) temperature_sensor: temperature range [-10°C ~ 80°C], error < 1°C
|
||||
I (286) example: Temperature sensor started
|
||||
I (1286) example: Temperature out celsius 21.64
|
||||
I (2286) example: Temperature out celsius 21.64
|
||||
I (3286) example: Temperature out celsius 21.64
|
||||
I (4286) example: Temperature out celsius 22.08
|
||||
I (5286) example: Temperature out celsius 22.08
|
||||
I (6286) example: Temperature out celsius 22.08
|
||||
I (7286) example: Temperature out celsius 22.08
|
||||
I (8286) example: Temperature out celsius 22.08
|
||||
I (9286) example: Temperature out celsius 22.08
|
||||
I (0) cpu_start: Starting scheduler on APP CPU.
|
||||
I (303) example: Install temperature sensor, expected temp ranger range: 10~50 ℃
|
||||
I (303) temperature_sensor: Range [-10°C ~ 80°C], error < 1°C
|
||||
I (313) example: Enable temperature sensor
|
||||
I (323) example: Read temperature
|
||||
I (323) example: Temperature value 26.06 ℃
|
||||
I (1323) example: Temperature value 26.06 ℃
|
||||
I (2323) example: Temperature value 26.06 ℃
|
||||
I (3323) example: Temperature value 26.06 ℃
|
||||
I (4323) example: Temperature value 26.06 ℃
|
||||
I (5323) example: Temperature value 26.49 ℃
|
||||
|
||||
```
|
||||
|
||||
|
@ -4,34 +4,29 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/temperature_sensor.h"
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
void tempsensor_example(void)
|
||||
{
|
||||
// Initialize touch pad peripheral, it will start a timer to run a filter
|
||||
ESP_LOGI(TAG, "Initializing Temperature sensor");
|
||||
float tsens_out;
|
||||
temperature_sensor_config_t temp_sensor = TEMPERAUTRE_SENSOR_CONFIG_DEFAULT(10, 50);
|
||||
temperature_sensor_handle_t temp_handle = NULL;
|
||||
ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor, &temp_handle));
|
||||
ESP_ERROR_CHECK(temperature_sensor_start(temp_handle));
|
||||
ESP_LOGI(TAG, "Temperature sensor started");
|
||||
int cnt = 20; //read value for 20 times
|
||||
while (cnt) {
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_handle, &tsens_out));
|
||||
ESP_LOGI(TAG, "Temperature out celsius %.02f", tsens_out);
|
||||
cnt--;
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
tempsensor_example();
|
||||
ESP_LOGI(TAG, "Install temperature sensor, expected temp ranger range: 10~50 ℃");
|
||||
temperature_sensor_handle_t temp_sensor = NULL;
|
||||
temperature_sensor_config_t temp_sensor_config = TEMPERAUTRE_SENSOR_CONFIG_DEFAULT(10, 50);
|
||||
ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor_config, &temp_sensor));
|
||||
|
||||
ESP_LOGI(TAG, "Enable temperature sensor");
|
||||
ESP_ERROR_CHECK(temperature_sensor_enable(temp_sensor));
|
||||
|
||||
ESP_LOGI(TAG, "Read temperature");
|
||||
int cnt = 20;
|
||||
float tsens_value;
|
||||
while (cnt--) {
|
||||
ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_sensor, &tsens_value));
|
||||
ESP_LOGI(TAG, "Temperature value %.02f ℃", tsens_value);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
@ -10,8 +10,11 @@ from pytest_embedded.dut import Dut
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic
|
||||
def test_temp_sensor_example(dut: Dut) -> None:
|
||||
dut.expect_exact('Initializing Temperature sensor')
|
||||
dut.expect_exact('Temperature sensor started')
|
||||
temp_value = dut.expect(r'Temperature out celsius (\d+\.\d+)', timeout=30)
|
||||
dut.expect_exact('Install temperature sensor')
|
||||
dut.expect_exact('Enable temperature sensor')
|
||||
dut.expect_exact('Read temperature')
|
||||
temp_value = dut.expect(r'Temperature value (\d+\.\d+) .*', timeout=5)
|
||||
# Because the example test only run in the normal temperature environment. So this assert range is meaningful
|
||||
assert 0 < float(temp_value.group(1)) < 45
|
||||
assert 0 < float(temp_value.group(1).decode('utf8')) < 50
|
||||
temp_value = dut.expect(r'Temperature value (\d+\.\d+) .*', timeout=5)
|
||||
assert 0 < float(temp_value.group(1).decode('utf8')) < 50
|
||||
|
@ -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();
|
||||
|
@ -83,6 +83,8 @@ void ref_clock_init(void)
|
||||
.on_reach = on_reach_watch_point,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_register_event_callbacks(s_pcnt_unit, &cbs, NULL));
|
||||
// enable pcnt
|
||||
TEST_ESP_OK(pcnt_unit_enable(s_pcnt_unit));
|
||||
// start pcnt
|
||||
TEST_ESP_OK(pcnt_unit_start(s_pcnt_unit));
|
||||
|
||||
@ -121,6 +123,7 @@ void ref_clock_deinit(void)
|
||||
{
|
||||
// Deinitialize PCNT
|
||||
TEST_ESP_OK(pcnt_unit_stop(s_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_disable(s_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_remove_watch_point(s_pcnt_unit, REF_CLOCK_PRESCALER_MS * 1000));
|
||||
TEST_ESP_OK(pcnt_del_channel(s_pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_del_unit(s_pcnt_unit));
|
||||
|
@ -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…
x
Reference in New Issue
Block a user