From 577bf5acc9a2a9e5554bc37dc368ccd264efb113 Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Fri, 24 Jul 2026 12:25:40 +0200 Subject: [PATCH 1/2] stm32: Detach GPIO IRQ callbacks upon clearing "setevent" When the interrupts get disabled, the callback(s) are still attached. That structure is never cleared, causing several calls to attach/detach to eventually fail as the callback queue gets full. When the error occurs, the registration fails with error 12 (ENOMEM). By detaching the IRQ and clearing the callbacks, this error doesn't happen again Signed-off-by: Javier Alonso --- arch/arm/src/common/stm32/stm32_exti_gpio_m0_v1.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/src/common/stm32/stm32_exti_gpio_m0_v1.c b/arch/arm/src/common/stm32/stm32_exti_gpio_m0_v1.c index 00b9158085c57..b143d31dc9e5e 100644 --- a/arch/arm/src/common/stm32/stm32_exti_gpio_m0_v1.c +++ b/arch/arm/src/common/stm32/stm32_exti_gpio_m0_v1.c @@ -221,6 +221,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -274,6 +275,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } } From b54cca3bf9aeb8e0adaefef5b93cd038c663747b Mon Sep 17 00:00:00 2001 From: Javier Alonso Date: Fri, 24 Jul 2026 14:10:53 +0200 Subject: [PATCH 2/2] Review: Address @raiden00pl comments The fix was ported from the STM32G0 to all the STM32 platforms, as the code is mostly the same hence presents the same failure Signed-off-by: Javier Alonso --- arch/arm/src/common/stm32/stm32_exti_gpio_m3m4_v1v2.c | 11 +++++++++++ arch/arm/src/stm32f7/stm32_exti_gpio.c | 11 +++++++++++ arch/arm/src/stm32h7/stm32_exti_gpio.c | 11 +++++++++++ arch/arm/src/stm32l4/stm32l4_exti_gpio.c | 11 +++++++++++ arch/arm/src/stm32l5/stm32l5_exti_gpio.c | 11 +++++++++++ arch/arm/src/stm32u5/stm32_exti_gpio.c | 11 +++++++++++ arch/arm/src/stm32wb/stm32wb_exti_gpio.c | 11 +++++++++++ arch/arm/src/stm32wl5/stm32wl5_exti_gpio.c | 11 +++++++++++ 8 files changed, 88 insertions(+) diff --git a/arch/arm/src/common/stm32/stm32_exti_gpio_m3m4_v1v2.c b/arch/arm/src/common/stm32/stm32_exti_gpio_m3m4_v1v2.c index db62fac13f669..f278016ce5144 100644 --- a/arch/arm/src/common/stm32/stm32_exti_gpio_m3m4_v1v2.c +++ b/arch/arm/src/common/stm32/stm32_exti_gpio_m3m4_v1v2.c @@ -259,6 +259,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -333,6 +334,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } } diff --git a/arch/arm/src/stm32f7/stm32_exti_gpio.c b/arch/arm/src/stm32f7/stm32_exti_gpio.c index 4081d9cba2404..057b905abd269 100644 --- a/arch/arm/src/stm32f7/stm32_exti_gpio.c +++ b/arch/arm/src/stm32f7/stm32_exti_gpio.c @@ -266,6 +266,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -340,6 +341,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } } diff --git a/arch/arm/src/stm32h7/stm32_exti_gpio.c b/arch/arm/src/stm32h7/stm32_exti_gpio.c index 74c8e812fc432..07af8666db3dd 100644 --- a/arch/arm/src/stm32h7/stm32_exti_gpio.c +++ b/arch/arm/src/stm32h7/stm32_exti_gpio.c @@ -268,6 +268,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -342,6 +343,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } } diff --git a/arch/arm/src/stm32l4/stm32l4_exti_gpio.c b/arch/arm/src/stm32l4/stm32l4_exti_gpio.c index 1418d7c75d644..8a5ef06e0d2ca 100644 --- a/arch/arm/src/stm32l4/stm32l4_exti_gpio.c +++ b/arch/arm/src/stm32l4/stm32l4_exti_gpio.c @@ -262,6 +262,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -336,6 +337,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } } diff --git a/arch/arm/src/stm32l5/stm32l5_exti_gpio.c b/arch/arm/src/stm32l5/stm32l5_exti_gpio.c index 10e1099e0ec88..0077576be74bb 100644 --- a/arch/arm/src/stm32l5/stm32l5_exti_gpio.c +++ b/arch/arm/src/stm32l5/stm32l5_exti_gpio.c @@ -126,6 +126,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, uint32_t pin = pinset & GPIO_PIN_MASK; uint32_t exti = 1 << pin; int irq = STM32_IRQ_EXTI0 + pin; + int ret; g_gpio_handlers[pin].callback = func; g_gpio_handlers[pin].arg = arg; @@ -139,6 +140,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, } else { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } diff --git a/arch/arm/src/stm32u5/stm32_exti_gpio.c b/arch/arm/src/stm32u5/stm32_exti_gpio.c index 03865acd4c278..d9bc149f5528c 100644 --- a/arch/arm/src/stm32u5/stm32_exti_gpio.c +++ b/arch/arm/src/stm32u5/stm32_exti_gpio.c @@ -126,6 +126,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, uint32_t pin = pinset & GPIO_PIN_MASK; uint32_t exti = 1 << pin; int irq = STM32_IRQ_EXTI0 + pin; + int ret; g_gpio_handlers[pin].callback = func; g_gpio_handlers[pin].arg = arg; @@ -139,6 +140,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, } else { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } diff --git a/arch/arm/src/stm32wb/stm32wb_exti_gpio.c b/arch/arm/src/stm32wb/stm32wb_exti_gpio.c index 6e6597b60ca33..138bb52404c80 100644 --- a/arch/arm/src/stm32wb/stm32wb_exti_gpio.c +++ b/arch/arm/src/stm32wb/stm32wb_exti_gpio.c @@ -260,6 +260,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -334,6 +335,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } } diff --git a/arch/arm/src/stm32wl5/stm32wl5_exti_gpio.c b/arch/arm/src/stm32wl5/stm32wl5_exti_gpio.c index eec0c58a667c0..92b9bd9b24127 100644 --- a/arch/arm/src/stm32wl5/stm32wl5_exti_gpio.c +++ b/arch/arm/src/stm32wl5/stm32wl5_exti_gpio.c @@ -262,6 +262,7 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, xcpt_t handler; int nshared; int i; + int ret; /* Select the interrupt handler for this EXTI pin */ @@ -336,6 +337,16 @@ int stm32_gpiosetevent(uint32_t pinset, bool risingedge, bool fallingedge, if (i == nshared) { + /* remove any leftover callback */ + + ret = irq_detach(irq); + if (ret < 0) + { + return ret; + } + + /* disable the interrupt */ + up_disable_irq(irq); } }