forked from espressif/esp-idf
refactor(ana_cmpr): enhanced the driver implementation
This commit is contained in:
@ -1,24 +1,45 @@
|
|||||||
menu "ESP-Driver:Analog Comparator Configurations"
|
menu "ESP-Driver:Analog Comparator Configurations"
|
||||||
depends on SOC_ANA_CMPR_SUPPORTED
|
depends on SOC_ANA_CMPR_SUPPORTED
|
||||||
config ANA_CMPR_ISR_IRAM_SAFE
|
|
||||||
bool "Analog comparator ISR IRAM-Safe"
|
config ANA_CMPR_ISR_HANDLER_IN_IRAM
|
||||||
default n
|
bool "Place Analog Comparator ISR handler in IRAM to reduce latency"
|
||||||
|
default y
|
||||||
|
select ANA_CMPR_OBJ_CACHE_SAFE
|
||||||
help
|
help
|
||||||
Ensure the Analog Comparator interrupt is IRAM-Safe by allowing the interrupt handler to be
|
Place Analog Comparator ISR handler in IRAM to reduce latency caused by cache miss.
|
||||||
executable when the cache is disabled (e.g. SPI Flash write).
|
|
||||||
|
|
||||||
config ANA_CMPR_CTRL_FUNC_IN_IRAM
|
config ANA_CMPR_CTRL_FUNC_IN_IRAM
|
||||||
bool "Place Analog Comparator control functions into IRAM"
|
bool "Place Analog Comparator control functions into IRAM"
|
||||||
default n
|
default n
|
||||||
|
select ANA_CMPR_OBJ_CACHE_SAFE
|
||||||
help
|
help
|
||||||
Place Analog Comparator control functions (like ana_cmpr_set_internal_reference) into IRAM,
|
Place Analog Comparator control functions (like ana_cmpr_set_internal_reference) into IRAM,
|
||||||
so that these functions can be IRAM-safe and able to be called in an IRAM interrupt context.
|
so that these functions can be IRAM-safe and able to be called in an IRAM interrupt context.
|
||||||
Enabling this option can improve driver performance as well.
|
Enabling this option can improve driver performance as well.
|
||||||
|
|
||||||
config ANA_CMPR_ENABLE_DEBUG_LOG
|
config ANA_CMPR_ISR_CACHE_SAFE
|
||||||
bool "Enable debug log"
|
bool "Allow Analog Comparator ISR to execute when cache is disabled"
|
||||||
|
select ANA_CMPR_ISR_HANDLER_IN_IRAM
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
whether to enable the debug log message for Analog Comparator driver.
|
Enable this option to allow the Analog Comparator Interrupt Service Routine (ISR)
|
||||||
Note that, this option only controls the Analog Comparator driver log, won't affect other drivers.
|
to execute even when the cache is disabled. This can be useful in scenarios where the cache
|
||||||
|
might be turned off, but the comparator functionality is still required to operate correctly.
|
||||||
|
|
||||||
|
config ANA_CMPR_OBJ_CACHE_SAFE
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This will ensure the driver object will not be allocated from a memory region
|
||||||
|
where its cache can be disabled.
|
||||||
|
|
||||||
|
config ANA_CMPR_ENABLE_DEBUG_LOG
|
||||||
|
bool "Force enable debug log"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
If enabled, the driver component will:
|
||||||
|
1. ignore the global logging settings
|
||||||
|
2. compile all log messages into the binary
|
||||||
|
3. set the runtime log level to VERBOSE
|
||||||
|
Please enable this option by caution, as it will increase the binary size.
|
||||||
endmenu # Analog Comparator Configuration
|
endmenu # Analog Comparator Configuration
|
||||||
|
@ -4,62 +4,36 @@
|
|||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#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
|
|
||||||
#endif
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "esp_clk_tree.h"
|
#include "esp_clk_tree.h"
|
||||||
#include "esp_types.h"
|
#include "esp_types.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_check.h"
|
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
#include "esp_heap_caps.h"
|
|
||||||
#include "esp_intr_alloc.h"
|
|
||||||
#include "esp_memory_utils.h"
|
#include "esp_memory_utils.h"
|
||||||
#include "soc/periph_defs.h"
|
|
||||||
#include "soc/ana_cmpr_periph.h"
|
|
||||||
#include "hal/ana_cmpr_ll.h"
|
|
||||||
#include "driver/ana_cmpr.h"
|
#include "driver/ana_cmpr.h"
|
||||||
#include "esp_private/gpio.h"
|
#include "esp_private/gpio.h"
|
||||||
#include "esp_private/io_mux.h"
|
#include "esp_private/io_mux.h"
|
||||||
#include "esp_private/esp_clk.h"
|
#include "esp_private/esp_clk.h"
|
||||||
|
#include "ana_cmpr_private.h"
|
||||||
|
|
||||||
struct ana_cmpr_t {
|
struct ana_cmpr_t {
|
||||||
ana_cmpr_unit_t unit; /*!< Analog comparator unit id */
|
ana_cmpr_unit_t unit; /*!< Analog comparator unit id */
|
||||||
analog_cmpr_dev_t *dev; /*!< Analog comparator unit device address */
|
analog_cmpr_dev_t *dev; /*!< Analog comparator unit device address */
|
||||||
ana_cmpr_ref_source_t ref_src; /*!< Analog comparator reference source, internal or external */
|
ana_cmpr_ref_source_t ref_src; /*!< Analog comparator reference source, internal or external */
|
||||||
bool is_enabled; /*!< Whether the Analog comparator unit is enabled */
|
_Atomic ana_cmpr_fsm_t fsm; /*!< The state machine of the Analog Comparator unit */
|
||||||
ana_cmpr_event_callbacks_t cbs; /*!< The callback group that set by user */
|
ana_cmpr_event_callbacks_t cbs; /*!< The callback group that set by user */
|
||||||
|
void *user_data; /*!< User data that passed to the callbacks */
|
||||||
intr_handle_t intr_handle; /*!< Interrupt handle */
|
intr_handle_t intr_handle; /*!< Interrupt handle */
|
||||||
uint32_t intr_mask; /*!< Interrupt mask */
|
uint32_t intr_mask; /*!< Interrupt mask */
|
||||||
int intr_priority; /*!< Interrupt priority */
|
int intr_priority; /*!< Interrupt priority */
|
||||||
void *user_data; /*!< User data that passed to the callbacks */
|
|
||||||
uint32_t src_clk_freq_hz; /*!< Source clock frequency of the Analog Comparator unit */
|
uint32_t src_clk_freq_hz; /*!< Source clock frequency of the Analog Comparator unit */
|
||||||
esp_pm_lock_handle_t pm_lock; /*!< The Power Management lock that used to avoid unexpected power down of the clock domain */
|
esp_pm_lock_handle_t pm_lock; /*!< The Power Management lock that used to avoid unexpected power down of the clock domain */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Helper macros */
|
/* Helper macros */
|
||||||
#define ANA_CMPR_NULL_POINTER_CHECK(p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL")
|
#define ANA_CMPR_NULL_POINTER_CHECK(p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '" #p "' is NULL")
|
||||||
#define ANA_CMPR_NULL_POINTER_CHECK_ISR(p) ESP_RETURN_ON_FALSE_ISR((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '"#p"' is NULL")
|
#define ANA_CMPR_NULL_POINTER_CHECK_ISR(p) ESP_RETURN_ON_FALSE_ISR((p), ESP_ERR_INVALID_ARG, TAG, "input parameter '" #p "' is NULL")
|
||||||
#define ANA_CMPR_UNIT_CHECK(unit) ESP_RETURN_ON_FALSE((unit) >= 0 && (unit) < SOC_ANA_CMPR_NUM, \
|
#define ANA_CMPR_UNIT_CHECK(unit) ESP_RETURN_ON_FALSE((unit) >= 0 && (unit) < SOC_ANA_CMPR_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid unit number")
|
||||||
ESP_ERR_INVALID_ARG, TAG, "invalid uint number");
|
|
||||||
|
|
||||||
/* 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_IRAM)
|
|
||||||
#else
|
|
||||||
#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
|
||||||
#define ANA_CMPR_INTR_FLAG (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Driver tag */
|
|
||||||
static const char *TAG = "ana_cmpr";
|
|
||||||
|
|
||||||
/* Global static object of the Analog Comparator unit */
|
/* Global static object of the Analog Comparator unit */
|
||||||
static ana_cmpr_handle_t s_ana_cmpr[SOC_ANA_CMPR_NUM] = {
|
static ana_cmpr_handle_t s_ana_cmpr[SOC_ANA_CMPR_NUM] = {
|
||||||
@ -69,10 +43,10 @@ static ana_cmpr_handle_t s_ana_cmpr[SOC_ANA_CMPR_NUM] = {
|
|||||||
/* Global spin lock */
|
/* Global spin lock */
|
||||||
static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
static void IRAM_ATTR s_ana_cmpr_default_intr_handler(void *usr_data)
|
void ana_cmpr_default_intr_handler(void *usr_data)
|
||||||
{
|
{
|
||||||
ana_cmpr_handle_t cmpr_handle = (ana_cmpr_handle_t)usr_data;
|
|
||||||
bool need_yield = false;
|
bool need_yield = false;
|
||||||
|
ana_cmpr_handle_t cmpr_handle = (ana_cmpr_handle_t)usr_data;
|
||||||
ana_cmpr_cross_event_data_t evt_data = {.cross_type = ANA_CMPR_CROSS_ANY};
|
ana_cmpr_cross_event_data_t evt_data = {.cross_type = ANA_CMPR_CROSS_ANY};
|
||||||
/* Get and clear the interrupt status */
|
/* Get and clear the interrupt status */
|
||||||
uint32_t status = analog_cmpr_ll_get_intr_status(cmpr_handle->dev);
|
uint32_t status = analog_cmpr_ll_get_intr_status(cmpr_handle->dev);
|
||||||
@ -80,6 +54,7 @@ static void IRAM_ATTR s_ana_cmpr_default_intr_handler(void *usr_data)
|
|||||||
|
|
||||||
/* Call the user callback function if it is specified and the corresponding event triggers*/
|
/* Call the user callback function if it is specified and the corresponding event triggers*/
|
||||||
if (cmpr_handle->cbs.on_cross && (status & cmpr_handle->intr_mask)) {
|
if (cmpr_handle->cbs.on_cross && (status & cmpr_handle->intr_mask)) {
|
||||||
|
// some chip can distinguish the edge of the cross event
|
||||||
#if SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
#if SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
||||||
if (status & ANALOG_CMPR_LL_POS_CROSS_MASK(cmpr_handle->unit)) {
|
if (status & ANALOG_CMPR_LL_POS_CROSS_MASK(cmpr_handle->unit)) {
|
||||||
evt_data.cross_type = ANA_CMPR_CROSS_POS;
|
evt_data.cross_type = ANA_CMPR_CROSS_POS;
|
||||||
@ -103,61 +78,74 @@ static esp_err_t s_ana_cmpr_init_gpio(ana_cmpr_handle_t cmpr, bool is_external_r
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ana_cmpr_destroy_unit(ana_cmpr_handle_t cmpr)
|
||||||
|
{
|
||||||
|
if (cmpr->pm_lock) {
|
||||||
|
esp_pm_lock_delete(cmpr->pm_lock);
|
||||||
|
}
|
||||||
|
if (cmpr->intr_handle) {
|
||||||
|
esp_intr_free(cmpr->intr_handle);
|
||||||
|
}
|
||||||
|
free(cmpr);
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr)
|
esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *ret_cmpr)
|
||||||
{
|
{
|
||||||
#if CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG
|
esp_err_t ret = ESP_OK;
|
||||||
esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
ana_cmpr_handle_t ana_cmpr_hdl = NULL;
|
||||||
#endif
|
|
||||||
ANA_CMPR_NULL_POINTER_CHECK(config);
|
ANA_CMPR_NULL_POINTER_CHECK(config);
|
||||||
ANA_CMPR_NULL_POINTER_CHECK(ret_cmpr);
|
ANA_CMPR_NULL_POINTER_CHECK(ret_cmpr);
|
||||||
ana_cmpr_unit_t unit = config->unit;
|
ana_cmpr_unit_t unit = config->unit;
|
||||||
ANA_CMPR_UNIT_CHECK(unit);
|
ANA_CMPR_UNIT_CHECK(unit);
|
||||||
ESP_RETURN_ON_FALSE(config->intr_priority >= 0 && config->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "interrupt priority should be within 0~7");
|
ESP_RETURN_ON_FALSE(!s_ana_cmpr[unit], ESP_ERR_INVALID_STATE, TAG, "unit has been allocated already");
|
||||||
ESP_RETURN_ON_FALSE(!s_ana_cmpr[unit], ESP_ERR_INVALID_STATE, TAG,
|
if (config->intr_priority) {
|
||||||
"unit has been allocated already");
|
ESP_RETURN_ON_FALSE(1 << (config->intr_priority) & ANA_CMPR_ALLOW_INTR_PRIORITY_MASK, ESP_ERR_INVALID_ARG,
|
||||||
esp_err_t ret = ESP_OK;
|
TAG, "invalid interrupt priority:%d", config->intr_priority);
|
||||||
|
|
||||||
/* Allocate analog comparator unit */
|
|
||||||
s_ana_cmpr[unit] = (ana_cmpr_handle_t)heap_caps_calloc(1, sizeof(struct ana_cmpr_t), ANA_CMPR_MEM_ALLOC_CAPS);
|
|
||||||
ESP_RETURN_ON_FALSE(s_ana_cmpr[unit], ESP_ERR_NO_MEM, TAG, "no memory for analog comparator struct");
|
|
||||||
|
|
||||||
/* Assign analog comparator unit */
|
|
||||||
s_ana_cmpr[unit]->dev = ANALOG_CMPR_LL_GET_HW(unit);
|
|
||||||
s_ana_cmpr[unit]->ref_src = config->ref_src;
|
|
||||||
s_ana_cmpr[unit]->intr_priority = config->intr_priority;
|
|
||||||
s_ana_cmpr[unit]->is_enabled = false;
|
|
||||||
s_ana_cmpr[unit]->pm_lock = NULL;
|
|
||||||
|
|
||||||
#if CONFIG_PM_ENABLE
|
|
||||||
/* Create PM lock */
|
|
||||||
char lock_name[10] = "ana_cmpr\0";
|
|
||||||
lock_name[8] = '0' + unit;
|
|
||||||
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, lock_name, &s_ana_cmpr[unit]->pm_lock);
|
|
||||||
ESP_GOTO_ON_ERROR(ret, err, TAG, "create NO_LIGHT_SLEEP, lock failed");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!config->flags.io_loop_back) {
|
|
||||||
ESP_GOTO_ON_ERROR(s_ana_cmpr_init_gpio(s_ana_cmpr[unit], config->ref_src == ANA_CMPR_REF_SRC_EXTERNAL), err, TAG, "failed to initialize GPIO");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Analog clock comes from IO MUX, but IO MUX clock might be shared with other submodules as well */
|
// analog comparator unit must be allocated from internal memory because it contains atomic variable
|
||||||
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)config->clk_src,
|
ana_cmpr_hdl = heap_caps_calloc(1, sizeof(struct ana_cmpr_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
|
ESP_RETURN_ON_FALSE(ana_cmpr_hdl, ESP_ERR_NO_MEM, TAG, "no memory for analog comparator object");
|
||||||
&s_ana_cmpr[unit]->src_clk_freq_hz),
|
|
||||||
|
/* Assign analog comparator unit */
|
||||||
|
ana_cmpr_hdl->dev = ANALOG_CMPR_LL_GET_HW(unit);
|
||||||
|
ana_cmpr_hdl->unit = unit;
|
||||||
|
ana_cmpr_hdl->intr_priority = config->intr_priority;
|
||||||
|
atomic_init(&ana_cmpr_hdl->fsm, ANA_CMPR_FSM_INIT);
|
||||||
|
|
||||||
|
ana_cmpr_clk_src_t clk_src = config->clk_src ? config->clk_src : ANA_CMPR_CLK_SRC_DEFAULT;
|
||||||
|
// Analog comparator located in the IO MUX, but IO MUX clock might be shared with other submodules as well, check if there's conflict
|
||||||
|
ESP_GOTO_ON_ERROR(io_mux_set_clock_source((soc_module_clk_t)clk_src), err, TAG, "clock source conflicts with other IOMUX consumers");
|
||||||
|
ESP_GOTO_ON_ERROR(esp_clk_tree_src_get_freq_hz((soc_module_clk_t)clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &ana_cmpr_hdl->src_clk_freq_hz),
|
||||||
err, TAG, "get source clock frequency failed");
|
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,
|
|
||||||
"potential clock source conflicts from other IOMUX peripherals");
|
#if CONFIG_PM_ENABLE
|
||||||
|
// Create PM lock, because the light sleep may disable the clock and power domain used by the analog comparator
|
||||||
|
// TODO: IDF-12818
|
||||||
|
ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, ana_cmpr_periph[unit].module_name, &ana_cmpr_hdl->pm_lock);
|
||||||
|
ESP_GOTO_ON_ERROR(ret, err, TAG, "create NO_LIGHT_SLEEP lock failed");
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Configure the register */
|
/* Configure the register */
|
||||||
portENTER_CRITICAL(&s_spinlock);
|
analog_cmpr_ll_set_ref_source(ana_cmpr_hdl->dev, config->ref_src);
|
||||||
analog_cmpr_ll_set_ref_source(s_ana_cmpr[unit]->dev, config->ref_src);
|
ana_cmpr_hdl->ref_src = config->ref_src;
|
||||||
#if !SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
#if !SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
||||||
analog_cmpr_ll_set_cross_type(s_ana_cmpr[unit]->dev, config->cross_type);
|
// set which cross type can trigger the interrupt
|
||||||
|
analog_cmpr_ll_set_intr_cross_type(ana_cmpr_hdl->dev, config->cross_type);
|
||||||
#endif // SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
#endif // SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
||||||
/* Record the interrupt mask, the interrupt will be lazy installed when register the callbacks */
|
// record the interrupt mask, the interrupt will be lazy installed when register user callbacks
|
||||||
s_ana_cmpr[unit]->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(s_ana_cmpr[unit]->dev, config->cross_type);
|
// different cross type means different interrupt mask
|
||||||
|
ana_cmpr_hdl->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(ana_cmpr_hdl->dev, config->cross_type);
|
||||||
|
|
||||||
|
// different unit share the same interrupt register, so using a spin lock to protect it
|
||||||
|
portENTER_CRITICAL(&s_spinlock);
|
||||||
|
// disable the interrupt by default, and clear pending status
|
||||||
|
analog_cmpr_ll_enable_intr(ana_cmpr_hdl->dev, ANALOG_CMPR_LL_ALL_INTR_MASK(unit), false);
|
||||||
|
analog_cmpr_ll_clear_intr(ana_cmpr_hdl->dev, ANALOG_CMPR_LL_ALL_INTR_MASK(unit));
|
||||||
portEXIT_CRITICAL(&s_spinlock);
|
portEXIT_CRITICAL(&s_spinlock);
|
||||||
|
|
||||||
|
// GPIO configuration
|
||||||
|
ESP_GOTO_ON_ERROR(s_ana_cmpr_init_gpio(ana_cmpr_hdl, config->ref_src == ANA_CMPR_REF_SRC_EXTERNAL), err, TAG, "failed to initialize GPIO");
|
||||||
if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) {
|
if (config->ref_src == ANA_CMPR_REF_SRC_INTERNAL) {
|
||||||
ESP_LOGD(TAG, "unit %d allocated, source signal: GPIO %d, reference signal: internal",
|
ESP_LOGD(TAG, "unit %d allocated, source signal: GPIO %d, reference signal: internal",
|
||||||
(int)unit, ana_cmpr_periph[unit].src_gpio);
|
(int)unit, ana_cmpr_periph[unit].src_gpio);
|
||||||
@ -166,12 +154,15 @@ esp_err_t ana_cmpr_new_unit(const ana_cmpr_config_t *config, ana_cmpr_handle_t *
|
|||||||
(int)unit, ana_cmpr_periph[unit].src_gpio, ana_cmpr_periph[unit].ext_ref_gpio);
|
(int)unit, ana_cmpr_periph[unit].src_gpio, ana_cmpr_periph[unit].ext_ref_gpio);
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret_cmpr = s_ana_cmpr[unit];
|
// register the analog comparator unit to the global object array
|
||||||
|
s_ana_cmpr[unit] = ana_cmpr_hdl;
|
||||||
|
*ret_cmpr = ana_cmpr_hdl;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
/* Delete the unit if allocation failed */
|
if (ana_cmpr_hdl) {
|
||||||
ana_cmpr_del_unit(s_ana_cmpr[unit]);
|
ana_cmpr_destroy_unit(ana_cmpr_hdl);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,22 +177,12 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_RETURN_ON_FALSE(unit != -1, ESP_ERR_INVALID_ARG, TAG, "wrong analog comparator handle");
|
ESP_RETURN_ON_FALSE(unit != -1, ESP_ERR_INVALID_ARG, TAG, "unregistered unit handle");
|
||||||
ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG, "this analog comparator unit not disabled yet");
|
ESP_RETURN_ON_FALSE(atomic_load(&cmpr->fsm) == ANA_CMPR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "not in init state");
|
||||||
|
|
||||||
/* Delete the pm lock if the unit has */
|
ana_cmpr_destroy_unit(cmpr);
|
||||||
if (cmpr->pm_lock) {
|
// unregister it from the global object array
|
||||||
ESP_RETURN_ON_ERROR(esp_pm_lock_delete(cmpr->pm_lock), TAG, "delete pm lock failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free interrupt and other resources */
|
|
||||||
if (cmpr->intr_handle) {
|
|
||||||
esp_intr_free(cmpr->intr_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(s_ana_cmpr[unit]);
|
|
||||||
s_ana_cmpr[unit] = NULL;
|
s_ana_cmpr[unit] = NULL;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "unit %d deleted", (int)unit);
|
ESP_LOGD(TAG, "unit %d deleted", (int)unit);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@ -212,15 +193,13 @@ esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr
|
|||||||
ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr);
|
ANA_CMPR_NULL_POINTER_CHECK_ISR(cmpr);
|
||||||
ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg);
|
ANA_CMPR_NULL_POINTER_CHECK_ISR(ref_cfg);
|
||||||
ESP_RETURN_ON_FALSE_ISR(cmpr->ref_src == ANA_CMPR_REF_SRC_INTERNAL, ESP_ERR_INVALID_STATE,
|
ESP_RETURN_ON_FALSE_ISR(cmpr->ref_src == ANA_CMPR_REF_SRC_INTERNAL, ESP_ERR_INVALID_STATE,
|
||||||
TAG, "the reference channel is not internal, no need to configure internal reference");
|
TAG, "the reference voltage does not come from internal");
|
||||||
|
|
||||||
/* Set internal reference voltage */
|
// the underlying register may be accessed by different threads at the same time, so use spin lock to protect it
|
||||||
portENTER_CRITICAL_SAFE(&s_spinlock);
|
portENTER_CRITICAL_SAFE(&s_spinlock);
|
||||||
analog_cmpr_ll_set_internal_ref_voltage(cmpr->dev, ref_cfg->ref_volt);
|
analog_cmpr_ll_set_internal_ref_voltage(cmpr->dev, ref_cfg->ref_volt);
|
||||||
portEXIT_CRITICAL_SAFE(&s_spinlock);
|
portEXIT_CRITICAL_SAFE(&s_spinlock);
|
||||||
|
|
||||||
ESP_EARLY_LOGD(TAG, "unit %d internal voltage level %" PRIu32, (int)cmpr->unit, (uint32_t)ref_cfg->ref_volt);
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,14 +209,12 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_
|
|||||||
ANA_CMPR_NULL_POINTER_CHECK_ISR(dbc_cfg);
|
ANA_CMPR_NULL_POINTER_CHECK_ISR(dbc_cfg);
|
||||||
|
|
||||||
/* Transfer the time to clock cycles */
|
/* 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 = dbc_cfg->wait_us * (cmpr->src_clk_freq_hz / 1000000);
|
||||||
/* Set the waiting clock cycles */
|
// the underlying register may be accessed by different threads at the same time, so use spin lock to protect it
|
||||||
portENTER_CRITICAL_SAFE(&s_spinlock);
|
portENTER_CRITICAL_SAFE(&s_spinlock);
|
||||||
analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle);
|
analog_cmpr_ll_set_debounce_cycle(cmpr->dev, wait_cycle);
|
||||||
portEXIT_CRITICAL_SAFE(&s_spinlock);
|
portEXIT_CRITICAL_SAFE(&s_spinlock);
|
||||||
|
|
||||||
ESP_EARLY_LOGD(TAG, "unit %d debounce wait cycle %"PRIu32, (int)cmpr->unit, wait_cycle);
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,14 +232,10 @@ esp_err_t ana_cmpr_set_cross_type(ana_cmpr_handle_t cmpr, ana_cmpr_cross_type_t
|
|||||||
ESP_ERR_INVALID_ARG, TAG, "invalid cross type");
|
ESP_ERR_INVALID_ARG, TAG, "invalid cross type");
|
||||||
|
|
||||||
portENTER_CRITICAL_SAFE(&s_spinlock);
|
portENTER_CRITICAL_SAFE(&s_spinlock);
|
||||||
#if !SOC_ANA_CMPR_CAN_DISTINGUISH_EDGE
|
analog_cmpr_ll_set_intr_cross_type(cmpr->dev, cross_type);
|
||||||
analog_cmpr_ll_set_cross_type(cmpr->dev, cross_type);
|
|
||||||
#endif
|
|
||||||
cmpr->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(cmpr->dev, cross_type);
|
cmpr->intr_mask = analog_cmpr_ll_get_intr_mask_by_type(cmpr->dev, cross_type);
|
||||||
portEXIT_CRITICAL_SAFE(&s_spinlock);
|
portEXIT_CRITICAL_SAFE(&s_spinlock);
|
||||||
|
|
||||||
ESP_EARLY_LOGD(TAG, "unit %d cross type updated to %d", (int)cmpr->unit, cross_type);
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -271,82 +244,78 @@ esp_err_t ana_cmpr_register_event_callbacks(ana_cmpr_handle_t cmpr, const ana_cm
|
|||||||
{
|
{
|
||||||
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
|
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
|
||||||
ANA_CMPR_NULL_POINTER_CHECK(cbs);
|
ANA_CMPR_NULL_POINTER_CHECK(cbs);
|
||||||
ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG,
|
ESP_RETURN_ON_FALSE(atomic_load(&cmpr->fsm) == ANA_CMPR_FSM_INIT, ESP_ERR_INVALID_STATE, TAG, "not in init state");
|
||||||
"please disable the analog comparator before registering the callbacks");
|
#if CONFIG_ANA_CMPR_ISR_CACHE_SAFE
|
||||||
#if CONFIG_ANA_CMPR_ISR_IRAM_SAFE
|
|
||||||
if (cbs->on_cross) {
|
if (cbs->on_cross) {
|
||||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_cross), ESP_ERR_INVALID_ARG, TAG,
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_cross), ESP_ERR_INVALID_ARG, TAG, "on_cross is not in IRAM");
|
||||||
"ANA_CMPR_ISR_IRAM_SAFE enabled but the callback function is not in IRAM");
|
|
||||||
}
|
}
|
||||||
if (user_data) {
|
if (user_data) {
|
||||||
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(user_data), ESP_ERR_INVALID_ARG, TAG,
|
ESP_RETURN_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, TAG, "user_data is not in internal RAM");
|
||||||
"ANA_CMPR_ISR_IRAM_SAFE enabled but the user_data is not in IRAM");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Allocate the interrupt, the interrupt source of Analog Comparator is shared with GPIO interrupt source on ESP32H2 */
|
|
||||||
if (!cmpr->intr_handle) {
|
if (!cmpr->intr_handle) {
|
||||||
int intr_flags = ANA_CMPR_INTR_FLAG | (cmpr->intr_priority ? BIT(cmpr->intr_priority) : ESP_INTR_FLAG_LOWMED);
|
int intr_flags = ANA_CMPR_INTR_FLAG | ((cmpr->intr_priority > 0) ? BIT(cmpr->intr_priority) : ESP_INTR_FLAG_LOWMED);
|
||||||
#if SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO
|
|
||||||
intr_flags |= ESP_INTR_FLAG_SHARED;
|
|
||||||
#endif // SOC_ANA_CMPR_INTR_SHARE_WITH_GPIO
|
|
||||||
ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(ana_cmpr_periph[cmpr->unit].intr_src, intr_flags, (uint32_t)analog_cmpr_ll_get_intr_status_reg(cmpr->dev),
|
ESP_RETURN_ON_ERROR(esp_intr_alloc_intrstatus(ana_cmpr_periph[cmpr->unit].intr_src, intr_flags, (uint32_t)analog_cmpr_ll_get_intr_status_reg(cmpr->dev),
|
||||||
cmpr->intr_mask, s_ana_cmpr_default_intr_handler, cmpr, &cmpr->intr_handle), TAG, "allocate interrupt failed");
|
cmpr->intr_mask, ana_cmpr_default_intr_handler, cmpr, &cmpr->intr_handle),
|
||||||
|
TAG, "allocate interrupt failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save the callback group */
|
/* Save the callback functions */
|
||||||
memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t));
|
memcpy(&(cmpr->cbs), cbs, sizeof(ana_cmpr_event_callbacks_t));
|
||||||
cmpr->user_data = user_data;
|
cmpr->user_data = user_data;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "unit %d event callback registered", (int)cmpr->unit);
|
ESP_LOGV(TAG, "unit %d event callback registered", (int)cmpr->unit);
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr)
|
esp_err_t ana_cmpr_enable(ana_cmpr_handle_t cmpr)
|
||||||
{
|
{
|
||||||
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
|
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
|
||||||
ESP_RETURN_ON_FALSE(!cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG,
|
ana_cmpr_fsm_t expected_fsm = ANA_CMPR_FSM_INIT;
|
||||||
"the analog comparator has enabled already");
|
if (atomic_compare_exchange_strong(&cmpr->fsm, &expected_fsm, ANA_CMPR_FSM_WAIT)) {
|
||||||
/* Update the driver status */
|
if (cmpr->pm_lock) {
|
||||||
cmpr->is_enabled = true;
|
esp_pm_lock_acquire(cmpr->pm_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Acquire the pm lock if the unit has, to avoid the system start light sleep while Analog comparator still working */
|
// the underlying register may be accessed by different threads at the same time, so use spin lock to protect it
|
||||||
if (cmpr->pm_lock) {
|
portENTER_CRITICAL(&s_spinlock);
|
||||||
ESP_RETURN_ON_ERROR(esp_pm_lock_acquire(cmpr->pm_lock), TAG, "acquire pm_lock failed");
|
analog_cmpr_ll_enable_intr(cmpr->dev, cmpr->intr_mask, true);
|
||||||
|
analog_cmpr_ll_enable(cmpr->dev, true);
|
||||||
|
portEXIT_CRITICAL(&s_spinlock);
|
||||||
|
|
||||||
|
// switch the state machine to enable state
|
||||||
|
atomic_store(&cmpr->fsm, ANA_CMPR_FSM_ENABLE);
|
||||||
|
ESP_LOGD(TAG, "unit %d enabled", (int)cmpr->unit);
|
||||||
|
} else {
|
||||||
|
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "not in init state");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable the Analog Comparator */
|
|
||||||
portENTER_CRITICAL(&s_spinlock);
|
|
||||||
analog_cmpr_ll_enable_intr(cmpr->dev, cmpr->intr_mask, true);
|
|
||||||
analog_cmpr_ll_enable(cmpr->dev, true);
|
|
||||||
portEXIT_CRITICAL(&s_spinlock);
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "unit %d enabled", (int)cmpr->unit);
|
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr)
|
esp_err_t ana_cmpr_disable(ana_cmpr_handle_t cmpr)
|
||||||
{
|
{
|
||||||
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
|
ANA_CMPR_NULL_POINTER_CHECK(cmpr);
|
||||||
ESP_RETURN_ON_FALSE(cmpr->is_enabled, ESP_ERR_INVALID_STATE, TAG,
|
ana_cmpr_fsm_t expected_fsm = ANA_CMPR_FSM_ENABLE;
|
||||||
"the analog comparator not enabled yet");
|
if (atomic_compare_exchange_strong(&cmpr->fsm, &expected_fsm, ANA_CMPR_FSM_WAIT)) {
|
||||||
/* Disable the Analog Comparator */
|
// the underlying register may be accessed by different threads at the same time, so use spin lock to protect it
|
||||||
portENTER_CRITICAL(&s_spinlock);
|
portENTER_CRITICAL(&s_spinlock);
|
||||||
analog_cmpr_ll_enable_intr(cmpr->dev, cmpr->intr_mask, false);
|
analog_cmpr_ll_enable_intr(cmpr->dev, cmpr->intr_mask, false);
|
||||||
analog_cmpr_ll_enable(cmpr->dev, false);
|
analog_cmpr_ll_enable(cmpr->dev, false);
|
||||||
portEXIT_CRITICAL(&s_spinlock);
|
portEXIT_CRITICAL(&s_spinlock);
|
||||||
|
|
||||||
/* Release the pm lock, allow light sleep then */
|
if (cmpr->pm_lock) {
|
||||||
if (cmpr->pm_lock) {
|
esp_pm_lock_release(cmpr->pm_lock);
|
||||||
ESP_RETURN_ON_ERROR(esp_pm_lock_release(cmpr->pm_lock), TAG, "release pm_lock failed");
|
}
|
||||||
|
|
||||||
|
// switch the state machine to init state
|
||||||
|
atomic_store(&cmpr->fsm, ANA_CMPR_FSM_INIT);
|
||||||
|
ESP_LOGD(TAG, "unit %d disabled", (int)cmpr->unit);
|
||||||
|
} else {
|
||||||
|
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_STATE, TAG, "not enabled yet");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the driver status */
|
|
||||||
cmpr->is_enabled = false;
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "unit %d disabled", (int)cmpr->unit);
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,10 +340,18 @@ esp_err_t ana_cmpr_get_gpio(ana_cmpr_unit_t unit, ana_cmpr_channel_type_t chan_t
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ana_cmpr_unit_t ana_cmpr_priv_get_unit_by_handle(ana_cmpr_handle_t cmpr)
|
ana_cmpr_unit_t ana_cmpr_get_unit_id(ana_cmpr_handle_t cmpr)
|
||||||
{
|
{
|
||||||
if (!cmpr) {
|
if (!cmpr) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return cmpr->unit;
|
return cmpr->unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void ana_cmpr_override_default_log_level(void)
|
||||||
|
{
|
||||||
|
esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,30 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#if CONFIG_ETM_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 "freertos/FreeRTOS.h"
|
|
||||||
#include "esp_heap_caps.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "esp_check.h"
|
|
||||||
#include "soc/soc_caps.h"
|
|
||||||
#include "hal/ana_cmpr_ll.h"
|
|
||||||
#include "driver/ana_cmpr_types.h"
|
|
||||||
#include "driver/ana_cmpr_etm.h"
|
#include "driver/ana_cmpr_etm.h"
|
||||||
#include "esp_private/etm_interface.h"
|
#include "esp_private/etm_interface.h"
|
||||||
#include "ana_cmpr_private.h"
|
#include "ana_cmpr_private.h"
|
||||||
|
|
||||||
static const char *TAG = "ana-cmpr-etm";
|
|
||||||
|
|
||||||
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
#define ETM_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -35,18 +18,14 @@ static esp_err_t ana_cmpr_del_etm_event(esp_etm_event_handle_t base_event)
|
|||||||
{
|
{
|
||||||
ana_cmpr_etm_event_t *event = __containerof(base_event, ana_cmpr_etm_event_t, base);
|
ana_cmpr_etm_event_t *event = __containerof(base_event, ana_cmpr_etm_event_t, base);
|
||||||
free(event);
|
free(event);
|
||||||
event = NULL;
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ana_cmpr_new_etm_event(ana_cmpr_handle_t cmpr, const ana_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *ret_event)
|
esp_err_t ana_cmpr_new_etm_event(ana_cmpr_handle_t cmpr, const ana_cmpr_etm_event_config_t *config, esp_etm_event_handle_t *ret_event)
|
||||||
{
|
{
|
||||||
#if CONFIG_ETM_ENABLE_DEBUG_LOG
|
|
||||||
esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
|
||||||
#endif
|
|
||||||
esp_err_t ret = ESP_OK;
|
esp_err_t ret = ESP_OK;
|
||||||
ana_cmpr_etm_event_t *event = NULL;
|
ana_cmpr_etm_event_t *event = NULL;
|
||||||
ana_cmpr_unit_t unit = ana_cmpr_priv_get_unit_by_handle(cmpr);
|
ana_cmpr_unit_t unit = ana_cmpr_get_unit_id(cmpr);
|
||||||
ESP_RETURN_ON_FALSE(((int)unit) >= 0, ESP_ERR_INVALID_ARG, TAG, "invalid analog comparator handle");
|
ESP_RETURN_ON_FALSE(((int)unit) >= 0, ESP_ERR_INVALID_ARG, TAG, "invalid analog comparator handle");
|
||||||
ESP_RETURN_ON_FALSE(config && ret_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(config && ret_event, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
event = heap_caps_calloc(1, sizeof(ana_cmpr_etm_event_t), ETM_MEM_ALLOC_CAPS);
|
event = heap_caps_calloc(1, sizeof(ana_cmpr_etm_event_t), ETM_MEM_ALLOC_CAPS);
|
||||||
|
@ -1,19 +1,67 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#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
|
||||||
|
#endif
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "esp_intr_alloc.h"
|
||||||
#include "driver/ana_cmpr_types.h"
|
#include "driver/ana_cmpr_types.h"
|
||||||
|
#include "soc/soc_caps.h"
|
||||||
|
#include "hal/ana_cmpr_ll.h"
|
||||||
|
#include "soc/ana_cmpr_periph.h"
|
||||||
|
|
||||||
|
#define TAG "ana_cmpr"
|
||||||
|
|
||||||
|
#if CONFIG_ANA_CMPR_OBJ_CACHE_SAFE
|
||||||
|
#define ANA_CMPR_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||||
|
#else
|
||||||
|
#define ANA_CMPR_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_ANA_CMPR_ISR_CACHE_SAFE
|
||||||
|
// the interrupt source of Analog Comparator is marked as shared because
|
||||||
|
// it may share with other GPIO interrupt events
|
||||||
|
// it may share with different analog comparator units
|
||||||
|
#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_SHARED)
|
||||||
|
#else
|
||||||
|
#define ANA_CMPR_INTR_FLAG (ESP_INTR_FLAG_SHARED)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ANA_CMPR_ALLOW_INTR_PRIORITY_MASK ESP_INTR_FLAG_LOWMED
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ana_cmpr_unit_t ana_cmpr_priv_get_unit_by_handle(ana_cmpr_handle_t cmpr);
|
typedef enum {
|
||||||
|
ANA_CMPR_FSM_INIT, // Comparator is in the initialization stage, not enabled yet
|
||||||
|
ANA_CMPR_FSM_ENABLE, // Comparator is enabled
|
||||||
|
ANA_CMPR_FSM_WAIT, // Comparator is in the middle of state change, so busy, other operations should wait
|
||||||
|
} ana_cmpr_fsm_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the analog comparator unit id from the handle
|
||||||
|
*
|
||||||
|
* @param cmpr The handle of the analog comparator unit
|
||||||
|
* @return The id of the analog comparator unit
|
||||||
|
*/
|
||||||
|
ana_cmpr_unit_t ana_cmpr_get_unit_id(ana_cmpr_handle_t cmpr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -15,7 +15,6 @@ extern "C" {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator unit configuration
|
* @brief Analog comparator unit configuration
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ana_cmpr_unit_t unit; /*!< Analog comparator unit */
|
ana_cmpr_unit_t unit; /*!< Analog comparator unit */
|
||||||
@ -28,17 +27,15 @@ typedef struct {
|
|||||||
* for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO`
|
* for external reference, the reference signal should be connect to `ANA_CMPRx_EXT_REF_GPIO`
|
||||||
*/
|
*/
|
||||||
ana_cmpr_cross_type_t cross_type; /*!< The crossing types that can trigger interrupt */
|
ana_cmpr_cross_type_t cross_type; /*!< The crossing types that can trigger interrupt */
|
||||||
int intr_priority; /*!< The interrupt priority, range 0~7, if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3)
|
int intr_priority; /*!< The interrupt priority, range 1~3.
|
||||||
* otherwise the larger the higher, 7 is NMI */
|
If set to 0, the driver will automatically select a relative low priority (1,2,3) */
|
||||||
struct {
|
struct {
|
||||||
uint32_t io_loop_back: 1; /*!< Enable this field when the other signals that output on the comparison pins are supposed to be fed back.
|
uint32_t io_loop_back: 1; /*!< Deprecated. For debug/test, a signal output from other peripheral can work as comparator input. */
|
||||||
* Normally used for debug/test scenario */
|
|
||||||
} flags; /*!< Analog comparator driver flags */
|
} flags; /*!< Analog comparator driver flags */
|
||||||
} ana_cmpr_config_t;
|
} ana_cmpr_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator internal reference configuration
|
* @brief Analog comparator internal reference configuration
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can be specified to a certain fixed percentage of
|
ana_cmpr_ref_voltage_t ref_volt; /*!< The internal reference voltage. It can be specified to a certain fixed percentage of
|
||||||
@ -48,21 +45,18 @@ typedef struct {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator debounce filter configuration
|
* @brief Analog comparator debounce filter configuration
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t wait_us; /*!< The wait time of re-enabling the interrupt after the last triggering,
|
uint32_t wait_us; /*!< The wait time to prevent frequent interrupts caused by signal noise or bouncing.
|
||||||
* it is used to avoid the spurious triggering while the source signal crossing the reference signal.
|
During the specified wait_us period, no new interrupts will be triggered.
|
||||||
* The value should regarding how fast the source signal changes, e.g., a rapid signal requires
|
Set the value according to the signal characteristics. A rapid signal requires a small wait time,
|
||||||
* a small wait time, otherwise the next crosses may be missed.
|
otherwise the next cross event may be missed. */
|
||||||
* (Unit: micro second)
|
|
||||||
*/
|
|
||||||
} ana_cmpr_debounce_config_t;
|
} ana_cmpr_debounce_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Group of Analog Comparator callbacks
|
* @brief Group of Analog Comparator callbacks
|
||||||
* @note The callbacks are all running under ISR environment
|
* @note The callbacks are all running under ISR environment
|
||||||
* @note When CONFIG_ANA_CMPR_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
* @note When CONFIG_ANA_CMPR_ISR_CACHE_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
|
||||||
* The variables used in the function should be in the SRAM as well.
|
* The variables used in the function should be in the SRAM as well.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -95,9 +89,8 @@ esp_err_t ana_cmpr_del_unit(ana_cmpr_handle_t cmpr);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set internal reference configuration
|
* @brief Set internal reference configuration
|
||||||
* @note This function only need to be called when `ana_cmpr_config_t::ref_src`
|
* @note This function only need to be called when `ana_cmpr_config_t::ref_src` is set to `ANA_CMPR_REF_SRC_INTERNAL`.
|
||||||
* is ANA_CMPR_REF_SRC_INTERNAL.
|
* @note This function is allowed to run within ISR context including interrupt callbacks
|
||||||
* @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,
|
* @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
|
* so that it's allowed to be executed when Cache is disabled
|
||||||
*
|
*
|
||||||
@ -112,7 +105,7 @@ esp_err_t ana_cmpr_set_internal_reference(ana_cmpr_handle_t cmpr, const ana_cmpr
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set debounce configuration to the analog comparator
|
* @brief Set debounce configuration to the analog comparator
|
||||||
* @note This function is allowed to run within ISR context including intr callbacks
|
* @note This function is allowed to run within ISR context including interrupt callbacks
|
||||||
* @note This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on,
|
* @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
|
* so that it's allowed to be executed when Cache is disabled
|
||||||
*
|
*
|
||||||
@ -127,9 +120,8 @@ esp_err_t ana_cmpr_set_debounce(ana_cmpr_handle_t cmpr, const ana_cmpr_debounce_
|
|||||||
/**
|
/**
|
||||||
* @brief Set the source signal cross type
|
* @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 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 is allowed to run within ISR context including interrupt callbacks
|
||||||
* @note This function will be placed into IRAM if `CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` is on,
|
* @note This function must be called before `ana_cmpr_register_event_callbacks`
|
||||||
* so that it's allowed to be executed when Cache is disabled
|
|
||||||
*
|
*
|
||||||
* @param[in] cmpr The handle of analog comparator unit
|
* @param[in] cmpr The handle of analog comparator unit
|
||||||
* @param[in] cross_type The source signal cross type that can trigger the interrupt
|
* @param[in] cross_type The source signal cross type that can trigger the interrupt
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -17,7 +17,6 @@ extern "C" {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator unit
|
* @brief Analog comparator unit
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef int ana_cmpr_unit_t;
|
typedef int ana_cmpr_unit_t;
|
||||||
|
|
||||||
@ -25,16 +24,14 @@ typedef int ana_cmpr_unit_t;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator reference source
|
* @brief Analog comparator reference source
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ANA_CMPR_REF_SRC_INTERNAL, /*!< Analog Comparator internal reference source, related to VDD */
|
ANA_CMPR_REF_SRC_INTERNAL, /*!< Analog Comparator reference voltage comes from internal, divided from VDD */
|
||||||
ANA_CMPR_REF_SRC_EXTERNAL, /*!< Analog Comparator external reference source, from `ANA_CMPR0_EXT_REF_GPIO` */
|
ANA_CMPR_REF_SRC_EXTERNAL, /*!< Analog Comparator reference voltage comes from external pin, e.g. `ANA_CMPR0_EXT_REF_GPIO` */
|
||||||
} ana_cmpr_ref_source_t;
|
} ana_cmpr_ref_source_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator channel type
|
* @brief Analog comparator channel type
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ANA_CMPR_SOURCE_CHAN, /*!< Analog Comparator source channel, which is used to input the signal that to be compared */
|
ANA_CMPR_SOURCE_CHAN, /*!< Analog Comparator source channel, which is used to input the signal that to be compared */
|
||||||
@ -43,27 +40,23 @@ typedef enum {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator unit handle
|
* @brief Analog comparator unit handle
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct ana_cmpr_t *ana_cmpr_handle_t;
|
typedef struct ana_cmpr_t *ana_cmpr_handle_t;
|
||||||
|
|
||||||
#if SOC_ANA_CMPR_SUPPORTED
|
#if SOC_ANA_CMPR_SUPPORTED
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator clock source
|
* @brief Analog comparator clock source
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef soc_periph_ana_cmpr_clk_src_t ana_cmpr_clk_src_t;
|
typedef soc_periph_ana_cmpr_clk_src_t ana_cmpr_clk_src_t;
|
||||||
#else
|
#else
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator clock source
|
* @brief Analog comparator clock source
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef int ana_cmpr_clk_src_t;
|
typedef int ana_cmpr_clk_src_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Analog comparator cross event data
|
* @brief Analog comparator cross event data
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ana_cmpr_cross_type_t cross_type; /*!< The cross type of the target signal to the reference signal.
|
ana_cmpr_cross_type_t cross_type; /*!< The cross type of the target signal to the reference signal.
|
||||||
|
@ -5,3 +5,5 @@ entries:
|
|||||||
ana_cmpr: ana_cmpr_set_internal_reference (noflash)
|
ana_cmpr: ana_cmpr_set_internal_reference (noflash)
|
||||||
ana_cmpr: ana_cmpr_set_debounce (noflash)
|
ana_cmpr: ana_cmpr_set_debounce (noflash)
|
||||||
ana_cmpr: ana_cmpr_set_cross_type (noflash)
|
ana_cmpr: ana_cmpr_set_cross_type (noflash)
|
||||||
|
if ANA_CMPR_ISR_HANDLER_IN_IRAM = y:
|
||||||
|
ana_cmpr: ana_cmpr_default_intr_handler (noflash)
|
||||||
|
4
components/esp_driver_ana_cmpr/sdkconfig.rename
Normal file
4
components/esp_driver_ana_cmpr/sdkconfig.rename
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# sdkconfig replacement configurations for deprecated options formatted as
|
||||||
|
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
|
||||||
|
|
||||||
|
CONFIG_ANA_CMPR_ISR_IRAM_SAFE CONFIG_ANA_CMPR_ISR_CACHE_SAFE
|
@ -1,8 +1,8 @@
|
|||||||
set(srcs "test_app_main.c"
|
set(srcs "test_app_main.c"
|
||||||
"test_ana_cmpr_common.c"
|
"test_ana_cmpr_utils.c"
|
||||||
"test_ana_cmpr.c")
|
"test_ana_cmpr.c")
|
||||||
|
|
||||||
if(CONFIG_ANA_CMPR_ISR_IRAM_SAFE)
|
if(CONFIG_ANA_CMPR_ISR_CACHE_SAFE)
|
||||||
list(APPEND srcs "test_ana_cmpr_iram.c")
|
list(APPEND srcs "test_ana_cmpr_iram.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -13,5 +13,5 @@ endif()
|
|||||||
|
|
||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
PRIV_REQUIRES unity esp_driver_gpio esp_driver_ana_cmpr esp_driver_gptimer
|
PRIV_REQUIRES unity esp_driver_gpio esp_driver_ana_cmpr esp_driver_gptimer esp_pm
|
||||||
WHOLE_ARCHIVE)
|
WHOLE_ARCHIVE)
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_ana_cmpr.h"
|
#include "test_ana_cmpr.h"
|
||||||
|
|
||||||
TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]")
|
TEST_CASE("ana_cmpr unit install/uninstall", "[ana_cmpr]")
|
||||||
{
|
{
|
||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
@ -45,10 +45,11 @@ TEST_CASE("ana_cmpr_unit_install_uninstall", "[ana_cmpr]")
|
|||||||
config.ref_src = ANA_CMPR_REF_SRC_EXTERNAL;
|
config.ref_src = ANA_CMPR_REF_SRC_EXTERNAL;
|
||||||
TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr));
|
TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
||||||
|
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, ana_cmpr_del_unit(NULL));
|
||||||
TEST_ESP_OK(ana_cmpr_del_unit(cmpr));
|
TEST_ESP_OK(ana_cmpr_del_unit(cmpr));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("ana_cmpr_internal_reference", "[ana_cmpr]")
|
TEST_CASE("ana_cmpr internal reference", "[ana_cmpr]")
|
||||||
{
|
{
|
||||||
uint32_t cnt = 0;
|
uint32_t cnt = 0;
|
||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
@ -57,28 +58,29 @@ TEST_CASE("ana_cmpr_internal_reference", "[ana_cmpr]")
|
|||||||
.clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
|
.clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
|
||||||
.ref_src = ANA_CMPR_REF_SRC_INTERNAL,
|
.ref_src = ANA_CMPR_REF_SRC_INTERNAL,
|
||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
.flags.io_loop_back = 1,
|
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr));
|
TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
int src_chan = test_init_src_chan_gpio(TEST_ANA_CMPR_UNIT_ID);
|
int src_chan_io = test_init_src_chan_gpio(TEST_ANA_CMPR_UNIT_ID, 0);
|
||||||
ana_cmpr_internal_ref_config_t ref_cfg = {
|
ana_cmpr_internal_ref_config_t ref_cfg = {
|
||||||
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
||||||
ana_cmpr_debounce_config_t dbc_cfg = {
|
ana_cmpr_debounce_config_t dbc_cfg = {
|
||||||
.wait_us = 10.0,
|
.wait_us = 10,
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
|
TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
|
||||||
ana_cmpr_event_callbacks_t cbs = {
|
ana_cmpr_event_callbacks_t cbs = {
|
||||||
.on_cross = test_ana_cmpr_on_cross_callback,
|
.on_cross = test_ana_cmpr_on_cross_callback,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
printf("register ana_cmpr event callbacks\r\n");
|
||||||
TEST_ESP_OK(ana_cmpr_register_event_callbacks(cmpr, &cbs, &cnt));
|
TEST_ESP_OK(ana_cmpr_register_event_callbacks(cmpr, &cbs, &cnt));
|
||||||
TEST_ESP_OK(ana_cmpr_enable(cmpr));
|
TEST_ESP_OK(ana_cmpr_enable(cmpr));
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
for (uint32_t i = 1; i <= 10; i++) {
|
for (uint32_t i = 1; i <= 10; i++) {
|
||||||
test_simulate_src_signal(src_chan, i % 2);
|
gpio_set_level(src_chan_io, i % 2);
|
||||||
esp_rom_delay_us(100);
|
esp_rom_delay_us(100); // must be larger than the debounce time
|
||||||
|
// we assume the cross event was triggered already, and the value of cnt should be updated
|
||||||
TEST_ASSERT_EQUAL_UINT32(i, cnt);
|
TEST_ASSERT_EQUAL_UINT32(i, cnt);
|
||||||
}
|
}
|
||||||
TEST_ESP_OK(ana_cmpr_disable(cmpr));
|
TEST_ESP_OK(ana_cmpr_disable(cmpr));
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -15,14 +15,20 @@
|
|||||||
#include "esp_rom_sys.h"
|
#include "esp_rom_sys.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "driver/ana_cmpr.h"
|
#include "driver/ana_cmpr.h"
|
||||||
|
#include "driver/ana_cmpr_etm.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32P4
|
#if CONFIG_IDF_TARGET_ESP32P4
|
||||||
// The pin of unit 0 is used for other purpose on P4 runner, use unit 1 instead
|
// The pin of unit 0 is not exposed on some ESP32-P4 runner, so test unit 1 by default
|
||||||
#define TEST_ANA_CMPR_UNIT_ID 1
|
#define TEST_ANA_CMPR_UNIT_ID 1
|
||||||
#else
|
#else
|
||||||
#define TEST_ANA_CMPR_UNIT_ID 0
|
#define TEST_ANA_CMPR_UNIT_ID 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Test default on cross callback
|
* @brief Test default on cross callback
|
||||||
*
|
*
|
||||||
@ -38,15 +44,14 @@ bool test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana_cmpr_cros
|
|||||||
/**
|
/**
|
||||||
* @brief Initialize Analog Comparator source channel GPIO
|
* @brief Initialize Analog Comparator source channel GPIO
|
||||||
*
|
*
|
||||||
|
* @param unit_id Analog Comparator unit ID
|
||||||
|
* @param init_level Initial level of the GPIO
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* - int Source channel GPIO number
|
* - int Source channel GPIO number
|
||||||
*/
|
*/
|
||||||
int test_init_src_chan_gpio(int unit_id);
|
int test_init_src_chan_gpio(int unit_id, int init_level);
|
||||||
|
|
||||||
/**
|
#ifdef __cplusplus
|
||||||
* @brief Simulate source channel signal
|
}
|
||||||
*
|
#endif
|
||||||
* @param src_chan Source channel GPIO number
|
|
||||||
* @param val 0 to set low, others to set high
|
|
||||||
*/
|
|
||||||
void test_simulate_src_signal(int src_chan, uint32_t val);
|
|
||||||
|
@ -1,22 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "unity.h"
|
|
||||||
#include "unity_test_utils.h"
|
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
#include "esp_etm.h"
|
#include "esp_etm.h"
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/gptimer.h"
|
#include "driver/gptimer.h"
|
||||||
#include "driver/ana_cmpr.h"
|
|
||||||
#include "driver/gptimer_etm.h"
|
#include "driver/gptimer_etm.h"
|
||||||
#include "driver/ana_cmpr_etm.h"
|
#include "test_ana_cmpr.h"
|
||||||
|
|
||||||
#define TEST_ANA_CMPR_UNIT 0
|
|
||||||
#define TEST_TIME_US 5000
|
#define TEST_TIME_US 5000
|
||||||
|
|
||||||
static gptimer_handle_t test_ana_cmpr_gptimer_init(void)
|
static gptimer_handle_t test_ana_cmpr_gptimer_init(void)
|
||||||
@ -44,7 +40,7 @@ static ana_cmpr_handle_t test_ana_cmpr_init(void)
|
|||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
|
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
.unit = TEST_ANA_CMPR_UNIT,
|
.unit = TEST_ANA_CMPR_UNIT_ID,
|
||||||
.clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
|
.clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
|
||||||
.ref_src = ANA_CMPR_REF_SRC_INTERNAL,
|
.ref_src = ANA_CMPR_REF_SRC_INTERNAL,
|
||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
@ -71,22 +67,6 @@ static void test_ana_cmpr_deinit(ana_cmpr_handle_t cmpr)
|
|||||||
TEST_ESP_OK(ana_cmpr_del_unit(cmpr));
|
TEST_ESP_OK(ana_cmpr_del_unit(cmpr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_ana_cmpr_src_gpio_init(void)
|
|
||||||
{
|
|
||||||
int gpio_num = -1;
|
|
||||||
TEST_ESP_OK(ana_cmpr_get_gpio(TEST_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &gpio_num));
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
.pin_bit_mask = (1ULL << gpio_num),
|
|
||||||
.pull_down_en = false,
|
|
||||||
.pull_up_en = false,
|
|
||||||
};
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
gpio_set_level(gpio_num, 1);
|
|
||||||
return gpio_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
esp_etm_event_handle_t cmpr_pos_evt;
|
esp_etm_event_handle_t cmpr_pos_evt;
|
||||||
esp_etm_event_handle_t cmpr_neg_evt;
|
esp_etm_event_handle_t cmpr_neg_evt;
|
||||||
@ -145,14 +125,17 @@ static void test_ana_cmpr_deinit_etm(test_ana_cmpr_etm_handles_t handles)
|
|||||||
TEST_ESP_OK(esp_etm_del_channel(handles.etm_neg_handle));
|
TEST_ESP_OK(esp_etm_del_channel(handles.etm_neg_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("analog_comparator_etm_event", "[etm]")
|
TEST_CASE("ana_cmpr etm event", "[ana_cmpr][etm]")
|
||||||
{
|
{
|
||||||
gptimer_handle_t gptimer = test_ana_cmpr_gptimer_init();
|
gptimer_handle_t gptimer = test_ana_cmpr_gptimer_init();
|
||||||
ana_cmpr_handle_t cmpr = test_ana_cmpr_init();
|
ana_cmpr_handle_t cmpr = test_ana_cmpr_init();
|
||||||
int src_gpio = test_ana_cmpr_src_gpio_init();
|
int src_gpio = test_init_src_chan_gpio(TEST_ANA_CMPR_UNIT_ID, 1);
|
||||||
test_ana_cmpr_etm_handles_t handles = test_ana_cmpr_init_etm(cmpr, gptimer);
|
test_ana_cmpr_etm_handles_t handles = test_ana_cmpr_init_etm(cmpr, gptimer);
|
||||||
|
|
||||||
// triggers a negative pulse, whose duration is ~TEST_TIME_US
|
// triggers a negative pulse, whose duration is ~TEST_TIME_US
|
||||||
|
// negedge triggers the gptimer to start task
|
||||||
|
// posedge triggers the gptimer to stop task
|
||||||
|
// gptimer will record the time between the negedge and posedge
|
||||||
gpio_set_level(src_gpio, 0);
|
gpio_set_level(src_gpio, 0);
|
||||||
esp_rom_delay_us(TEST_TIME_US);
|
esp_rom_delay_us(TEST_TIME_US);
|
||||||
gpio_set_level(src_gpio, 1);
|
gpio_set_level(src_gpio, 1);
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_ana_cmpr.h"
|
#include "test_ana_cmpr.h"
|
||||||
#include "unity_test_utils.h"
|
|
||||||
#include "unity_test_utils_cache.h"
|
#include "unity_test_utils_cache.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ana_cmpr_handle_t handle;
|
ana_cmpr_handle_t handle;
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
int src_chan;
|
int src_chan_io;
|
||||||
} test_ana_cmpr_data_t;
|
} test_ana_cmpr_data_t;
|
||||||
|
|
||||||
static void IRAM_ATTR test_ana_cmpr_iram_safety(void *args)
|
static void IRAM_ATTR test_ana_cmpr_iram_safety(void *args)
|
||||||
@ -26,40 +25,41 @@ static void IRAM_ATTR test_ana_cmpr_iram_safety(void *args)
|
|||||||
};
|
};
|
||||||
ana_cmpr_set_debounce(data->handle, &dbc_cfg);
|
ana_cmpr_set_debounce(data->handle, &dbc_cfg);
|
||||||
data->count = 0;
|
data->count = 0;
|
||||||
|
|
||||||
|
// generate 10 cross events by toggling the GPIO
|
||||||
for (int i = 1; i <= 10; i++) {
|
for (int i = 1; i <= 10; i++) {
|
||||||
test_simulate_src_signal(data->src_chan, i % 2);
|
gpio_set_level(data->src_chan_io, i % 2);
|
||||||
esp_rom_delay_us(100);
|
esp_rom_delay_us(100);
|
||||||
}
|
}
|
||||||
ana_cmpr_set_cross_type(data->handle, ANA_CMPR_CROSS_POS);
|
ana_cmpr_set_cross_type(data->handle, ANA_CMPR_CROSS_POS);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("ana_cmpr_internal_reference_iram_safe", "[ana_cmpr]")
|
TEST_CASE("ana_cmpr works with cache disabled", "[ana_cmpr]")
|
||||||
{
|
{
|
||||||
test_ana_cmpr_data_t test_data = {
|
|
||||||
.handle = NULL,
|
|
||||||
.count = 0,
|
|
||||||
.src_chan = -1,
|
|
||||||
};
|
|
||||||
test_data.src_chan = test_init_src_chan_gpio(TEST_ANA_CMPR_UNIT_ID);
|
|
||||||
|
|
||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
.unit = TEST_ANA_CMPR_UNIT_ID,
|
.unit = TEST_ANA_CMPR_UNIT_ID,
|
||||||
.clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
|
.clk_src = ANA_CMPR_CLK_SRC_DEFAULT,
|
||||||
.ref_src = ANA_CMPR_REF_SRC_INTERNAL,
|
.ref_src = ANA_CMPR_REF_SRC_INTERNAL,
|
||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
.flags.io_loop_back = 1,
|
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr));
|
TEST_ESP_OK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
test_data.handle = cmpr;
|
|
||||||
ana_cmpr_internal_ref_config_t ref_cfg = {
|
ana_cmpr_internal_ref_config_t ref_cfg = {
|
||||||
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
.ref_volt = ANA_CMPR_REF_VOLT_20_PCT_VDD,
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
TEST_ESP_OK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
||||||
ana_cmpr_debounce_config_t dbc_cfg = {
|
ana_cmpr_debounce_config_t dbc_cfg = {
|
||||||
.wait_us = 10,
|
.wait_us = 10,
|
||||||
};
|
};
|
||||||
TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
|
TEST_ESP_OK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
|
||||||
|
|
||||||
|
test_ana_cmpr_data_t test_data = {
|
||||||
|
.handle = cmpr,
|
||||||
|
.count = 0,
|
||||||
|
.src_chan_io = test_init_src_chan_gpio(TEST_ANA_CMPR_UNIT_ID, 0),
|
||||||
|
};
|
||||||
|
|
||||||
ana_cmpr_event_callbacks_t cbs = {
|
ana_cmpr_event_callbacks_t cbs = {
|
||||||
.on_cross = test_ana_cmpr_on_cross_callback,
|
.on_cross = test_ana_cmpr_on_cross_callback,
|
||||||
};
|
};
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "test_ana_cmpr.h"
|
#include "test_ana_cmpr.h"
|
||||||
#include "hal/gpio_ll.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "esp_private/gpio.h"
|
#include "esp_private/gpio.h"
|
||||||
#include "esp_attr.h"
|
#include "esp_attr.h"
|
||||||
|
|
||||||
@ -17,17 +15,12 @@ bool IRAM_ATTR test_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr, const ana
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_init_src_chan_gpio(int unit_id)
|
int test_init_src_chan_gpio(int unit_id, int init_level)
|
||||||
{
|
{
|
||||||
int src_chan_num = -1;
|
int src_chan_num = -1;
|
||||||
TEST_ESP_OK(ana_cmpr_get_gpio(unit_id, ANA_CMPR_SOURCE_CHAN, &src_chan_num));
|
TEST_ESP_OK(ana_cmpr_get_gpio(unit_id, ANA_CMPR_SOURCE_CHAN, &src_chan_num));
|
||||||
TEST_ASSERT(src_chan_num > 0);
|
TEST_ASSERT(src_chan_num >= 0);
|
||||||
TEST_ESP_OK(gpio_set_level(src_chan_num, 0));
|
TEST_ESP_OK(gpio_set_level(src_chan_num, init_level));
|
||||||
TEST_ESP_OK(gpio_output_enable(src_chan_num));
|
TEST_ESP_OK(gpio_output_enable(src_chan_num));
|
||||||
return src_chan_num;
|
return src_chan_num;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR test_simulate_src_signal(int src_chan, uint32_t val)
|
|
||||||
{
|
|
||||||
gpio_set_level(src_chan, val);
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -17,7 +17,7 @@ static size_t before_free_32bit;
|
|||||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||||
{
|
{
|
||||||
ssize_t delta = after_free - before_free;
|
ssize_t delta = after_free - before_free;
|
||||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\\n", type, before_free, after_free, delta);
|
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ from pytest_embedded_idf.utils import idf_parametrize
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'config',
|
'config',
|
||||||
[
|
[
|
||||||
'iram_safe',
|
'cache_safe',
|
||||||
'release',
|
'release',
|
||||||
],
|
],
|
||||||
indirect=True,
|
indirect=True,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||||
CONFIG_ANA_CMPR_ISR_IRAM_SAFE=y
|
CONFIG_ANA_CMPR_ISR_CACHE_SAFE=y
|
||||||
CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM=y
|
CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM=y
|
||||||
CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y
|
CONFIG_GPIO_CTRL_FUNC_IN_IRAM=y
|
||||||
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
CONFIG_COMPILER_OPTIMIZATION_NONE=y
|
@ -1,5 +1,6 @@
|
|||||||
CONFIG_PM_ENABLE=y
|
CONFIG_PM_ENABLE=y
|
||||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||||
|
CONFIG_PM_DFS_INIT_AUTO=y
|
||||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||||
|
@ -19,10 +19,12 @@ extern "C" {
|
|||||||
|
|
||||||
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
||||||
#define ANALOG_CMPR_LL_GET_UNIT(hw) (0)
|
#define ANALOG_CMPR_LL_GET_UNIT(hw) (0)
|
||||||
#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0)
|
|
||||||
|
|
||||||
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3))
|
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0))
|
||||||
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
||||||
|
#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2))
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit))
|
||||||
|
|
||||||
#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type))
|
#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type))
|
||||||
|
|
||||||
|
@ -19,10 +19,12 @@ extern "C" {
|
|||||||
|
|
||||||
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
||||||
#define ANALOG_CMPR_LL_GET_UNIT(hw) (0)
|
#define ANALOG_CMPR_LL_GET_UNIT(hw) (0)
|
||||||
#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0)
|
|
||||||
|
|
||||||
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3))
|
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0))
|
||||||
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
||||||
|
#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2))
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit))
|
||||||
|
|
||||||
#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type))
|
#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type))
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
||||||
#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0)
|
#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0)
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_EVENT_CROSS)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -77,7 +79,7 @@ static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr
|
|||||||
* - 3: enable any positive or negative cross interrupt
|
* - 3: enable any positive or negative cross interrupt
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline))
|
__attribute__((always_inline))
|
||||||
static inline void analog_cmpr_ll_set_cross_type(analog_cmpr_dev_t *hw, uint8_t type)
|
static inline void analog_cmpr_ll_set_intr_cross_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type)
|
||||||
{
|
{
|
||||||
hw->pad_comp_config->zero_det_mode = type;
|
hw->pad_comp_config->zero_det_mode = type;
|
||||||
}
|
}
|
||||||
|
168
components/hal/esp32h21/include/hal/ana_cmpr_ll.h
Normal file
168
components/hal/esp32h21/include/hal/ana_cmpr_ll.h
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "hal/misc.h"
|
||||||
|
#include "hal/assert.h"
|
||||||
|
#include "hal/ana_cmpr_types.h"
|
||||||
|
#include "soc/ana_cmpr_struct.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
||||||
|
#define ANALOG_CMPR_LL_GET_UNIT(hw) (0)
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0))
|
||||||
|
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
||||||
|
#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2))
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable analog comparator
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param en True to enable, False to disable
|
||||||
|
*/
|
||||||
|
static inline void analog_cmpr_ll_enable(analog_cmpr_dev_t *hw, bool en)
|
||||||
|
{
|
||||||
|
hw->pad_comp_config->ext_xpd_comp_0 = en;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the voltage of the internal reference
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param volt_level The voltage level of the internal reference, range [0.0V, 0.7VDD], step 0.1VDD
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void analog_cmpr_ll_set_internal_ref_voltage(analog_cmpr_dev_t *hw, uint32_t volt_level)
|
||||||
|
{
|
||||||
|
hw->pad_comp_config->ext_dref_comp_0 = volt_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the voltage of the internal reference
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @return The voltage of the internal reference
|
||||||
|
*/
|
||||||
|
static inline float analog_cmpr_ll_get_internal_ref_voltage(analog_cmpr_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->pad_comp_config->ext_dref_comp_0 * 0.1F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The reference voltage comes from internal or external
|
||||||
|
*
|
||||||
|
* @note Also see `analog_cmpr_ll_set_internal_ref_voltage` to use the internal reference voltage
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param ref_src reference source, 0 for internal, 1 for external GPIO pad (GPIO10)
|
||||||
|
*/
|
||||||
|
static inline void analog_cmpr_ll_set_ref_source(analog_cmpr_dev_t *hw, ana_cmpr_ref_voltage_t ref_src)
|
||||||
|
{
|
||||||
|
hw->pad_comp_config->ext_mode_comp_0 = ref_src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the interrupt mask by trigger type
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param type The type of cross interrupt
|
||||||
|
* - 0: disable interrupt
|
||||||
|
* - 1: enable positive cross interrupt (input analog goes from low to high and across the reference voltage)
|
||||||
|
* - 2: enable negative cross interrupt (input analog goes from high to low and across the reference voltage)
|
||||||
|
* - 3: enable any positive or negative cross interrupt
|
||||||
|
* @return interrupt mask
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline uint32_t analog_cmpr_ll_get_intr_mask_by_type(analog_cmpr_dev_t *hw, ana_cmpr_cross_type_t type)
|
||||||
|
{
|
||||||
|
uint32_t unit = ANALOG_CMPR_LL_GET_UNIT(hw);
|
||||||
|
uint32_t mask = 0;
|
||||||
|
if (type & 0x01) {
|
||||||
|
mask |= ANALOG_CMPR_LL_POS_CROSS_MASK(unit);
|
||||||
|
}
|
||||||
|
if (type & 0x02) {
|
||||||
|
mask |= ANALOG_CMPR_LL_NEG_CROSS_MASK(unit);
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the debounce cycle for the cross detection
|
||||||
|
*
|
||||||
|
* @note When the comparator detects a cross, it will wait for the debounce cycle to make sure the cross is stable.
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param cycle The debounce cycle
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void analog_cmpr_ll_set_debounce_cycle(analog_cmpr_dev_t *hw, uint32_t cycle)
|
||||||
|
{
|
||||||
|
hw->pad_comp_filter->ext_zero_det_filter_cnt_0 = cycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable comparator interrupt
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param mask Interrupt mask
|
||||||
|
* @param enable True to enable, False to disable
|
||||||
|
*/
|
||||||
|
static inline void analog_cmpr_ll_enable_intr(analog_cmpr_dev_t *hw, uint32_t mask, bool enable)
|
||||||
|
{
|
||||||
|
uint32_t val = hw->int_ena->val;
|
||||||
|
if (enable) {
|
||||||
|
val |= mask;
|
||||||
|
} else {
|
||||||
|
val &= ~mask;
|
||||||
|
}
|
||||||
|
hw->int_ena->val = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get comparator interrupt status
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline uint32_t analog_cmpr_ll_get_intr_status(analog_cmpr_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->int_st->val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear comparator interrupt status
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @param mask Interrupt status word
|
||||||
|
*/
|
||||||
|
__attribute__((always_inline))
|
||||||
|
static inline void analog_cmpr_ll_clear_intr(analog_cmpr_dev_t *hw, uint32_t mask)
|
||||||
|
{
|
||||||
|
hw->int_clr->val = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the interrupt status register address
|
||||||
|
*
|
||||||
|
* @param hw Analog comparator register base address
|
||||||
|
* @return The interrupt status register address
|
||||||
|
*/
|
||||||
|
static inline volatile void *analog_cmpr_ll_get_intr_status_reg(analog_cmpr_dev_t *hw)
|
||||||
|
{
|
||||||
|
return hw->int_st;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -19,10 +19,12 @@ extern "C" {
|
|||||||
|
|
||||||
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
#define ANALOG_CMPR_LL_GET_HW(unit) (&ANALOG_CMPR[unit])
|
||||||
#define ANALOG_CMPR_LL_GET_UNIT(hw) ((hw) == (&ANALOG_CMPR[0]) ? 0 : 1)
|
#define ANALOG_CMPR_LL_GET_UNIT(hw) ((hw) == (&ANALOG_CMPR[0]) ? 0 : 1)
|
||||||
#define ANALOG_CMPR_LL_EVENT_CROSS (1 << 0)
|
|
||||||
|
|
||||||
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3))
|
#define ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 0))
|
||||||
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
#define ANALOG_CMPR_LL_POS_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 1))
|
||||||
|
#define ANALOG_CMPR_LL_ANY_CROSS_MASK(unit) (1UL << ((int)unit * 3 + 2))
|
||||||
|
|
||||||
|
#define ANALOG_CMPR_LL_ALL_INTR_MASK(unit) (ANALOG_CMPR_LL_NEG_CROSS_MASK(unit) | ANALOG_CMPR_LL_POS_CROSS_MASK(unit) | ANALOG_CMPR_LL_ANY_CROSS_MASK(unit))
|
||||||
|
|
||||||
#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type))
|
#define ANALOG_CMPR_LL_ETM_SOURCE(unit, type) (GPIO_EVT_ZERO_DET_POS0 + (unit) * 2 + (type))
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -12,6 +12,7 @@ const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM] = {
|
|||||||
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
||||||
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
||||||
.intr_src = ETS_GPIO_EXT_SOURCE,
|
.intr_src = ETS_GPIO_EXT_SOURCE,
|
||||||
|
.module_name = "ANA_CMPR_U0",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -12,6 +12,7 @@ const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM] = {
|
|||||||
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
||||||
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
||||||
.intr_src = ETS_GPIO_INTERRUPT_EXT_SOURCE,
|
.intr_src = ETS_GPIO_INTERRUPT_EXT_SOURCE,
|
||||||
|
.module_name = "ANA_CMPR_U0",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -12,6 +12,7 @@ const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM] = {
|
|||||||
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
||||||
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
||||||
.intr_src = ETS_GPIO_INTR_SOURCE,
|
.intr_src = ETS_GPIO_INTR_SOURCE,
|
||||||
|
.module_name = "ANA_CMPR_U0",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
36
components/soc/esp32h21/include/soc/ana_cmpr_struct.h
Normal file
36
components/soc/esp32h21/include/soc/ana_cmpr_struct.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NOTE: this file is created manually for compatibility */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "soc/gpio_ext_struct.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Analog Comparator Device struct
|
||||||
|
* @note The field in it are register pointers, which point to the physical address
|
||||||
|
* of the corresponding configuration register
|
||||||
|
* @note see 'ana_cmpr_periph.c' for the device instance
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
volatile gpio_ext_pad_comp_config_0_reg_t *pad_comp_config;
|
||||||
|
volatile gpio_ext_pad_comp_filter_0_reg_t *pad_comp_filter;
|
||||||
|
volatile gpio_ext_int_st_reg_t *int_st;
|
||||||
|
volatile gpio_ext_int_ena_reg_t *int_ena;
|
||||||
|
volatile gpio_ext_int_clr_reg_t *int_clr;
|
||||||
|
} analog_cmpr_dev_t;
|
||||||
|
|
||||||
|
extern analog_cmpr_dev_t ANALOG_CMPR[1];
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -12,11 +12,13 @@ const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM] = {
|
|||||||
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
.src_gpio = ANA_CMPR0_SRC_GPIO,
|
||||||
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
.ext_ref_gpio = ANA_CMPR0_EXT_REF_GPIO,
|
||||||
.intr_src = ETS_GPIO_PAD_COMP_INTR_SOURCE,
|
.intr_src = ETS_GPIO_PAD_COMP_INTR_SOURCE,
|
||||||
|
.module_name = "ANA_CMPR_U0",
|
||||||
},
|
},
|
||||||
[1] = {
|
[1] = {
|
||||||
.src_gpio = ANA_CMPR1_SRC_GPIO,
|
.src_gpio = ANA_CMPR1_SRC_GPIO,
|
||||||
.ext_ref_gpio = ANA_CMPR1_EXT_REF_GPIO,
|
.ext_ref_gpio = ANA_CMPR1_EXT_REF_GPIO,
|
||||||
.intr_src = ETS_GPIO_PAD_COMP_INTR_SOURCE,
|
.intr_src = ETS_GPIO_PAD_COMP_INTR_SOURCE,
|
||||||
|
.module_name = "ANA_CMPR_U1",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -10,7 +10,7 @@
|
|||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
#include "soc/interrupts.h"
|
#include "soc/interrupts.h"
|
||||||
#if SOC_ANA_CMPR_SUPPORTED
|
#if SOC_ANA_CMPR_SUPPORTED
|
||||||
#include "soc/ana_cmpr_channel.h"
|
#include "soc/ana_cmpr_pins.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -22,6 +22,7 @@ typedef struct {
|
|||||||
int src_gpio;
|
int src_gpio;
|
||||||
int ext_ref_gpio;
|
int ext_ref_gpio;
|
||||||
int intr_src;
|
int intr_src;
|
||||||
|
const char *module_name;
|
||||||
} ana_cmpr_periph_t;
|
} ana_cmpr_periph_t;
|
||||||
|
|
||||||
extern const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM];
|
extern const ana_cmpr_periph_t ana_cmpr_periph[SOC_ANA_CMPR_NUM];
|
||||||
|
@ -141,7 +141,7 @@ Currently it supports :cpp:member:`ana_cmpr_event_callbacks_t::on_cross`, and it
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
When :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` is enabled, you should guarantee that the callback context and involved data are in internal RAM by adding the attribute ``IRAM_ATTR`` (See more in :ref:`anacmpr-iram-safe`).
|
When :ref:`CONFIG_ANA_CMPR_ISR_CACHE_SAFE` is enabled, you should guarantee that the callback context and involved data are in internal RAM by adding the attribute ``IRAM_ATTR`` (See more in :ref:`anacmpr-iram-safe`).
|
||||||
|
|
||||||
.. _anacmpr-enable-and-disable-unit:
|
.. _anacmpr-enable-and-disable-unit:
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ IRAM Safe
|
|||||||
|
|
||||||
By default, the analog comparator interrupt will be deferred when the cache is disabled for reasons like programming or erasing the flash. Thus the alarm interrupt will not get executed in time, which is not expected in a real-time application.
|
By default, the analog comparator interrupt will be deferred when the cache is disabled for reasons like programming or erasing the flash. Thus the alarm interrupt will not get executed in time, which is not expected in a real-time application.
|
||||||
|
|
||||||
There is a Kconfig option :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` that:
|
There is a Kconfig option :ref:`CONFIG_ANA_CMPR_ISR_CACHE_SAFE` that:
|
||||||
|
|
||||||
1. Enables the interrupt being serviced even when cache is disabled.
|
1. Enables the interrupt being serviced even when cache is disabled.
|
||||||
2. Places all functions that used by the ISR into IRAM. [1]_
|
2. Places all functions that used by the ISR into IRAM. [1]_
|
||||||
@ -205,7 +205,7 @@ Other functions that take :cpp:type:`ana_cmpr_handle_t` as the first positional
|
|||||||
Kconfig Options
|
Kconfig Options
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
- :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` controls whether the default ISR handler can work when cache is disabled. See :ref:`anacmpr-iram-safe` for more information.
|
- :ref:`CONFIG_ANA_CMPR_ISR_CACHE_SAFE` controls whether the default ISR handler can work when cache is disabled. See :ref:`anacmpr-iram-safe` for more information.
|
||||||
- :ref:`CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` controls where to place the analog comparator control functions (IRAM or flash). See :ref:`anacmpr-iram-safe` for more information.
|
- :ref:`CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` controls where to place the analog comparator control functions (IRAM or flash). See :ref:`anacmpr-iram-safe` for more information.
|
||||||
- :ref:`CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG` is used to enable the debug log output. Enabling this option increases the firmware binary size.
|
- :ref:`CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG` is used to enable the debug log output. Enabling this option increases the firmware binary size.
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
当启用 :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` 时,应添加属性 ``IRAM_ATTR``,确保回调上下文和涉及的数据位于内部 RAM 中(详情请参阅 :ref:`anacmpr-iram-safe`)。
|
当启用 :ref:`CONFIG_ANA_CMPR_ISR_CACHE_SAFE` 时,应添加属性 ``IRAM_ATTR``,确保回调上下文和涉及的数据位于内部 RAM 中(详情请参阅 :ref:`anacmpr-iram-safe`)。
|
||||||
|
|
||||||
.. _anacmpr-enable-and-disable-unit:
|
.. _anacmpr-enable-and-disable-unit:
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ IRAM 安全
|
|||||||
|
|
||||||
默认情况下,当 cache 因写入或擦除 flash 等原因而被禁用时,模拟比较器的中断服务将会延迟,造成警报中断无法及时执行。在实时应用程序中通常需要避免这一情况发生。
|
默认情况下,当 cache 因写入或擦除 flash 等原因而被禁用时,模拟比较器的中断服务将会延迟,造成警报中断无法及时执行。在实时应用程序中通常需要避免这一情况发生。
|
||||||
|
|
||||||
Kconfig 选项 :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` 支持:
|
Kconfig 选项 :ref:`CONFIG_ANA_CMPR_ISR_CACHE_SAFE` 支持:
|
||||||
|
|
||||||
1. 即使 cache 被禁用也能启用中断服务。
|
1. 即使 cache 被禁用也能启用中断服务。
|
||||||
2. 将 ISR 使用的所有函数放入 IRAM。 [1]_
|
2. 将 ISR 使用的所有函数放入 IRAM。 [1]_
|
||||||
@ -205,7 +205,7 @@ Kconfig 选项 :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` 支持:
|
|||||||
Kconfig 选项
|
Kconfig 选项
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
- :ref:`CONFIG_ANA_CMPR_ISR_IRAM_SAFE` 控制默认的 ISR 句柄在 cache 被禁用时是否可以正常工作,详见 :ref:`anacmpr-iram-safe`。
|
- :ref:`CONFIG_ANA_CMPR_ISR_CACHE_SAFE` 控制默认的 ISR 句柄在 cache 被禁用时是否可以正常工作,详见 :ref:`anacmpr-iram-safe`。
|
||||||
- :ref:`CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` 控制模拟比较器控制函数的存放位置(IRAM 或 flash),详见 :ref:`anacmpr-iram-safe`。
|
- :ref:`CONFIG_ANA_CMPR_CTRL_FUNC_IN_IRAM` 控制模拟比较器控制函数的存放位置(IRAM 或 flash),详见 :ref:`anacmpr-iram-safe`。
|
||||||
- :ref:`CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG` 用于启用调试日志输出。启用此选项将增加固件的二进制文件大小。
|
- :ref:`CONFIG_ANA_CMPR_ENABLE_DEBUG_LOG` 用于启用调试日志输出。启用此选项将增加固件的二进制文件大小。
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
set(src "ana_cmpr_example_main.c")
|
set(src "ana_cmpr_example_main.c")
|
||||||
|
|
||||||
if(CONFIG_EXAMPLE_USE_ETM)
|
if(CONFIG_EXAMPLE_MONITOR_IO_FROM_ETM)
|
||||||
list(APPEND src "ana_cmpr_example_etm.c")
|
list(APPEND src "ana_cmpr_example_etm.c")
|
||||||
else()
|
else()
|
||||||
list(APPEND src "ana_cmpr_example_intr.c")
|
list(APPEND src "ana_cmpr_example_intr.c")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
idf_component_register(SRCS ${src}
|
idf_component_register(SRCS ${src}
|
||||||
PRIV_REQUIRES esp_driver_ana_cmpr esp_driver_gpio
|
PRIV_REQUIRES esp_driver_ana_cmpr esp_driver_gpio
|
||||||
INCLUDE_DIRS ".")
|
INCLUDE_DIRS ".")
|
||||||
|
@ -1,39 +1,41 @@
|
|||||||
menu "Analog Comparator Example Configuration"
|
menu "Example Configuration"
|
||||||
|
|
||||||
choice EXAMPLE_REALIZATION
|
choice EXAMPLE_MONITOR_IO_FROM
|
||||||
prompt "Analog Comparator example realization methods"
|
prompt "Monitor IO signal comes from"
|
||||||
default EXAMPLE_USE_ETM if SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM
|
default EXAMPLE_MONITOR_IO_FROM_ETM if SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM
|
||||||
default EXAMPLE_USE_INTR if !SOC_ANA_CMPR_SUPPORT_ETM || !SOC_GPIO_SUPPORT_ETM
|
default EXAMPLE_MONITOR_IO_FROM_INTR
|
||||||
config EXAMPLE_USE_INTR
|
|
||||||
bool "Use Interrupt"
|
config EXAMPLE_MONITOR_IO_FROM_INTR
|
||||||
|
bool "Analog Comparator Interrupt"
|
||||||
help
|
help
|
||||||
Enable to set the monitor GPIO via interrupt callback
|
Enable to set the monitor GPIO via interrupt callback
|
||||||
config EXAMPLE_USE_ETM
|
|
||||||
|
config EXAMPLE_MONITOR_IO_FROM_ETM
|
||||||
depends on SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM
|
depends on SOC_ANA_CMPR_SUPPORT_ETM && SOC_GPIO_SUPPORT_ETM
|
||||||
bool "Use ETM"
|
bool "Analog Comparator Event-Task-Matrix"
|
||||||
help
|
help
|
||||||
Enable to set the monitor GPIO via Event Task Matrix
|
Enable to set the monitor GPIO via Event Task Matrix
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
choice EXAMPLE_REFERENCE_SOURCE
|
choice EXAMPLE_REF_FROM
|
||||||
prompt "Analog Comparator reference source"
|
prompt "Analog Comparator reference voltage comes from"
|
||||||
default EXAMPLE_INTERNAL_REF
|
default EXAMPLE_REF_FROM_INTERNAL
|
||||||
help
|
help
|
||||||
Decide the reference signal comes from internal or external
|
Decide the reference voltage comes from internal or external
|
||||||
|
|
||||||
config EXAMPLE_INTERNAL_REF
|
config EXAMPLE_REF_FROM_INTERNAL
|
||||||
bool "Internal reference"
|
bool "Internal"
|
||||||
help
|
help
|
||||||
The source signal will refer to an internal voltage, which related to VDD.
|
The source signal will refer to an internal voltage, which is divided from VDD.
|
||||||
|
|
||||||
config EXAMPLE_EXTERNAL_REF
|
config EXAMPLE_REF_FROM_EXTERNAL
|
||||||
bool "External reference"
|
bool "External pin"
|
||||||
help
|
help
|
||||||
The source signal will refer to the external signal on a specific GPIO.
|
The source signal will refer to the external signal on a specific GPIO.
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config EXAMPLE_HYSTERESIS_COMPARATOR
|
config EXAMPLE_HYSTERESIS_COMPARATOR
|
||||||
depends on EXAMPLE_INTERNAL_REF && !EXAMPLE_USE_ETM
|
depends on EXAMPLE_REF_FROM_INTERNAL && EXAMPLE_MONITOR_IO_FROM_INTR
|
||||||
bool "Enable hysteresis comparator"
|
bool "Enable hysteresis comparator"
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@ -7,16 +7,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/ana_cmpr.h"
|
|
||||||
#include "driver/ana_cmpr_etm.h"
|
#include "driver/ana_cmpr_etm.h"
|
||||||
#include "driver/gpio_etm.h"
|
#include "driver/gpio_etm.h"
|
||||||
#include "esp_etm.h"
|
#include "esp_etm.h"
|
||||||
#include "esp_log.h"
|
|
||||||
#include "ana_cmpr_example_main.h"
|
#include "ana_cmpr_example_main.h"
|
||||||
|
|
||||||
static const char *TAG = "ana_cmpr_example";
|
|
||||||
|
|
||||||
static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmpr)
|
static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmpr)
|
||||||
{
|
{
|
||||||
/* Allocate the analog comparator positive & negative cross events */
|
/* Allocate the analog comparator positive & negative cross events */
|
||||||
@ -36,13 +31,13 @@ static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmp
|
|||||||
task_cfg.actions[0] = GPIO_ETM_TASK_ACTION_SET;
|
task_cfg.actions[0] = GPIO_ETM_TASK_ACTION_SET;
|
||||||
task_cfg.actions[1] = GPIO_ETM_TASK_ACTION_CLR;
|
task_cfg.actions[1] = GPIO_ETM_TASK_ACTION_CLR;
|
||||||
ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_set_task, &gpio_clr_task));
|
ESP_ERROR_CHECK(gpio_new_etm_task(&task_cfg, &gpio_set_task, &gpio_clr_task));
|
||||||
/* Add task to the monitor GPIO */
|
/* Bind different tasks to the same GPIO */
|
||||||
ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_set_task, EXAMPLE_MONITOR_GPIO_NUM));
|
ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_set_task, EXAMPLE_MONITOR_GPIO_NUM));
|
||||||
ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_clr_task, EXAMPLE_MONITOR_GPIO_NUM));
|
ESP_ERROR_CHECK(gpio_etm_task_add_gpio(gpio_clr_task, EXAMPLE_MONITOR_GPIO_NUM));
|
||||||
|
|
||||||
/* Allocate the Event Task Matrix channels */
|
/* Allocate the Event Task Matrix channels */
|
||||||
esp_etm_channel_handle_t etm_pos_handle;
|
esp_etm_channel_handle_t etm_pos_handle = NULL;
|
||||||
esp_etm_channel_handle_t etm_neg_handle;
|
esp_etm_channel_handle_t etm_neg_handle = NULL;
|
||||||
esp_etm_channel_config_t etm_cfg = {};
|
esp_etm_channel_config_t etm_cfg = {};
|
||||||
ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_pos_handle));
|
ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_pos_handle));
|
||||||
ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_neg_handle));
|
ESP_ERROR_CHECK(esp_etm_new_channel(&etm_cfg, &etm_neg_handle));
|
||||||
@ -54,18 +49,13 @@ static void example_etm_bind_ana_cmpr_event_with_gpio_task(ana_cmpr_handle_t cmp
|
|||||||
ESP_ERROR_CHECK(esp_etm_channel_enable(etm_neg_handle));
|
ESP_ERROR_CHECK(esp_etm_channel_enable(etm_neg_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
ana_cmpr_handle_t example_init_analog_comparator_etm(void)
|
static void example_init_analog_comparator_etm(void)
|
||||||
{
|
{
|
||||||
/* Step 0: Show the source channel and reference channel GPIO */
|
|
||||||
int src_gpio = -1;
|
|
||||||
int ext_ref_gpio = -1;
|
|
||||||
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio));
|
|
||||||
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio));
|
|
||||||
ESP_LOGI(TAG, "Analog Comparator source gpio %d, external reference gpio %d", src_gpio, ext_ref_gpio);
|
|
||||||
|
|
||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
|
int src_gpio = -1;
|
||||||
|
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio));
|
||||||
|
|
||||||
#if CONFIG_EXAMPLE_INTERNAL_REF
|
#if CONFIG_EXAMPLE_REF_FROM_INTERNAL
|
||||||
/* Step 1: Allocate the new analog comparator unit */
|
/* Step 1: Allocate the new analog comparator unit */
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
.unit = EXAMPLE_ANA_CMPR_UNIT,
|
.unit = EXAMPLE_ANA_CMPR_UNIT,
|
||||||
@ -74,13 +64,14 @@ ana_cmpr_handle_t example_init_analog_comparator_etm(void)
|
|||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference");
|
|
||||||
|
|
||||||
/* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */
|
/* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */
|
||||||
ana_cmpr_internal_ref_config_t ref_cfg = {
|
ana_cmpr_internal_ref_config_t ref_cfg = {
|
||||||
|
/* Set the internal reference voltage to 50% VDD */
|
||||||
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
||||||
|
ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference voltage: %d%% * VDD, source from GPIO %d", (int)ref_cfg.ref_volt * 10, src_gpio);
|
||||||
#else
|
#else
|
||||||
/* Step 1: Allocate the new analog comparator unit */
|
/* Step 1: Allocate the new analog comparator unit */
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
@ -90,8 +81,10 @@ ana_cmpr_handle_t example_init_analog_comparator_etm(void)
|
|||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
ESP_LOGI(TAG, "Allocate Analog Comparator with external reference");
|
int ext_ref_gpio = -1;
|
||||||
#endif // CONFIG_EXAMPLE_INTERNAL_REF
|
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio));
|
||||||
|
ESP_LOGI(TAG, "Allocate Analog Comparator with external reference from GPIO %d, source from GPIO %d", ext_ref_gpio, src_gpio);
|
||||||
|
#endif // CONFIG_EXAMPLE_REF_FROM_INTERNAL
|
||||||
|
|
||||||
/* Step 2: (Optional) Set the debounce configuration
|
/* Step 2: (Optional) Set the debounce configuration
|
||||||
* It's an optional configuration, if the wait time is set in debounce configuration,
|
* It's an optional configuration, if the wait time is set in debounce configuration,
|
||||||
@ -109,23 +102,19 @@ ana_cmpr_handle_t example_init_analog_comparator_etm(void)
|
|||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
|
ESP_ERROR_CHECK(ana_cmpr_set_debounce(cmpr, &dbc_cfg));
|
||||||
|
|
||||||
/* Step 3: Enable the analog comparator unit */
|
/* Step 3: Connect the analog comparator events and gpio tasks via ETM channels */
|
||||||
ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));
|
example_etm_bind_ana_cmpr_event_with_gpio_task(cmpr);
|
||||||
|
ESP_LOGI(TAG, "Connected analog comparator events and GPIO tasks");
|
||||||
|
|
||||||
#if CONFIG_EXAMPLE_INTERNAL_REF
|
/* Step 4: Enable the analog comparator unit */
|
||||||
ESP_LOGI(TAG, "Analog comparator enabled, reference voltage: %d%% * VDD", (int)ref_cfg.ref_volt * 10);
|
ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));
|
||||||
#else
|
ESP_LOGI(TAG, "Analog comparator enabled");
|
||||||
ESP_LOGI(TAG, "Analog comparator enabled, external reference selected");
|
|
||||||
#endif
|
|
||||||
return cmpr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void example_analog_comparator_etm_app(void)
|
void example_analog_comparator_etm_app(void)
|
||||||
{
|
{
|
||||||
/* Initialize GPIO to monitor the comparator interrupt */
|
/* Initialize GPIO to monitor the comparator cross event */
|
||||||
example_init_monitor_gpio();
|
example_init_monitor_gpio();
|
||||||
/* Initialize Analog Comparator */
|
/* Initialize Analog Comparator */
|
||||||
ana_cmpr_handle_t cmpr = example_init_analog_comparator_etm();
|
example_init_analog_comparator_etm();
|
||||||
/* Connect the analog comparator events and gpio tasks via ETM channels */
|
|
||||||
example_etm_bind_ana_cmpr_event_with_gpio_task(cmpr);
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@ -7,13 +7,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/ana_cmpr.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "ana_cmpr_example_main.h"
|
#include "ana_cmpr_example_main.h"
|
||||||
|
|
||||||
static const char *TAG = "ana_cmpr_example";
|
|
||||||
|
|
||||||
static bool example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr,
|
static bool example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr,
|
||||||
const ana_cmpr_cross_event_data_t *edata,
|
const ana_cmpr_cross_event_data_t *edata,
|
||||||
void *user_ctx)
|
void *user_ctx)
|
||||||
@ -37,18 +32,13 @@ static bool example_ana_cmpr_on_cross_callback(ana_cmpr_handle_t cmpr,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void example_init_analog_comparator_intr(void)
|
static void example_init_analog_comparator_intr(void)
|
||||||
{
|
{
|
||||||
/* Step 0: Show the source channel and reference channel GPIO */
|
|
||||||
int src_gpio = -1;
|
|
||||||
int ext_ref_gpio = -1;
|
|
||||||
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio));
|
|
||||||
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio));
|
|
||||||
ESP_LOGI(TAG, "Analog Comparator source gpio %d, external reference gpio %d", src_gpio, ext_ref_gpio);
|
|
||||||
|
|
||||||
ana_cmpr_handle_t cmpr = NULL;
|
ana_cmpr_handle_t cmpr = NULL;
|
||||||
|
int src_gpio = -1;
|
||||||
|
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_SOURCE_CHAN, &src_gpio));
|
||||||
|
|
||||||
#if CONFIG_EXAMPLE_INTERNAL_REF
|
#if CONFIG_EXAMPLE_REF_FROM_INTERNAL
|
||||||
/* Step 1: Allocate the new analog comparator unit */
|
/* Step 1: Allocate the new analog comparator unit */
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
.unit = EXAMPLE_ANA_CMPR_UNIT,
|
.unit = EXAMPLE_ANA_CMPR_UNIT,
|
||||||
@ -57,7 +47,6 @@ void example_init_analog_comparator_intr(void)
|
|||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference");
|
|
||||||
|
|
||||||
/* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */
|
/* Step 1.1: As we are using the internal reference source, we need to configure the internal reference */
|
||||||
ana_cmpr_internal_ref_config_t ref_cfg = {
|
ana_cmpr_internal_ref_config_t ref_cfg = {
|
||||||
@ -65,10 +54,12 @@ void example_init_analog_comparator_intr(void)
|
|||||||
/* Set the initial internal reference voltage to 70% VDD, it will be updated in the callback every time the interrupt triggered */
|
/* Set the initial internal reference voltage to 70% VDD, it will be updated in the callback every time the interrupt triggered */
|
||||||
.ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD
|
.ref_volt = ANA_CMPR_REF_VOLT_70_PCT_VDD
|
||||||
#else
|
#else
|
||||||
|
/* Set the internal reference voltage to 50% VDD */
|
||||||
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
.ref_volt = ANA_CMPR_REF_VOLT_50_PCT_VDD,
|
||||||
#endif
|
#endif // CONFIG_EXAMPLE_HYSTERESIS_COMPARATOR
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
ESP_ERROR_CHECK(ana_cmpr_set_internal_reference(cmpr, &ref_cfg));
|
||||||
|
ESP_LOGI(TAG, "Allocate Analog Comparator with internal reference voltage: %d%% * VDD, source from GPIO %d", (int)ref_cfg.ref_volt * 10, src_gpio);
|
||||||
#else
|
#else
|
||||||
/* Step 1: Allocate the new analog comparator unit */
|
/* Step 1: Allocate the new analog comparator unit */
|
||||||
ana_cmpr_config_t config = {
|
ana_cmpr_config_t config = {
|
||||||
@ -78,8 +69,10 @@ void example_init_analog_comparator_intr(void)
|
|||||||
.cross_type = ANA_CMPR_CROSS_ANY,
|
.cross_type = ANA_CMPR_CROSS_ANY,
|
||||||
};
|
};
|
||||||
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
ESP_ERROR_CHECK(ana_cmpr_new_unit(&config, &cmpr));
|
||||||
ESP_LOGI(TAG, "Allocate Analog Comparator with external reference");
|
int ext_ref_gpio = -1;
|
||||||
#endif
|
ESP_ERROR_CHECK(ana_cmpr_get_gpio(EXAMPLE_ANA_CMPR_UNIT, ANA_CMPR_EXT_REF_CHAN, &ext_ref_gpio));
|
||||||
|
ESP_LOGI(TAG, "Allocate Analog Comparator with external reference from GPIO %d, source from GPIO %d", ext_ref_gpio, src_gpio);
|
||||||
|
#endif // CONFIG_EXAMPLE_REF_FROM_INTERNAL
|
||||||
|
|
||||||
/* Step 2: (Optional) Set the debounce configuration
|
/* Step 2: (Optional) Set the debounce configuration
|
||||||
* It's an optional configuration, if the wait time is set in debounce configuration,
|
* It's an optional configuration, if the wait time is set in debounce configuration,
|
||||||
@ -105,17 +98,12 @@ void example_init_analog_comparator_intr(void)
|
|||||||
|
|
||||||
/* Step 4: Enable the analog comparator unit */
|
/* Step 4: Enable the analog comparator unit */
|
||||||
ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));
|
ESP_ERROR_CHECK(ana_cmpr_enable(cmpr));
|
||||||
|
ESP_LOGI(TAG, "Analog comparator enabled");
|
||||||
#if CONFIG_EXAMPLE_INTERNAL_REF
|
|
||||||
ESP_LOGI(TAG, "Analog comparator enabled, reference voltage: %d%% * VDD", (int)ref_cfg.ref_volt * 10);
|
|
||||||
#else
|
|
||||||
ESP_LOGI(TAG, "Analog comparator enabled, external reference selected");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void example_analog_comparator_intr_app(void)
|
void example_analog_comparator_intr_app(void)
|
||||||
{
|
{
|
||||||
/* Initialize GPIO to monitor the comparator interrupt */
|
/* Initialize GPIO to monitor the comparator cross event */
|
||||||
example_init_monitor_gpio();
|
example_init_monitor_gpio();
|
||||||
/* Initialize Analog Comparator */
|
/* Initialize Analog Comparator */
|
||||||
example_init_analog_comparator_intr();
|
example_init_analog_comparator_intr();
|
||||||
|
@ -23,7 +23,7 @@ void example_init_monitor_gpio(void)
|
|||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
#if CONFIG_EXAMPLE_USE_ETM
|
#if CONFIG_EXAMPLE_MONITOR_IO_FROM_ETM
|
||||||
example_analog_comparator_etm_app();
|
example_analog_comparator_etm_app();
|
||||||
#else
|
#else
|
||||||
example_analog_comparator_intr_app();
|
example_analog_comparator_intr_app();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||||
*/
|
*/
|
||||||
@ -9,29 +9,29 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "soc/soc_caps.h"
|
#include "soc/soc_caps.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/ana_cmpr.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define EXAMPLE_ANA_CMPR_UNIT 0 // Analog Comparator unit
|
#define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the comparator cross event
|
||||||
#define EXAMPLE_WAIT_TIME_PROP (0.1) // The wait time proportion in one relative signal period
|
#define EXAMPLE_ANA_CMPR_UNIT (0) // Analog Comparator unit
|
||||||
|
#define EXAMPLE_WAIT_TIME_PROP (0.1) // The wait time proportion in one relative signal period
|
||||||
#define EXAMPLE_WAITE_TIME_US(freq_approx) (uint32_t)(1000000 * EXAMPLE_WAIT_TIME_PROP / (freq_approx))
|
#define EXAMPLE_WAITE_TIME_US(freq_approx) (uint32_t)(1000000 * EXAMPLE_WAIT_TIME_PROP / (freq_approx))
|
||||||
|
|
||||||
#if CONFIG_IDF_TARGET_ESP32P4
|
#define TAG "example"
|
||||||
#define EXAMPLE_MONITOR_GPIO_NUM (32) // The gpio to monitor the on cross callback
|
|
||||||
#else
|
|
||||||
#define EXAMPLE_MONITOR_GPIO_NUM (0) // The gpio to monitor the on cross callback
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void example_init_monitor_gpio(void);
|
void example_init_monitor_gpio(void);
|
||||||
|
|
||||||
#if CONFIG_EXAMPLE_USE_ETM
|
#if CONFIG_EXAMPLE_MONITOR_IO_FROM_ETM
|
||||||
/**
|
/**
|
||||||
* @brief Set or clear the monitor GPIO via Event Task Matrix when cross interrupt triggers.
|
* @brief Set or clear the monitor GPIO via Event Task Matrix when cross event fires.
|
||||||
* @note The interrupt of analog comparator is regarded as Event,
|
* @note The interrupt of analog comparator is regarded as Event,
|
||||||
* and the the operation of setting/clearing the GPIO is regarded as the corresponding task of the event.
|
* and the the operation of setting/clearing the GPIO is regarded as the corresponding task of the event.
|
||||||
* CPU won't be involved by using Event Task Matrix, so it can achieve relatively higher interrupt frequency
|
* CPU won't be involved by using Event Task Matrix, so it can achieve relatively higher interrupt frequency
|
||||||
*/
|
*/
|
||||||
void example_analog_comparator_etm_app(void);
|
void example_analog_comparator_etm_app(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,12 +17,8 @@ from pytest_embedded_idf.utils import idf_parametrize
|
|||||||
@idf_parametrize('target', ['esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target'])
|
@idf_parametrize('target', ['esp32h2', 'esp32p4', 'esp32c5', 'esp32c61'], indirect=['target'])
|
||||||
def test_ana_cmpr_example(dut: Dut) -> None:
|
def test_ana_cmpr_example(dut: Dut) -> None:
|
||||||
sdkconfig = dut.app.sdkconfig
|
sdkconfig = dut.app.sdkconfig
|
||||||
dut.expect(
|
if sdkconfig['EXAMPLE_REF_FROM_INTERNAL']:
|
||||||
r'ana_cmpr_example: Analog Comparator source gpio ([0-9]+), external reference gpio ([0-9]+)', timeout=10
|
dut.expect_exact('Allocate Analog Comparator with internal reference voltage')
|
||||||
)
|
elif sdkconfig['EXAMPLE_REF_FROM_EXTERNAL']:
|
||||||
if sdkconfig['EXAMPLE_INTERNAL_REF']:
|
dut.expect_exact('Allocate Analog Comparator with external reference from GPIO')
|
||||||
dut.expect('ana_cmpr_example: Allocate Analog Comparator with internal reference', timeout=10)
|
dut.expect_exact('Analog comparator enabled')
|
||||||
dut.expect(r'ana_cmpr_example: Analog comparator enabled, reference voltage: [0-9]+% \* VDD', timeout=10)
|
|
||||||
elif sdkconfig['EXAMPLE_EXTERNAL_REF']:
|
|
||||||
dut.expect('ana_cmpr_example: Allocate Analog Comparator with external reference', timeout=10)
|
|
||||||
dut.expect('ana_cmpr_example: Analog comparator enabled, external reference selected', timeout=10)
|
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
CONFIG_EXAMPLE_INTERNAL_REF=n
|
CONFIG_EXAMPLE_REF_FROM_INTERNAL=n
|
||||||
CONFIG_EXAMPLE_EXTERNAL_REF=y
|
CONFIG_EXAMPLE_REF_FROM_EXTERNAL=y
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
CONFIG_EXAMPLE_INTERNAL_REF=y
|
CONFIG_EXAMPLE_REF_FROM_INTERNAL=y
|
||||||
CONFIG_EXAMPLE_EXTERNAL_REF=n
|
CONFIG_EXAMPLE_REF_FROM_EXTERNAL=n
|
||||||
|
Reference in New Issue
Block a user