Confused about interrupts

02 Jul 2009 . Edited: 16 Jul 2009

Hi,

I've been trying to get a simple timer interrupt working without any success.  It's very possible that I've coded it incorrectly as I have just been blindly following an example.  However, it is quite simple.

All I do is set up Timer0 to fire an interrupt every X cycles.  I'm using the serial port to print the value of the T0TC register and you can see it incrementing up until the first interrupt fires.  Thereafter, the ISR runs indefinately and the program never returns to the main loop.

I've either set up my ISR incorrectly and somehow the result is that it never exits properly, or something else funny is happening.  I've disabled the only other interrupt that was enabled and you can see, that as the ISR is called the first time, the relevant bit in the VICRawIntr register is set (VICRawIntr[4]).  Every time after that it is not set.  So what is calling my ISR?

Thanks, Shareef.

 

#include "mbed.h"

Serial pc(USBTX, USBRX);
DigitalOut myLed(LED1);

void tmr0_isr (void) __irq {

	pc.printf("\nInside Timer0 ISR.\n");
	pc.printf("VICRawIntr register is %x\n", VICRawIntr);
	pc.printf("VICIntEnable reg is 0x%x\n", VICIntEnable);
	pc.printf("T0TC is %x\n", T0TC);
	pc.printf("Reseting Timer0\n");
	T0TCR = 2;
	pc.printf("T0TC is %x\n", T0TC);
	
	T0IR = 1;   // Clear MR0 interrupt flag

	myLed = ~myLed;
	
	pc.printf("T0TC is %x\n", T0TC);
	pc.printf("Enabling Timer0\n");
	T0TCR = 1;
	pc.printf("T0TC is %x\n", T0TC);
}


int main() {
        
    // Read the clock configuration
    pc.printf("Reg CLKSRCSEL is 0x%x\n", CLKSRCSEL);
    pc.printf("Reg PLLCON is 0x%x\n", PLLCON);
    pc.printf("Reg PLLCFG is 0x%x\n", PLLCFG);
    pc.printf("Reg PLLSTAT is 0x%x\n", PLLSTAT);
    pc.printf("Reg CCLKCFG is 0x%x\n", CCLKCFG);
    pc.printf("Reg USBCLKCFG is 0x%x\n", USBCLKCFG);
    pc.printf("Reg PCLKSEL0 is 0x%x\n", PCLKSEL0);
    pc.printf("Reg PCLKSEL1 is 0x%x\n", PCLKSEL1);
    pc.printf("Reg PCON is 0x%x\n", PCON);
    pc.printf("Reg INTWAKE is 0x%x\n", INTWAKE);
    pc.printf("Reg PCONP is 0x%x\n", PCONP);
    
    // Set up a timer0
    T0PR = 0x3;          // Timer0 prescale value 
    T0MR0 = 0x00FFFFFF;  // Set Match Register
    T0MCR = 7;           // Interrupt, stop and reset on match
    T0TCR = 2;           // Reset prescale and counter registers.
    
    // Enable interrupts
    VICVectAddr4 = (unsigned long)tmr0_isr;
    VICVectCntl4 = 0;
    VICIntEnable = 1 << 4;
    VICIntEnClr = 1 << 2;
    
    pc.printf("VICRawIntr reg is 0x%x\n", VICRawIntr);
 	pc.printf("VICIntEnable reg is 0x%x\n", VICIntEnable);
 	pc.printf("VICIRQStatus reg is 0x%x\n", VICIRQStatus);
 	pc.printf("VICFIQStatus reg is 0x%x\n", VICFIQStatus);
 	pc.printf("VICVectAddr4 reg is 0x%x\n", VICVectAddr4);

	pc.printf("T0IR is %x\n", T0IR);
	pc.printf("T0TCR is %x\n", T0TCR);
	pc.printf("T0TC is %x\n", T0TC);
	pc.printf("T0MR0 is %x\n", T0MR0);

    // Enable Timer0
    T0TCR = 1;
		
 	while(1) {
 		pc.printf("main.c: T0TC is %x\n", T0TC);
 	}   
}

 

02 Jul 2009

Hi Shareef,

Timer0 is already in use by the library to provide the Timer, Timeout and Ticker functions - so you could try using al alternative timer for your experiments.

Looking are what you are trying to achieve, could this be done with the Ticker functionality provided by the mbed library?

Also, I'm not sure that printf in an interrupt isnt best practice because of how long it takes to execute.

Cheers,
Chris

03 Jul 2009

OK, I can try a different timer, I was just trying to debug a piece of a larger bit of code and understand the correct way to define ISR's.  I really just wanted to understand why the ISR I have here seems to fire continuously after the first time.  Something is broken somewhere.

The printf was just there while I debugged it.

