I’m trying to create a program that triggers an external interrupt from a level change on a pin and then sets a compare value for a basic timer to disable that external interrupt for the next 800ms. I’m using a Sodaq ExpLoRer.
I can successfully set the device to wake up on a level change of EXTINT0 and activate an EIC_Handler() routine. I also have the timer successfully waking up on a TC4_Handler() interrupt routine when it reaches its compare value stored in the CC0 register.
Heres what Ive done:
When the EXTINT0 is triggered, it disables the WAKEUP on EXTINT0 to ensure it can’t wakeup from another pin level change. Then, I attempt to read the current COUNT value of the timer and add 200 clock cycles to it (which is 800ms @ 250Hz) and set the CC0 to this new value. Finally I re-enable the Compare match on the TC4 counter.
800ms later when the compare match is triggered on the timer, I disable Timer Compare interrupts (MC0) and re-enable the EXTINT0 interrupts.
Here is the issue:
The first few times it doesn’t work. The CC0 interrupt occurs immediately after the EXTINT0 interrupt. After about 5 or 6 external interrupt triggers in quick succession, it starts to kick in and work properly, disabling the EXTINT0 for 800ms like its supposed to. If I stop triggering the pin consistently then the problem comes back, triggering the timer MC0 interrupt immediately after the EXTINT0 interrupt again. I cant figure out why this is only working after being triggered a few times. The offending code is below. Please let me know if you need to see the setup code.
/*-----------------------
MAIN - LOOP FOREVER
-------------------------*/
void loop()
{
//This runs after an External Interrupt
if (sensorTriggered)
doSensorTriggered();
//This runs after the 800ms timer compare
if(timerTriggered)
doTimerTriggered();
//System Sleep
__WFI();
}
/*-------------------------
SUB ROUTINES/FUNCTIONS
---------------------------*/
//This runs after an External Interrupt
void doSensorTriggered()
{
//Get current count and Print to terminal
uint8_t currentCount = TC4->COUNT8.COUNT.reg;
debug("Before: "); debugl(currentCount); flush;
//Set CC0 to currentCount and add 800ms (wrap around at 255 cycles)
TC4->COUNT8.CC[0].reg = currentCount + sensorDelay;
while(TC4->COUNT8.STATUS.bit.SYNCBUSY & TC_STATUS_SYNCBUSY);
//Re-enable Counter TC4
TC4->COUNT8.INTENSET.reg |= TC_INTENSET_MC0;
sensorTriggered = 0;
}
//This runs after the 800ms timer compare
void doTimerTriggered()
{
//Get current count and Print to terminal
uint8_t currentCount = TC4->COUNT8.COUNT.reg;
debug("After: "); debugl(currentCount); flush;
//Re-enable EXTINT0
EIC->WAKEUP.reg |= EIC_WAKEUP_WAKEUPEN0;
timerTriggered = 0;
}
/**-------------------------------------
INTERRUPT ROUTINES - Keep them short!
---------------------------------------- */
//External Interrupts
void EIC_Handler()
{
//If EXTINT0 is Triggered
if (EIC->INTFLAG.bit.EXTINT0 && EIC->INTENSET.bit.EXTINT0){
EIC->WAKEUP.reg &= ~EIC_WAKEUP_WAKEUPEN0; //Disable EXTINT0 Wakeup
sensorTriggered = 1;
EIC->INTFLAG.reg |= EIC_INTFLAG_EXTINT0; //clear the EXTINT0 flag
}
}
//Counter Interrupts
void TC4_Handler ()
{
//If Timer Compare CC0 is a Match
if (TC4->COUNT8.INTFLAG.bit.MC0 && TC4->COUNT8.INTENSET.bit.MC0) {
TC4->COUNT8.INTENCLR.reg |= TC_INTFLAG_MC0; // Disable Compare on CC0
timerTriggered = 1;
TC4->COUNT8.INTFLAG.reg |= TC_INTFLAG_MC0; // Clear the MC0 int flag
}
}
The terminal output of the program can be seen in the picture below:
You can see from this picture that the first few times it doesn’t work at all:
Before: 17 - After: 17.
Before: 21 - After: 22.
Before: 12 - After: 13.
But after about 7 External Interrupts it starts to function correctly. Here you can see:
Before: 236 - After: 182.
Before: 182 - After: 22.
Before: 22 - After: 223
Each of these are giving a 201 clock cycle delay (wrapping around to 0 at 255)
This continues as long as I continue to trigger the EXTINT0 Pin. However, when I stop triggering the ExtInt and continue again later (even 10 seconds later) the same pattern occurs. What could possibly be making this happen so intermittently?
Thanks heaps guys.
Ps. If instead I decide to restart on the EXTINT0 and stop the counter on the MC0 then it works perfectly. Or if I use ONESHOT mode it works perfectly too. The problem only occurs when changing the CC0 value in the middle of its operation.