@@ -47,6 +47,22 @@ namespace espp {
4747// / the each other, while ensuring that the interupts are still
4848// / processed in an orderly fashion.
4949// /
50+ // / If CONFIG_GPIO_CTRL_FUNC_IN_IRAM is enabled, then the ISR handler
51+ // / will be placed in IRAM. In this condition, the interrupt class' ISR
52+ // / handler will automatically disable the interrupt associated with
53+ // / that GPIO within the ISR handler.
54+ // /
55+ // / If CONFIG_GPIO_CTRL_FUNC_IN_IRAM is enabled and the PinConfig has
56+ // / auto_reenable set to false, then the interrupt will not be
57+ // / reenabled automatically. This is because the ISR handler will
58+ // / disable the interrupt, and it will not be reenabled until the user
59+ // / reenables it. This use-case is recommended for ACTIVE_LOW or
60+ // / ACTIVE_HIGH interrupts which may need some other action to clear
61+ // / the interrupt condition and prevent the ISR from being triggered
62+ // / continuously. In this case, simply re-enable the interrupt when you
63+ // / have cleared the interrupt condition if you want to be able to
64+ // / respond to it again.
65+ // /
5066// / \section interrupt_ex0 Interrupt Example
5167// / \snippet interrupt_example.cpp interrupt example
5268class Interrupt : public BaseComponent {
@@ -104,6 +120,13 @@ class Interrupt : public BaseComponent {
104120 struct PinConfig {
105121 int gpio_num; // /< GPIO number to for this interrupt
106122 event_callback_fn callback; // /< Callback for the interrupt event
123+ bool auto_reenable = true ; // /< Whether to auto reenable the
124+ // / interrupt after it is triggered.
125+ // / If false, the interrupt will
126+ // / need to be < reenabled in the
127+ // / callback or some other codepath.
128+ // / If true, the interrupt will < be
129+ // / reenabled automatically.
107130 ActiveLevel active_level; // /< Active level of the GPIO
108131 Type interrupt_type = Type::ANY_EDGE; // /< Interrupt type to use for the GPIO
109132 bool pullup_enabled = false ; // /< Whether to enable the pullup resistor
@@ -160,12 +183,7 @@ class Interrupt : public BaseComponent {
160183 // / \brief Destructor
161184 ~Interrupt () {
162185 // remove the isr handlers
163- {
164- std::lock_guard<std::recursive_mutex> lock (interrupt_mutex_);
165- for (const auto &args : handler_args_) {
166- gpio_isr_handler_remove (static_cast <gpio_num_t >(args->gpio_num ));
167- }
168- }
186+ remove_all ();
169187 if (queue_) {
170188 // send to the event queue to wake up the task
171189 EventData event_data = {-1 };
@@ -175,18 +193,6 @@ class Interrupt : public BaseComponent {
175193 // delete the queue
176194 vQueueDelete (queue_);
177195 }
178- #if CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER || CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM > 0
179- for (const auto &handle : glitch_filter_handles_) {
180- // disable the glitch filters
181- gpio_glitch_filter_disable (handle);
182- // and delete the handle
183- gpio_del_glitch_filter (handle);
184- }
185- #endif
186- // now delete the handler args
187- for (const auto &args : handler_args_) {
188- delete args;
189- }
190196 }
191197
192198 // / \brief Get the minimum number of free spaces in the queue
@@ -210,6 +216,126 @@ class Interrupt : public BaseComponent {
210216 configure_interrupt (interrupt);
211217 }
212218
219+ // / \brief Remove all the interrupts from the interrupt handler
220+ // / \details This will remove all the interrupts that are currently registered
221+ // / with the interrupt handler. This will also disable all the
222+ // / interrupts that are currently enabled.
223+ void remove_all () {
224+ std::lock_guard<std::recursive_mutex> lock (interrupt_mutex_);
225+ for (const auto &interrupt : interrupts_) {
226+ disable_interrupt (interrupt);
227+ }
228+ // clear the interrupts vector
229+ interrupts_.clear ();
230+ // delete the handler args objects
231+ for (const auto &args : handler_args_) {
232+ delete args;
233+ }
234+ // clear the handler args vector
235+ handler_args_.clear ();
236+ // disable anly glitch filters if they are enabled
237+ #if CONFIG_SOC_GPIO_SUPPORT_PIN_GLITCH_FILTER || CONFIG_SOC_GPIO_FLEX_GLITCH_FILTER_NUM > 0
238+ for (const auto &handle : glitch_filter_handles_) {
239+ // disable the glitch filters
240+ gpio_glitch_filter_disable (handle);
241+ // and delete the handle
242+ gpio_del_glitch_filter (handle);
243+ }
244+ #endif
245+ // clear the glitch filter handles vector
246+ glitch_filter_handles_.clear ();
247+ }
248+
249+ // / \brief Remove an interrupt from the interrupt handler
250+ // / \param interrupt The interrupt to remove
251+ // / \details This will find a registered interrupt with the given GPIO number
252+ // / and remove it from the list of interrupts. It will also disable
253+ // / the interrupt for that GPIO number. If no interrupt is found with
254+ // / the given GPIO number, then nothing is done.
255+ void remove_interrupt (const PinConfig &interrupt) { remove_interrupt (interrupt.gpio_num ); }
256+
257+ // / \brief Remove an interrupt from the interrupt handler
258+ // / \param gpio_num The GPIO number of the interrupt to remove
259+ // / \details This will find a registered interrupt with the given GPIO number
260+ // / and remove it from the list of interrupts. It will also disable
261+ // / the interrupt for that GPIO number. If no interrupt is found with
262+ // / the given GPIO number, then nothing is done.
263+ void remove_interrupt (int gpio_num) {
264+ logger_.info (" Removing interrupt for GPIO {}" , gpio_num);
265+ // disable the interrupt
266+ gpio_intr_disable (static_cast <gpio_num_t >(gpio_num));
267+ // remove the interrupt from the list
268+ std::lock_guard<std::recursive_mutex> lock (interrupt_mutex_);
269+ auto predicate = [gpio_num](const PinConfig &interrupt) {
270+ return interrupt.gpio_num == gpio_num;
271+ };
272+ auto interrupt = std::find_if (interrupts_.begin (), interrupts_.end (), predicate);
273+ if (interrupt == interrupts_.end ()) {
274+ logger_.error (" No interrupt found for GPIO {}" , gpio_num);
275+ return ;
276+ }
277+ // erase the interrupt
278+ interrupts_.erase (interrupt);
279+ // remove the isr handler
280+ gpio_isr_handler_remove (static_cast <gpio_num_t >(gpio_num));
281+ // erase the handler args object that corresponds to the gpio_num
282+ auto handler_arg =
283+ std::find_if (handler_args_.begin (), handler_args_.end (),
284+ [gpio_num](const HandlerArgs *args) { return args->gpio_num == gpio_num; });
285+ if (handler_arg != handler_args_.end ()) {
286+ delete *handler_arg;
287+ handler_args_.erase (handler_arg);
288+ } else {
289+ logger_.error (" No handler args found for GPIO {}" , gpio_num);
290+ }
291+ }
292+
293+ // / \brief Disable all the interrupts
294+ // / \details This will disable all the interrupts that are currently
295+ // / registered with the interrupt handler. This will not remove the
296+ // / interrupts from the list of interrupts, so they can be reenabled
297+ // / later.
298+ void disable_all () {
299+ std::lock_guard<std::recursive_mutex> lock (interrupt_mutex_);
300+ for (const auto &interrupt : interrupts_) {
301+ disable_interrupt (interrupt);
302+ }
303+ }
304+
305+ // / \brief Disable the interrupt for the interrupt PinConfig
306+ // / \param interrupt The interrupt to disable
307+ // / \details This will disable the interrupt for the GPIO that is specified,
308+ // / regardless of whether the interrupt is in the list of interrupts
309+ // / or not.
310+ void disable_interrupt (const PinConfig &interrupt) { disable_interrupt (interrupt.gpio_num ); }
311+
312+ // / \brief Disable the interrupt for the GPIO
313+ // / \param gpio_num The GPIO number of the interrupt to disable
314+ // / \details This will disable the interrupt for the GPIO that is specified,
315+ // / regardless of whether the interrupt is in the list of interrupts
316+ // / or not.
317+ void disable_interrupt (int gpio_num) {
318+ logger_.debug (" Disabling interrupt for GPIO {}" , gpio_num);
319+ gpio_intr_disable (static_cast <gpio_num_t >(gpio_num));
320+ }
321+
322+ // / \brief Enable the interrupt for the GPIO
323+ // / \param interrupt The interrupt to enable
324+ // / \details This will enable the interrupt for the GPIO that is specified,
325+ // / regardless of whether the interrupt is in the list of interrupts
326+ // / or not.
327+ void enable_interrupt (const PinConfig &interrupt) { enable_interrupt (interrupt.gpio_num ); }
328+
329+ // / \brief Enable the interrupt for the GPIO
330+ // / \param gpio_num The GPIO number of the interrupt to enable
331+ // / \details This will enable the interrupt for the GPIO that is specified,
332+ // / regardless of whether the interrupt is in the list of interrupts
333+ // / or not.
334+ void enable_interrupt (int gpio_num) {
335+ logger_.debug (" Enabling interrupt for GPIO {}" , gpio_num);
336+ gpio_intr_enable (static_cast <gpio_num_t >(gpio_num));
337+ }
338+
213339 // / \brief Get the state of the interrupt
214340 // / \param interrupt The interrupt to check
215341 // / \return Whether the interrupt is active
@@ -263,9 +389,17 @@ class Interrupt : public BaseComponent {
263389 };
264390
265391 static void isr_handler (void *arg) {
392+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
266393 auto *args = static_cast <HandlerArgs *>(arg);
394+ #if CONFIG_GPIO_CTRL_FUNC_IN_IRAM
395+ // disable the interrupt for the pin
396+ gpio_intr_disable (static_cast <gpio_num_t >(args->gpio_num ));
397+ #endif
267398 EventData event_data = {args->gpio_num };
268- xQueueSendFromISR (args->event_queue , &event_data, nullptr );
399+ xQueueSendFromISR (args->event_queue , &event_data, &xHigherPriorityTaskWoken);
400+ if (xHigherPriorityTaskWoken) {
401+ portYIELD_FROM_ISR ();
402+ }
269403 }
270404
271405 bool is_active_level (int gpio_num, ActiveLevel active_level) const {
@@ -296,6 +430,12 @@ class Interrupt : public BaseComponent {
296430 logger_.error (" No interrupt found for GPIO {}" , event_data.gpio_num );
297431 return false ;
298432 }
433+ #if CONFIG_GPIO_CTRL_FUNC_IN_IRAM
434+ if (interrupt->auto_reenable ) {
435+ logger_.debug (" Auto-reenabling interrupt for GPIO {}" , event_data.gpio_num );
436+ gpio_intr_enable (static_cast <gpio_num_t >(event_data.gpio_num ));
437+ }
438+ #endif
299439 if (!interrupt->callback ) {
300440 logger_.error (" No callback registered for GPIO {}" , event_data.gpio_num );
301441 return false ;
@@ -372,17 +512,17 @@ class Interrupt : public BaseComponent {
372512 io_conf.pull_up_en = interrupt.pullup_enabled ? GPIO_PULLUP_ENABLE : GPIO_PULLUP_DISABLE;
373513 io_conf.pull_down_en =
374514 interrupt.pulldown_enabled ? GPIO_PULLDOWN_ENABLE : GPIO_PULLDOWN_DISABLE;
375- gpio_config (&io_conf);
376515 {
377516 std::lock_guard<std::recursive_mutex> lock (interrupt_mutex_);
378517 // add the isr handler
379518 HandlerArgs *handler_arg = new HandlerArgs{interrupt.gpio_num , queue_};
380519 handler_args_.push_back (handler_arg);
381- gpio_isr_handler_add ( static_cast <gpio_num_t >(interrupt.gpio_num ), isr_handler,
382- static_cast <void *>(handler_arg));
520+ gpio_num_t gpio_num = static_cast <gpio_num_t >(interrupt.gpio_num );
521+ gpio_isr_handler_add (gpio_num, isr_handler, static_cast <void *>(handler_arg));
383522 // configure the filter if needed
384523 configure_filter (interrupt);
385524 }
525+ gpio_config (&io_conf);
386526 }
387527
388528 static bool ISR_SERVICE_INSTALLED;
@@ -392,7 +532,8 @@ class Interrupt : public BaseComponent {
392532 std::recursive_mutex interrupt_mutex_;
393533 std::vector<PinConfig> interrupts_;
394534 std::vector<HandlerArgs *> handler_args_;
395- std::vector<gpio_glitch_filter_handle_t > glitch_filter_handles_;
535+ std::vector<gpio_glitch_filter_handle_t > glitch_filter_handles_; // TODO: remove these when the
536+ // interrupts are removed
396537 std::unique_ptr<Task> task_;
397538};
398539} // namespace espp
0 commit comments