Cheers.

03 Jul 2009

So I've changed to Timer1 and still get the same behaviour.  The ISR is called continuously even though the relevant bit for Timer1 in the raw interrupt register is not set.

I can't find anything in the LPC2368 user guide that says I need to clear a VIC interrupt.

Even when I remove all the printf's I still get the same behaviour.  The LED should pulse but it is lit continuously.  Something is causing my ISR to fire and as far as I can see, it's not me.

Stuck.

07 Jul 2009

Shareef, I can't tell from the code what timer frequency you're expecting, but unless it's really slow, like once every few seconds, I don't think you'll be able to have all those printfs in your ISR.  They're very slow and if they don't all complete before the next tick occurs you're in trouble.  In general your ISR code needs to be as fast as possible.  Try just incrementing a counter in the ISR, and blinking an LED every 1000 or whatever ticks.

 

--steve

07 Jul 2009

Hi, and thanks for the reply.

I do understand about the printf's and the fact that the ISR should be as short as possible.  Honestly, I do.

The CPU clock is 60MHz, according to Chris in another post, and I'm using the default clock divider for Timer1 of 4.  So we have a 15MHz peripheral clock.  My prescale register is set to 3 so I have a divide by 4 on the counter which means it has an effective frequency of 3.75MHz.  My match register is set to 0xFFFFFF which should give a timer1 period of 4.4 seconds.

I can actually count approximately 4.5 seconds before I hit my first interrupt after pushing reset.  I can see the flag set in the RawInt register and all is dandy.  However, my ISR now fires continually and the timer1 interrupt flag is not set.

Something is causing my ISR to fire and it ain't me.  This is somehow broken.

Is the way I'm writing my ISR correct?  Do I need any assembler, which I've seen in other examples, for pushing and popping the stack on entry/exit from my ISR?

Does someone else want to take my code snippet and run it to make sure I'm not making a fool of myself.  :-)  If I can't get a timer working then there's no hope for me.

Cheers.

08 Jul 2009 . Edited: 08 Jul 2009

Hi Shareef,

Try removing the _irq and replacing ~led with !led....

Cheers,

Chris

10 Jul 2009

Genius!

I have a working timer interrupt.  Thanks a lot.  Do you have a description of why I shouldn't be using __irq in my code?

Thanks.

10 Jul 2009
Shareef Jalloq wrote:

> Genius!

Well... i'm more modest than that...

> Thanks a lot.  Do you have a description of why I shouldn't be using __irq in my code?

Hmm... "because Phil the software guy suggested it" is the only *honest* answer i can give... which I have no claim on the "genuis" bit above...


Glad it's working though

Cheers, Chris

16 Jul 2009

 

Chris Styles wrote:

Hmm... "because Phil the software guy suggested it" is the only *honest* answer i can give... which I have no claim on the "genuis" bit above...


Glad it's working though

Cheers, Chris

I suggested in the old forum that it would be handy to be able to see the assembler generated by the compiler.  The above is an example of why.  A quick look at the code the compiler generates with and without __irq would provide the answer.  It's even more important if people are going to be developing outside the MBED class libraries like Shareef is.

--steve

 

16 Jul 2009 . Edited: 16 Jul 2009

Hi,

I have a working timer interrupt.  Thanks a lot.  Do you have a description of why I shouldn't be using __irq in my code?

To avoid the propogation of witchcraft/folklore around removing __irq, here is the explanation.

The current mbed libraries do a bit of work in the IRQ before/after calling the function pointed to in the VIC vector:

  • Bumps you on to the main stack after IRQ interrupt entry (ARM7 has a number of stack pointers for different exceptions, but I wanted to just have a unified stack, much like the Cortex-M3)
  • Calls the function in the VIC Vector
  • When it returns, it restores the stack/cpsr, acknowledges the interrupt, and returns from the exception
What this means is the functions in the VIC Vector can be just *normal* functions (void funcname()), rather than marked with __irq (which changes the way the function is compiled with respect to stack manipulation and return).
Whilst the objective is good (unified stack, standard interrupt functions), i'm not sure I quite like the implementation at the moment, as it is not so compatible with just shoving in raw interrupt code as you have been doing. I'll consider revising the implementation strategy, and also writing up a good explanation of what is going on and how to implement your own handlers.
For reference, here is how you would implement the resultant functionality with the mbed libraries:
// repeated timer interrupt example
#include "mbed.h"

Serial pc(USBTX, USBRX);
DigitalOut myLed(LED1);
Ticker tmr;
 
void tmr_isr(void) {
	myLed = !myLed;
}

int main() {
	tmr.attach(&tmr_isr, 0.1); 
 	while(1) {
 		pc.printf("main loop\n");
 	}   
}
Hope this helps,

Simon