Can you please post your complete example project, so that we all can have a look at all of your settings? To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file.
Well this is a little embarrassing, in tidying up my example code so that I could post it I managed to obtain the desired behaviour. What I needed to do was use the _ClearInterrupt() then _ClearPending() commands in that order just before re-enabling the interrupt. I must have tried every other combination of enabling, disabling, clearing, stopping etc. at least twice but managed to miss this one.
I guess this makes sense, the interrupt type is set to LEVEL so the GPIO interrupt needs to be cleared before clearing the pending interrupt otherwise a new interrupt will just be pended straight away.
However, one thing I am still not entirely clear on is why do I need to clear a pending interrupt? If the interrupt has been disabled or stopped is it correct that an interrupt request is pended in the first place?
Anyway I have attached the example project, hopefully someone will find it useful. Thank you very much for your reply Bob.
Sorry, I meant to mention the above code was written for a CY8CKIT-042 PSoC 4 Pioneer Kit and uses a digital output pin with an external jumper wire to the input pin to generate the interrupts.
Before looking into your project:
If the interrupt has been disabled or stopped is it correct that an interrupt request is pended in the first place?
Yes: interrupts are handled by the ICU (Interrupt Controller Unit) which is part of the ARM M0 core. Interrupts have several states as handled, pending etc. Most concern is (of course) not to miss any interrupt, so a blocked (by software or by priority) interrupt becomes pending when the interrupt condition occurs.
In your project the flaw is to have a "Level" interrupt defined. Because you do not have any influence on the causing signal from inside you cannot remove the interrupt cause, so when the interrupt is handled and the program returns from the handler, the interrupt cause still exists and will at once fire immediately.
Using a "Falling edge" cause will (despite switch bouncing) occur only once, when the program flow enters the handler, the cause is already removed. No clear is needed.
The irq output of a pin "remembers" the interrupt and so it has to be cleared at the pin to enable it firing again or to remove the level.
This is similar to the "sticky bits" of an UART's status register which are used to generate interrupts for that component.
Now I'm going to look into your project....
Yes, as I thought: You still have enabled the interrupt signal of the pin which will be recognized as soon as the interrupt component is re-enabled.
Usually (in a "normal" project) the handling is done completely within the handler.
**** One dramatic bug ****
You have the opportunity (and sometimes you are forced to) setting the optimization level to something different from "Debug". Your
uint8 intFlag = 0 declaration might fail in constructs like
while(!intFlag) Wait(); // Wait for an interrupt
The optimization can (will) take out the invariant intFlag (it does not change within the loop) leaving the program with an infinite loop.
volatile uint8 intFlag = 0;
will inform the compiler that intFlag may be changed from the "outside" and so may not be optimized-out.
Hi Bob, again thank you for replying.
In your project the flaw is to have a "Level" interrupt defined.
I’ve chosen a level interrupt because the final target for my project is a 4000 series PSoC, which doesn’t support the rising edge setting on GPIO interrupts. I realise that this is ‘sticky’ and needs to be cleared, but it wasn’t obvious to me that a pending interrupt should be raised if the interrupt had been disabled.
Most concern is (of course) not to miss any interrupt, so a blocked (by software or by priority) interrupt becomes pending when the interrupt condition occurs.
This explains why the interrupt is still pended even when disabled, thank you. One consequence of this I have noticed that might catch some people out is that any interrupt source that occurs before the _StartEx() function is used for the very first time will be queued up and cause the ISR to run immediately afterwards. I suspect a lot of people would think the ISR would run only for interrupt sources that occur after _StartEx() function is called.
**** One dramatic bug ****...
Thank you for pointing that out, I had actually originally set the flag to volatile but it was one of the things I changed when trying out different combinations and forgot to set it back.