chipKIT® Development Platform

Inspired by Arduino™

Interrupt problem

Created Tue, 20 Dec 2011 19:13:29 +0000 by Gagarin


Gagarin

Tue, 20 Dec 2011 19:13:29 +0000

Hello I try to measure how long time processor stay in interrupt. After interrupt ends, millis() don't start again. Here is the code:

int cas; void setup() { Serial.begin (9600); attachInterrupt(0,time,FALLING); cas=millis(); Serial.print(cas); }

void time() { Serial.print( "cas " ); Serial.println(cas); } void loop()

Here is sample from serial monitor:

4096 4102 4108 4114 4121 4127 4133 41cas 4139 cas 4139 cas 4139 cas 4139 cas 4139 cas 4139 39 4143 4143 4143 4143 4143 4143 4143

Thank's for any comment's.


Jacob Christ

Wed, 21 Dec 2011 05:57:15 +0000

I'm not sure you would measure anything other than the time it takes to transmit 4 to 8 bytes at 9600bps with this code.

What's very strange is that you cas value does not count up... Which version of MPIDE are you using?

Jacob mpide-0022-windows-20110822


Gagarin

Wed, 21 Dec 2011 07:25:29 +0000

Thank's Jakob. I am using mpide-0022-windows-20110822, the same as you. Posted code is only the part of code which i want to use. I cut it because of length of message posted and interrupt was running well. Problem happened when interrupt ends and program returned to void loop (). Did you try to run that code on your machine ?


Jacob Christ

Wed, 21 Dec 2011 07:31:20 +0000

Yes, but I didn't try to generate an interrupt. And it just counted up with time.


majenko

Fri, 23 Dec 2011 10:14:51 +0000

I have noticed that millis() is somewhat unstable at times. I haven't yet tracked down the cause of it, but delay(), which relies on millis() has often locked up for me on the UNO32â„¢.

One point about your program - you should always declare any global variables used in interrupt routines as volatile:

volatile int cas;

This turns off some compiler optimizations for that variable which can cause issues with interrupt routines (namely caching of the variable in a register, and then the interrupt routine using the non-cached version and getting the wrong data).

Not a problem per-se in your program, as you are only reading and the data looks right, but still good practice.


majenko

Fri, 23 Dec 2011 10:57:25 +0000

Ok, I think the problem here is that you are using the serial from within an interrupt.

My theory:

The serial runs at interrupt priority level 2 (IPL2).

The change-notifications run at IPL4.

The core timer (what handles the millis() counter etc) runs at IPL2.

So, the change notification (4) runs the serial (2) which then conflicts with the timer (2).

Thus, the timer sometimes doesn't get to return cleanly from its interrupt status and never gets called again.

Nasty.

But:

I have tried shifting the core timer to a different priority level, but it either has no effect, or kills the timer completely.

I have tried shifting the HardwareSerial to another IPL, to no avail.

I don't have any direct experience with programming of interrupts in this specific compiler, so I am not sure if I am doing it right.

However:

Remove the Serial.println calls from the interrupt and it all works smoothly. I would suggest setting some volatile variables inside the interrupt and then reporting them in the main loop - that way the Serial.println is only ever in the main loop.


KurtE

Fri, 23 Dec 2011 14:19:19 +0000

I am also new to this processor, but learning...

I believe you are using a hardware serial port to do your output during the interrupt. My quick look at HardwareSerial.cpp shows that this version is not doing any buffering of output, in particular it looks like:

void HardwareSerial::write(uint8_t theChar)
{

	while ((uart->uxSta.reg & (1 << _UARTSTA_TMRT)) == 0)	//check the TRMT bit
		{
		//* wait for the transmitter to be clear
		}


	uart->uxTx.reg = theChar;
}

So when you get the interrupt, you are hung in your interrupt during the entire time that it takes to output your characters at the your baud rate. So no lower priority interrupts can be serviced while in this interrupt. This probably includes not being able to service the timer interrupt.

I have not tried this, but I believe I read that you can re-enable interrupts inside your interrupt handler, doing something like:

asm("ei");

My guess is that if you do this, you will first need to clear the appropriate interrupt status flag for your interrupt and potentially disable your interrupt as to not be reentered... But again I am just guessing.

Good Luck Kurt