Pages: [1]   Go Down
Author Topic: Compare match interrupt and Serial.print();  (Read 455 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I want to have an interrupt that runs roughly 75 times a second to, among other things, handle some housekeeping and check for button presses.

As far as I can tell I have it set up correctly, but it always crashes at the same point:
Quote
RTI Fired @ 13
RTI Fired @ 26
RTI Fired @ 39
RTI Fired @ 53
RTI Fired @ 66
RTI Fired @ 79
RTI Fired @ 93
RTI Fired @ 106
RTI Fired @ 119
RTI Fired @ 133
RTI Fired @ 146
R

You can see it's firing roughly every 13ms as expected, then at around 159ms in it dies.  I know it has to do with the Serial.print() routine conflicting with the interrupt, probably by being midprint when it fires again.  If I up the baud rate to something like 57600 it runs fine.  I understand why it dies where it does (outputting 15 characters @ 9600 baud takes ~13ms the same as the ISR fire rate).

I'd like to better understand what's going on and how to protect against it.  This ISR will be running in a complex program and I need to ensure it won't cause other issues like this.  

Here's the test code:
Code:
void setup()
{
  Serial.begin(9600);
  setupRTI();
}
void loop()
{
//nothing
}
void setupRTI()
{
  //Use timer 5, output A  (pin 44)
  // initialize timer5
  noInterrupts();           // disable all interrupts
  TCCR5A = 0;
  TCCR5B = 0;
  TCNT5  = 0;

  OCR5A = 833;            // compare match register 16MHz/256/75Hz ~75.03Hz
  TCCR5B |= (1 << WGM12);   // CTC mode
  TCCR5B |= (1 << CS12);    // 256 prescaler
  TIMSK5 |= (1 << OCIE5A);  // enable timer compare interrupt mask
  interrupts();             // enable all interrupts
}

ISR(TIMER5_COMPA_vect)          // timer compare ISR
{
  Serial.print("RTI Fired @ ");   //print RTI fire time
  Serial.println(millis());
}

I don't think I can use cli(); and sei(); since the serial routine would just enable interrupts anyway right?
Do I need to mask OCIE5A while critical things are running?

« Last Edit: April 19, 2013, 10:36:00 am by Hillridge » Logged

Massachusetts, USA
Offline Offline
Tesla Member
***
Karma: 208
Posts: 8860
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're sending about 18 characters, 75 times per second.

18 * 75 = 1350 characters per second * 10 = 13,500 bits per second.

You are sending at 9,600 bits per second.

When the buffer fills the Serial routines wait for an interrupt to move a character out of the buffer... and interrupts are disabled so it will wait forever.  It is generally not a good idea to use Serial.print() in an ISR.

Set your baudrate well above 13,500 and the code will last longer.

Perhaps the first 11 samples will be enough.
Logged

Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

Offline Offline
Newbie
*
Karma: 1
Posts: 19
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You were probably writing that while I edited my post, but I understand why the crash is happening.  What I was asking is how to protect against it, assuming for some reason I HAVE to do a Serial.print() (or something else) inside an ISR that will take longer than the period of the interrupt.

Thanks

Edit: I suppose better practice would be to set a flag in the ISR, then check it in the main loop and do serial.prints from there.
« Last Edit: April 19, 2013, 11:25:53 am by Hillridge » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 617
Posts: 49463
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
assuming for some reason I HAVE to do a Serial.print() (or something else) inside an ISR that will take longer than the period of the interrupt.
See, that's the problem. We're not willing to assume that HAVE to do something you KNOW you shouldn't (and, realistically, can't) do.
Logged

Pages: [1]   Go Up
Jump to: