ana_cmpr: add programming guide

This commit is contained in:
laokaiyao
2023-03-13 12:34:53 +08:00
parent 24361f232d
commit 53584bb5a7
19 changed files with 317 additions and 85 deletions
+41 -26
View File
@@ -7,7 +7,7 @@
#include <stdlib.h>
#include <inttypes.h>
#include "sdkconfig.h"
#if CONFIG_SDM_ENABLE_DEBUG_LOG
#if CONFIG_ANA_CMPR_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
@@ -49,10 +49,10 @@ struct ana_cmpr_t {
/* Memory allocation caps which decide the section that memory supposed to allocate */
#if CONFIG_ANA_CMPR_ISR_IRAM_SAFE
#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM)
#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM) // Shared with GPIO
#else
#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#define ANA_CMPR_INTR_FLAG ESP_INTR_FLAG_LEVEL1
#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED) // Shared with GPIO
#endif
/* Driver tag */
@@ -86,7 +86,7 @@ static void IRAM_ATTR s_ana_cmpr_default_intr_handler(void *usr_data)
esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr)
{
#if CONFIG_SDM_ENABLE_DEBUG_LOG
#if CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG
esp_log_level_set(TAG, ESP_LOG_DEBUG);
#endif
ANA_CMPR_NULL_POINTER_CHECK(config);
@@ -120,17 +120,19 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *
CLK_TREE_SRC_FREQ_PRECISION_CACHED,
&s_ana_cmpr[unit]->src_clk_freq_hz),
err, TAG, "get source clock frequency failed");
ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG, "set IO MUX clock source failed");
ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)(config->clk_src)), err, TAG,
"potential clock source conflicts from other IOMUX peripherals");
/* Configure the register */
portENTER_CRITICAL(&s_spinlock);
analog_cmpr_ll_ref_source(s_ana_cmpr[unit]->dev, config->ref_src);
analog_cmpr_ll_set_cross_intr_type(s_ana_cmpr[unit]->dev, config->intr_type);
analog_cmpr_ll_set_ref_source(s_ana_cmpr[unit]->dev, config->ref_src);
analog_cmpr_ll_set_cross_type(s_ana_cmpr[unit]->dev, config->cross_type);
portEXIT_CRITICAL(&s_spinlock);
/* Allocate the interrupt, currently the interrupt source of Analog Comparator is shared with GPIO interrupt source */
esp_intr_alloc(ETS_GPIO_INTR_SOURCE, ANA_CMPR_INTR_FLAG,
s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle);
ESP_GOTO_ON_ERROR(esp_intr_alloc_intrstatus(ETS_GPIO_INTR_SOURCE, ANA_CMPR_INTR_FLAG, (uint32_t)analog_cmpr_ll_get_intr_status_reg(s_ana_cmpr[unit]->dev),
ANALOG_CMPR_LL_EVENT_CROSS, s_ana_cmpr_default_intr_handler, s_ana_cmpr[unit], &s_ana_cmpr[unit]->intr_handle),
err, TAG, "allocate interrupt failed");
if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) {
ESP_LOGD(TAG, "unit %d allocated, source signal: GPIO %d, reference signal: internal",
@@ -144,9 +146,8 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *
return ESP_OK;
err:
/* Free the resources if allocation failed */
free(s_ana_cmpr[unit]);
s_ana_cmpr[unit] = NULL;
/* Delete the unit if allocation failed */
ana_cmpr_del_unit(s_ana_cmpr[unit]);
return ret;
}
@@ -164,18 +165,16 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr)
ESP_RETURN_ON_FALSE(unit >= ANA_CMPR_UNIT_0, ESP_ERR_INVALID_ARG, TAG, "wrong analog comparator handle");
ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, "this analog comparator unit not disabled yet");
/* Disable the Analog Comparator interrupt */
portENTER_CRITICAL(&s_spinlock);
analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, false);
portEXIT_CRITICAL(&s_spinlock);
/* Delete the pm lock if the unit has */
if (cmpr->pm_lock) {
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(cmpr->pm_lock), TAG, "delete pm lock failed");
}
/* Free interrupt and other resources */
esp_intr_free(cmpr->intr_handle);
if (cmpr->intr_handle) {
esp_intr_free(cmpr->intr_handle);
}
free(s_ana_cmpr[unit]);
s_ana_cmpr[unit] = NULL;
@@ -184,7 +183,7 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr)
return ESP_OK;
}
esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_intl_ref_config_t *ref_cfg)
esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_internal_ref_config_t *ref_cfg)
{
ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr);
ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg);
@@ -207,7 +206,7 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_
ANA_CMPR_NULL_POINTER_CHECK_ISR(dbc_cfg);
/* Transfer the time to clock cycles */
uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * cmpr->src_clk_freq_hz) / 1000000;
uint32_t wait_cycle = (uint32_t)(dbc_cfg->wait_us * (cmpr->src_clk_freq_hz / 1000000));
/* Set the waiting clock cycles */
portENTER_CRITICAL_SAFE(&s_spinlock);
analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle);
@@ -218,6 +217,21 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_
return ESP_OK;
}
esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type)
{
ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr);
ESP_RETURN_ON_FALSE_ISR(cross_type >= ANA_CMPR_CROSS_DISABLE && cross_type <= ANA_CMPR_CROSS_ANY,
ESP_ERR_INVALID_ARG, TAG, "invalid cross type");
portENTER_CRITICAL_SAFE(&s_spinlock);
analog_cmpr_ll_set_cross_type(cmpr->dev, cross_type);
portEXIT_CRITICAL_SAFE(&s_spinlock);
ESP_EARLY_LOGD(TAG, "unit %d cross type updated to %d", (int)cmpr->unit, cross_type);
return ESP_OK;
}
esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cmpr_event_callbacks_t *cbs, void *user_data)
{
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
@@ -227,7 +241,11 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm
#if CONFIG_ANA_CMPR_ISR_IRAM_SAFE
if (cbs->on_cross) {
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_cross), ESP_ERR_INVALID_ARG, TAG,
"ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function not in IRAM");
"ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function is not in IRAM");
}
if (user_data) {
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(user_data), ESP_ERR_INVALID_ARG, TAG,
"ANA_CMPR_ISR_IRAM_SAFE enabled but the user_data is not in IRAM");
}
#endif
@@ -235,11 +253,6 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm
memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t));
cmpr->user_data = user_data;
/* Enable the Analog Comparator interrupt */
portENTER_CRITICAL(&s_spinlock);
analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, !!(cbs->on_cross));
portEXIT_CRITICAL(&s_spinlock);
ESP_LOGD(TAG, "unit %d event callback registered", (int)cmpr->unit);
return ESP_OK;
@@ -260,6 +273,7 @@ esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr)
/* Enable the Analog Comparator */
portENTER_CRITICAL(&s_spinlock);
analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, !!(cmpr->cbs.on_cross));
analog_cmpr_ll_enable(cmpr->dev, true);
portEXIT_CRITICAL(&s_spinlock);
@@ -275,6 +289,7 @@ esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr)
"the analog comparator not enabled yet");
/* Disable the Analog Comparator */
portENTER_CRITICAL(&s_spinlock);
analog_cmpr_ll_enable_intr(cmpr->dev, ANALOG_CMPR_LL_EVENT_CROSS, false);
analog_cmpr_ll_enable(cmpr->dev, false);
portEXIT_CRITICAL(&s_spinlock);
@@ -3,6 +3,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
@@ -26,7 +27,7 @@ typedef struct {
* For internal reference, the reference voltage should be set to `internal_ref_volt`,
* for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO`
*/
ana_cmpr_intr_type_t intr_type; /*!< The crossing types that can trigger interrupt */
ana_cmpr_cross_type_t cross_type; /*!< The crossing types that can trigger interrupt */
} ana_cmpr_config_t;
/**
@@ -34,21 +35,21 @@ typedef struct {
*
*/
typedef struct {
ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can specify several dozen percent from the VDD power supply,
* currently supports 0%~70% VDD with step 10%
ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can be specified to a certain fixed percentage of
* the VDD power supply, currently supports 0%~70% VDD with a step 10%
*/
} ana_cmpr_intl_ref_config_t;
} ana_cmpr_internal_ref_config_t;
/**
* @brief Analog comparator debounce filter configuration
*
*/
typedef struct {
float wait_us; /*!< The wait time of re-enabling the interrupt after the last triggering,
uint32_t wait_us; /*!< The wait time of re-enabling the interrupt after the last triggering,
* it is used to avoid the spurious triggering while the source signal crossing the reference signal.
* The value should regarding how fast the source signal changes, e.g., a rapid signal requires
* a small wait time, otherwise the next crosses may be missed.
* (Unit: micro second, resolution = 1 / SRC_CLK_FREQ)
* (Unit: micro second)
*/
} ana_cmpr_debounce_config_t;
@@ -99,8 +100,9 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr);
* @return
* - ESP_OK Set denounce configuration success
* - ESP_ERR_INVALID_ARG NULL pointer of the parameters
* - ESP_ERR_INVALID_STATE The reference source is not `ANA_CMPR_REF_SRC_INTERNAL`
*/
esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_intl_ref_config_t *ref_cfg);
esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_internal_ref_config_t *ref_cfg);
/**
* @brief Set debounce configuration to the analog comparator
@@ -116,6 +118,21 @@ esp_err_t ana_cmpr_set_intl_reference(ana_cmpr_handle_t cmpr, const ana_cmpr_int
*/
esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_config_t *dbc_cfg);
/**
* @brief Set the source signal cross type
* @note The initial cross type is configured in `ana_cmpr_new_unit`, this function can update the cross type
* @note This function is allowed to run within ISR context including intr callbacks
* @note This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on,
* so that it's allowed to be executed when Cache is disabled
*
* @param[in] cmpr The handle of analog comparator unit
* @param[in] cross_type The source signal cross type that can trigger the interrupt
* @return
* - ESP_OK Set denounce configuration success
* - ESP_ERR_INVALID_ARG NULL pointer of the parameters
*/
esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t cross_type);
/**
* @brief Register analog comparator interrupt event callbacks
* @note This function can only be called before enabling the unit
@@ -44,11 +44,11 @@ typedef enum {
*
*/
typedef enum {
ANA_CMPR_INTR_DISABLE, /*!< Disable the cross event interrupt */
ANA_CMPR_INTR_POS_CROSS, /*!< Enable the positive cross event interrupt */
ANA_CMPR_INTR_NEG_CROSS, /*!< Enable the negative cross event interrupt */
ANA_CMPR_INTR_ANY_CROSS, /*!< Enable the both positive & negative cross event interrupt */
} ana_cmpr_intr_type_t;
ANA_CMPR_CROSS_DISABLE, /*!< Disable the cross event interrupt */
ANA_CMPR_CROSS_POS, /*!< Positive cross can trigger event interrupt */
ANA_CMPR_CROSS_NEG, /*!< Negative cross can trigger event interrupt */
ANA_CMPR_CROSS_ANY, /*!< Any cross can trigger event interrupt */
} ana_cmpr_cross_type_t;
/**
* @brief Analog comparator internal reference voltage