Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
11 years, 9 months ago.
Dissable IRQ on DigialIn pin stopping sleep mode
I need to disable a DigialIn pin IRQ permanently so it does not restart when calling any other ISR for example a Ticker ISR or a wake up from deep sleep. This is for the KL25z chip.
This is a snip of my code
disable IRQ
InterruptIn dcfSignalIn(PTD7); void dcfIRQ(void) { if (sync==0){ __disable_irq(); // I want to remove the interrupt properties of this digital in pin Ticker50ms.attach(& dcfISR, .05); // this restarts the IRQ again. } } int main() { dcfSignalIn.rise(dcfIRQ); While(1){} }
After I have detected the rising edge I need to discard this ISR completely and use the same digital in pin to continue counting pulses. The rest of my program runs as it should, however using disable_irq(); switches it off but if I engage a Ticker or sleep function after, it starts again also stopping the cpu going to sleep later in my code even if I use disable_irq() again before going to sleep mode.
Synchronising the Ticker is not a problem as I have conditional code to avoid calling the Ticker50ms() when I do not need to. I hit the problem when trying to put the MCU to sleep.
Could I un-define the ISR InteruptIn pin then re-define it as Digital In pin or is there a simpler way?
Many thanks
1 Answer
11 years, 9 months ago.
Using _disable_irq(); is slightly overkill, it disables all interrupts on the entire microcontroller, so not useful if you want other interrupts to function.
Luckily there is a simple method, attach a NULL pointer: dcfSignalIn.rise(NULL);. That doesn't just prevent the function from being called, it actually disables the interrupt.
And just to be complete, you can also disable the interrupt generation of a port: NVIC_DisableIRQ(PORTD_IRQn);. However attaching a NULL pointer is what you should need here.
Blimey Erik, what took you so long :) I'll try it shortly and update here. Many thanks.
posted by 27 Dec 2013I added enable_irq() and disable_irq() methods on InterruptIn class, which does quickly what it says. Might use those Paul. The NULL pointer trick as Eric suggested, does it also, but it is more time consuming.
Regards, 0xc0170
posted by 27 Dec 2013Is that a relative new function? Never noticed it before. I see it does the same as what I put as third method, indeed faster, but still often a little bit on the overkill side of things ;). Most important, I think that it can use slightly more documentation that it has now. Mainly to mention its behavior is dependent on which uC is used, and that it can disable all InterruptIns.
@Paul, hey you never responded on my last mail :P (I did see your current consumption numbers in another topic though).
posted by 27 Dec 2013Erik, dcfSignalIn.rise(NULL); has done the trick, sleep/wake functions back to normal now. (mail on its way:)
Martin, disable _irq() has some issues I think, possibly only with the KL25z?, definite issue with low power timer interrupts in sleep modes. I have not worked with IRQ on any other MCU. I would have thought calling a Ticker ISR should not restart any other disabled IRQ's? unless it is intended purely as a global disable/enable function to quickly shut down/restart many IRQ's in one go.
Thanks again guys
posted by 27 Dec 2013You can start a new thread on this issue, but I believe it does not have any, have you checked the implementation? It's straightforward, just enable/disables interrupt which was registered using InterruptIn object, can't disable anything else. If your pin is on the PORT A, during the initialization of an object for that pin, it enables interrupts from PORTA (entire port, a limitation of Kinetis L). By invoking disable_irq method, it disables the same vector which was enabled.
void InterruptIn::enable_irq() { gpio_irq_enable(&gpio_irq); } void InterruptIn::disable_irq() { gpio_irq_disable(&gpio_irq); }
KL25Z HAL implementation:
void gpio_irq_enable(gpio_irq_t *obj) { if (obj->port == PortA) { NVIC_EnableIRQ(PORTA_IRQn); } else if (obj->port == PortD) { NVIC_EnableIRQ(PORTD_IRQn); } } void gpio_irq_disable(gpio_irq_t *obj) { if (obj->port == PortA) { NVIC_DisableIRQ(PORTA_IRQn); } else if (obj->port == PortD) { NVIC_DisableIRQ(PORTD_IRQn); } }
@Erik Yes, it's been there since November. Overkill? Methods above are intended for quickly disabling/enabling interrupts for the object which registered that interrupt. You can compare the NULL pointer for raise/fall, what the implementation does (as I recall, even global disable/enable interrupts, not to mention stepping over array of attached functions) ! What would be your suggestions to enable/disable an interrupt for InterruptIn class? If I commit to mbed src again, I will add brief description.
Regards, 0xc0170
posted by 28 Dec 2013Maybe Paul was confused with the global irq enable/disable functions.
Regarding these specific ones, imo the problem is that their behavior is highly dependent on the platform: On the LPC1768 they disable all InterruptIns, on the KL25 half of them, on the LPC11u24 only one (I assume). And in general I am all for higher performance, but does enabling/disabling interrupts require such speed? And even if it does, doesn't it kinda decrease the advantage of a relative target independent library if the behavior depends so much on your target?
Normally to disable one I just use attach NULL, technically it doesn't disable the interrupt vector, but if all its sources are disabled the interrupt will never be called.
posted by 28 Dec 2013Yes you are correct Erik, but not so much confused more along the lines not having the code knowledge that I can narrow down and pinpoint an individual IRQ to control it. I know exactly what I want to do but lack the knowledge as to how to write the code. The code example that you and Martin have shown above has expanded this IRQ control function to be more specific to the IRQ I am trying to control. So yes for the beginner/intermediate programmer like myself more documentation with examples is a good way to go. However the question is how much documentation and to what depth and how much spare time you guys have. If you take a look at the 'hello world' examples on mbed, these are geared up very much for entry level knowledge and some of the questions I see do come from beginners. So if I were to document an example on mbed I would bare that in mind and for instance give an example of how to initialise the IRQ, use it and then how to disable it and re-enable it again if required. With regards to speed or ultimately how many clock cycles to perform a task can be very important for certain processes, but I think this is more for high performance applications that would be leaning towards multi-cored CPU's with vastly more resources and at this level the target audience would be expert who would know the code examples above. Lastly it has to be recognised that you guys are not getting paid for this time and I as well as many others really appreciate your efforts :)
posted by 28 Dec 2013