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:
morris
2022-05-06 20:44:50 +08:00
51 changed files with 765 additions and 363 deletions

View File

@@ -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
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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));

View File

@@ -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]));
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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));

View File

@@ -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

View 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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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));
}

View File

@@ -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));
}

View File

@@ -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]));
}
}

View File

@@ -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));
}

View File

@@ -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++) {

View File

@@ -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);

View File

@@ -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]));
}
}

View File

@@ -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);

View File

@@ -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));
}

View File

@@ -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));
}