Interrupt APIs
The Interrupt class provides APIs to register interrupt handlers for GPIO and configure the interrupts. Interrupts can be configured to trigger on rising edge, falling edge, high level, low level, or any change in the input signal. A single interrupt object can manage multiple GPIO pins with separate callbacks for each GPIO, or separte Interrupt objects can be created (though that uses more memory and CPU as each Interrupt will has its own queue, ISR handler, and task.
Finally, the Interrupt class is also designed to be subclassed if desired to provide additional functionality, or it can of course be included as a member within another class. The Button class provides a very simple implementation of a subclass of Interrupt.
API Reference
Header File
Classes
-
class Interrupt : public espp::BaseComponent
A class to handle a GPIO interrupt.
This class uses the ESP-IDF GPIO interrupt handler to detect GPIO interrupts. It then calls the callback function with the event. It can handle multiple GPIO interrupts and call the appropriate callback for each GPIO interrupt.
The class uses a FreeRTOS queue to handle the events. The queue is created in the constructor and deleted in the destructor. The queue is used to wake up the task when an interrupt event occurs. The task then calls the appropriate callback for the interrupt. Since all the GPIO interrupts are handled by the same task, all the callbacks are called from the same task. This means that the callbacks should be fast and not block for long periods of time, otherwise the other interrupts will be delayed.
Regardless of the callback speed, some interrupts could still be missed if they happen too quickly. For this reason, the queue size can be set in the configuration (default is 10). If the queue is full, then the interrupt event will be missed. If you are expecting a lot of interrupts to happen quickly, then you should increase the queue size.
Another way to handle the situation where you have many interrupts and would like to separate out the processing by priority is to have different Interrupt objects for the different priority levels, and assign the interrupt pins/callbacks to the objects according to the priority levels that you want. This will ensure that interrupts at different priority levels / in different objects do not starve the each other, while ensuring that the interupts are still processed in an orderly fashion.
Interrupt Example
static auto start = std::chrono::high_resolution_clock::now(); auto callback = [&](const espp::Interrupt::Event &event) { auto now = std::chrono::high_resolution_clock::now(); auto elapsed = std::chrono::duration<float>(now - start).count(); logger.info("[Callback][{:.3f}] Interrupt: pin {} changed to active state: {}", elapsed, event.gpio_num, event.active); }; espp::Interrupt::PinConfig io0 = { .gpio_num = GPIO_NUM_0, .callback = callback, .active_level = espp::Interrupt::ActiveLevel::LOW, .interrupt_type = espp::Interrupt::Type::ANY_EDGE, .pullup_enabled = true, .pulldown_enabled = false, // flexible filter requiring configuration (default is provided as 5us // threshold in 10us window), but other configurations can be manually // set as below .filter_type = espp::Interrupt::FilterType::FLEX_GLITCH_FILTER, .filter_config = {.window_width_ns = 10000, .window_threshold_ns = 5000}, }; espp::Interrupt::PinConfig io12 = { .gpio_num = GPIO_NUM_12, .callback = callback, .active_level = espp::Interrupt::ActiveLevel::LOW, .interrupt_type = espp::Interrupt::Type::ANY_EDGE, .pullup_enabled = true, .pulldown_enabled = false, // pre-configured 2 clock pulse width filter .filter_type = espp::Interrupt::FilterType::PIN_GLITCH_FILTER, }; // make an interrupt for a single gpio { espp::Interrupt interrupt({ .isr_core_id = 1, .interrupts = {io0}, .task_config = { .name = "Interrupt task", .stack_size_bytes = 6192, .priority = 5, }, .log_level = espp::Logger::Verbosity::DEBUG, }); std::this_thread::sleep_for(5s); } // make multiple interrupts for multiple gpios { espp::Interrupt interrupt0({ .interrupts = {io0}, .task_config = { .name = "Interrupt task", .stack_size_bytes = 6192, .priority = 5, }, .log_level = espp::Logger::Verbosity::DEBUG, }); espp::Interrupt interrupt12({ .interrupts = {io12}, .task_config = { .name = "Interrupt 0 task", .stack_size_bytes = 6192, .priority = 5, }, .log_level = espp::Logger::Verbosity::DEBUG, }); std::this_thread::sleep_for(2s); // now lets read the instantaneous state of the interrupt pins auto is_0_active = interrupt0.is_active(io0); auto is_12_active = interrupt12.is_active(io12); logger.info("Instantaneous state of pin 0: {}", is_0_active); logger.info("Instantaneous state of pin 12: {}", is_12_active); std::this_thread::sleep_for(2s); } // make a single interrupt for multiple GPIOs // make an interrupt for a single gpio { // Register for interrupts on a few pins (GPIO_NUM_0, GPIO_NUM_12) espp::Interrupt interrupt({ .interrupts = {io0}, .task_config = { .name = "Interrupt task", .stack_size_bytes = 6192, .priority = 5, }, .log_level = espp::Logger::Verbosity::DEBUG, }); // use the add_interrupt method to add another interrupt interrupt.add_interrupt(io12); std::this_thread::sleep_for(2s); // now lets read the instantaneous state of the interrupt pins auto active_states = interrupt.get_active_states(); logger.info("Instantaneous state of pins: {}", active_states); std::this_thread::sleep_for(2s); // print out the minimum number of spaces in the interrupt queue over the // last 2 seconds auto min_queue_size = interrupt.get_min_queue_size(); logger.info("Minimum queue size over last 4 seconds: {}", min_queue_size); } #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) esp_intr_dump(stdout); #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
Subclassed by espp::Button
Public Types
-
enum class ActiveLevel
The active level of the GPIO.
Values:
-
enumerator LOW
Active low.
-
enumerator HIGH
Active high.
-
enumerator LOW
-
enum class Type
The type of interrupt to use for the GPIO.
Values:
Public Functions
-
inline explicit Interrupt(const Config &config)
Constructor.
- Parameters
config – The configuration for the interrupt
-
inline ~Interrupt()
Destructor.
-
inline size_t get_min_queue_size() const
Get the minimum number of free spaces in the queue.
This will return the minimum number of free spaces in the queue Over the lifetime of the object. This can be used to determine if the queue size is too small for the number of interrupts that are being received. It may also help indicate if the interrupt task priority is too low, preventing the queue from being serviced. Finally, it may also help to indicate if additional filtering may be needed on the interrupt line (either using the FilterType or with hardware filtering).
- Returns
The minimum number of free spaces in the queue
-
inline void add_interrupt(const PinConfig &interrupt)
Add an interrupt to the interrupt handler.
- Parameters
interrupt – The interrupt to add
-
inline bool is_active(const PinConfig &interrupt) const
Get the state of the interrupt.
This will check the raw logic level of the GPIO and return whether the interrupt is active or not according to the active level that was set in the configuration.
- Parameters
interrupt – The interrupt to check
- Returns
Whether the interrupt is active
-
inline std::vector<std::pair<int, bool>> get_active_states()
Get the state of all the interrupts.
- Returns
A vector of the states of the interrupts as pairs of the GPIO number and whether the interrupt is active
-
inline const std::string &get_name() const
Get the name of the component
Note
This is the tag of the logger
- Returns
A const reference to the name of the component
-
inline void set_log_tag(const std::string_view &tag)
Set the tag for the logger
- Parameters
tag – The tag to use for the logger
-
inline espp::Logger::Verbosity get_log_level() const
Get the log level for the logger
See also
See also
- Returns
The verbosity level of the logger
-
inline void set_log_level(espp::Logger::Verbosity level)
Set the log level for the logger
See also
See also
- Parameters
level – The verbosity level to use for the logger
-
inline void set_log_verbosity(espp::Logger::Verbosity level)
Set the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls set_log_level
- Parameters
level – The verbosity level to use for the logger
-
inline espp::Logger::Verbosity get_log_verbosity() const
Get the log verbosity for the logger
See also
See also
See also
Note
This is a convenience method that calls get_log_level
- Returns
The verbosity level of the logger
-
inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)
Set the rate limit for the logger
See also
Note
Only calls to the logger that have _rate_limit suffix will be rate limited
- Parameters
rate_limit – The rate limit to use for the logger
-
struct Config
The configuration for the interrupt.
Public Members
-
int isr_core_id = -1
The core to install the ISR service on. If -1, then the ISR service is installed on the core that this constructor is called on. If 0 or 1, then the ISR service is installed on the specified core. If the ISR service is already installed, then this function does nothing. If the core_id is invalid, then an error is logged and the ISR service is not installed.
-
size_t event_queue_size = 10
The size of the event queue.
-
Task::BaseConfig task_config
The configuration for the task.
-
int isr_core_id = -1
-
struct Event
The event for the interrupt.
-
struct FilterConfig
The configuration for the filter.
This is used to configure the GPIO flex glitch filter The filter is used to filter out glitches on the GPIO whose pulses are shorter than window_threshold_ns within the window_width_ns sampling window.
Note
This is only supported on some chips (-C and -S series chips) and is only enabled if CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM > 0.
Note
This filter config is only supported by the flex_glitch_filter. The pin_glitch_filter is not-configurable.
-
struct PinConfig
The configuration for an interrupt on a GPIO.
This is used to configure the GPIO interrupt
Public Members
-
int gpio_num
GPIO number to for this interrupt.
-
event_callback_fn callback
Callback for the interrupt event.
-
ActiveLevel active_level
Active level of the GPIO.
-
bool pullup_enabled = false
Whether to enable the pullup resistor.
-
bool pulldown_enabled = false
Whether to enable the pulldown resistor.
-
FilterType filter_type = FilterType::NONE
The type of filter to use. If set to FLEX_GLITCH_FILTER, the filter_config should be set.
-
FilterConfig filter_config = {}
The configuration for the filter. This is only used if filter_type is set to FLEX_GLITCH_FILTER
-
int gpio_num
-
enum class ActiveLevel