attachInterrupt D7

In the spark_wiring_interrupts.cpp attachInterrupt() function, there is a confusing ifdef block:

#if Wiring_Cellular == 1
/* safety check that prevents users from attaching an interrupt to D7
* which is shared with BATT_INT_PC13 for power management */
if (pin == D7) return false;
  1. From what I see, BATT_INT_PC13 is hooked up to PC13, how does this conflict with D7 (PA13?)
  2. What does this have to do with Wiring_Cellular?


Not every STM32 pin has its own interrupt handler. Presumably PA13 and PC13 share the same one, so there would be no way to tell if the battery interrupt or your interrupt triggered it.

It’s only enabled for the Electron (Wiring_Cellular) because at the time, it was the only device that has a battery charge controller that generated that interrupt. It’s connected to the BQ24195, I think.


There is a brief write-up about the EXTI (external interrupt) lines here

originally posted this, but the one above is a bit clearer IMO Interrupts: #, priority, architecture


I see.

Thanks for the quick and descriptive response

Hello there. I tried to follow this thread and most of the linked resources but got not conclusive answer on how to make D7 work for an interrupt in an Electron. I’ve tested the code in Photon and works perfect but does not work in an Electron. I thought it was the hardware so changed the electron, changed the input_pullup/pulldown/input configurations and all is the same. I know there are shared EXTI lines which make only 1 pin usable for external interrupts at the same time ( but it does not mention D7. I understand from above that D& is shared with BATT_INT_PC13. However, is there any way to make D7 in an electron work for external interrupts?

Thanks in advance for the help

It is not possible to attachInterrupt on D7 on an Electron or E series because the interrupt is shared and there would be no way to tell if it was your interrupt or the battery interrupt that caused the interrupt. It’s disabled in this bit of code, but even if you took that out, you’d still run into the problem of figuring out the actual interrupt source.

Keep in mind that when you unplug the battery, the battery interrupt fires hundreds of times per second.

Thanks for the clarification. It’s now clear. Particle should update the documentation and state this clearly.

Done! There’s a fancy new interrupts section that hopefully will make the whole EXTI situation clearer, especially on the P1 and Electron.


Hi Rick,

We released a product back in 2017 that relied on interrupts on pin D7, they used to work fine back then, we are doing an OS upgrade and find out that we can no longer use them.

Is there a way to get them working again whitout having to fork a different implementation of the OS?

Just for the sake of clarity, can you confirm which platform you are using (P1, Electron 2G/3G, Electron LTE, other)?
What does “we can no longer use them” mean exactly?
We don’t know your code, so there are multiple reasons why it’s not working anymore.
Is it really attachInterrupt() or maybe detachInterrupt() inside an ISR?
Could it be that the same issue might exist for any pin and not only D7?
Have you got a simple test code that exhibits that issue for testing?

1 Like

My company sold a number of weather stations based on Electron 2G/3G on 2017, they are based on 0.6.4 and have hardwired the D7 Input to a wind speed sensor (hence the need for an interrupt to calculate the speed based on the time between pulses). They all work well and the D7 interrupt works without issues.
I am testing a firmware upgrade that redirects the data to another server, and we would like to take advantage of many improvements since that OS version, specially the Device Vitals features.

During testing I discovered that interrupts were disabled for D7 via this line in the definition of attachinterrupt() in spark_wiring_interrupts.cpp#L92, #L76

if (pin == D7) return false;

I commented out this line and compiled locally and the interrupts worked again, I checked and this was modified in the source even for 0.6.4. So I’m afraid if we upgrade the OS the D7 pin will no longer acquire the wind speed correctly because it will not allow attaching the interrupt.

Correct me if I’m wrong, but unless we use a custom OS that allows the interrupt on D7, we can’t do any OS upgrade to our devices. And would that mean losing OTA upgrades?

It seems to me disabling all interrupts on D7 just because it’s shared with the BATT_INT_PC13 interrupt was a bad call. This would never be a problem for our product because the device’s battery is not removable while the wind speed sensor is connected.

If you want I can share the code, but I think this explanation is enough, thanks for your interest!

1 Like

So am I stuck being unable to upgrade the OS for my product? Anyone?

I guess this is something to tag @no1089 or @marekparticle for.

You may also open a support ticket at as this is a breaking change for your application/hardware.

Since you were using a 0.x.y version the transition to 1.x.y “allows” for breaking changes. Within a major version there shouldn’t be any.

However, I think it’s a questionable move to prevent the use of D7 as interrupt source “unconditionally”.
I’d rather go with a compiler warning but leave the responsibility to check for it with the developer to make an informed decision.

Furthermore, although I’m not entirely sure what that BATT_INT interrupt is used for, I’d assume when no battery is attached and/or charging is disabled then D7 should be free to be used as interrupt source anyhow.
In other cases, maybe a function could be added to the PMIC object to conciously yield the use of the BATT_INTerrupt and attachInterrupt() checks for that when being instructed to attach an alternative ISR to D7.

1 Like

Even if the battery is not attached and/or charging is disabled, DeviceOS needs to manage the PMIC and it can only correctly be done if we can get interrupt notifications from the PMIC. This can be disabled (, however the application will need to manually manage the PMIC.

Depending on DeviceOS version (pre 1.5.0), as a workaround you can manually call HAL to force attach an interrupt to D7 (since 1.5.0 this check has been moved into HAL), again, provided that the application manually manages the PMIC:

HAL_Interrupts_Attach(D7, handleFunction, nullptr /*data */, RISING, nullptr);
1 Like