Go Down

Topic: Compare match interrupt and Serial.print(); (Read 932 times) previous topic - next topic


Apr 19, 2013, 05:17 pm Last Edit: Apr 19, 2013, 05:36 pm by Hillridge Reason: 1
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:

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

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: [Select]
void setup()
void loop()
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

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?


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.
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp


Apr 19, 2013, 05:55 pm Last Edit: Apr 19, 2013, 06:25 pm by Hillridge Reason: 1
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.


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.


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.
The art of getting good answers lies in asking good questions.

Go Up