Skip to main content
replaced http://arduino.stackexchange.com/ with https://arduino.stackexchange.com/
Source Link

As noted in the last part of Nick Gammon's answerNick Gammon's answer to the question How does the Arduino handle serial buffer overflow?How does the Arduino handle serial buffer overflow?, if the serial output buffer fills up, serial output blocks, waiting for an interrupt telling it it's ok to send the next byte out the serial port. When interrupts are turned off, that interrupt is never processed, so the program deadlocks. Don't do Serial prints in an ISR.

As noted in the last part of Nick Gammon's answer to the question How does the Arduino handle serial buffer overflow?, if the serial output buffer fills up, serial output blocks, waiting for an interrupt telling it it's ok to send the next byte out the serial port. When interrupts are turned off, that interrupt is never processed, so the program deadlocks. Don't do Serial prints in an ISR.

As noted in the last part of Nick Gammon's answer to the question How does the Arduino handle serial buffer overflow?, if the serial output buffer fills up, serial output blocks, waiting for an interrupt telling it it's ok to send the next byte out the serial port. When interrupts are turned off, that interrupt is never processed, so the program deadlocks. Don't do Serial prints in an ISR.

pointed out a few issues with races and concurrency
Source Link

Looking at your code, it looks like a typical message has about 20 characters. Sending at 38400 bps, or 384 characters per second, it seems to me the buffer shouldn't fill, even if it's small (16 bytes) instead of large (64 bytes). However, I don't know of another explanation for the behavior you describe. Sending at 38400 bps, or 384 characters per second, it seems to me the buffer shouldn't fill, even if it's small (16 bytes) instead of large (64 bytes). However, I don't know of another explanation for the behavior you describe.

Summary: In your ISR, just store the current time and other relevant data in volatile variables, set a flag in a volatile variable, and in your main loop print stuff and clear the flag (or clear the flag and print stuff) whenever you see that the flag has been set.


Edit 1: I've struck out some erroneous numbers above. Here is a correction: 100 sends per second at 20 characters each is 2000 characters per second. 38400 bps of asynchronous data at 10 bits per transmitted byte is 3840 characters per second. So the raw data rate should be fast enough that the buffer ordinarily doesn't overfill.


In the summary above, I suggested that the ISR store the current time and other relevant data in volatile variables and set a flag in a volatile variable. That is, read millis() and store it, perhaps as follows:

// at file level ...
volatile unsigned long isrMillis;
volatile byte isrFlag;

// in ISR ...
  isrMillis = millis();
  isrFlag = true;

// in main loop ...
  unsigned long mlMillis;
  ...
  // when flag is true...
  cli();
  mlMillis = isrMillis;
  isrFlag = false;
  sei();
  // Now do stuff with mlMillis
  ...

However, looking at your ISR, perhaps it should go like the following instead:

// at file level ...
volatile float xf, yf, xfc, yfc;
volatile unsigned long t1, t2, tdelt;
volatile byte isrflag;

// in ISR ...
void myHandler(){
  tdelt = t2-t1;
  xfc = xf;
  yfc = yf;   
  isrFlag = true;    
}

// in main loop ...
  // when flag is true...
  isrFlag = false;
  // Now do stuff with tdelt, xfc, and yfc
  ...

Note that if an interrupt occurs while xf and yf are in the middle of being computed via your Kalman filter or whatever, the statements xfc = xf; and yfc = yf; may pick up partially-stored results. You can avoid that problem at least in part by protecting stores of t1, t2, xf, yf in the main loop:

  cli();
  xf = someXResult;
  yf = someYResult;  
  t1 = someT1Result;
  t2 = someT2Result;  
  sei(); 

In the above I've pointed out a few issues with races and concurrency and suggested technical solutions. Those suggestions may be quite wide of the mark rather than appropriate. In general I don't have a precise understanding of what you are trying to do with the software and don't know what redesign should be done to make it coherent.

Looking at your code, it looks like a typical message has about 20 characters. Sending at 38400 bps, or 384 characters per second, it seems to me the buffer shouldn't fill, even if it's small (16 bytes) instead of large (64 bytes). However, I don't know of another explanation for the behavior you describe.

Summary: In your ISR, just store the current time and other relevant data in volatile variables, set a flag in a volatile variable, and in your main loop print stuff and clear the flag (or clear the flag and print stuff) whenever you see that the flag has been set.

Looking at your code, it looks like a typical message has about 20 characters. Sending at 38400 bps, or 384 characters per second, it seems to me the buffer shouldn't fill, even if it's small (16 bytes) instead of large (64 bytes). However, I don't know of another explanation for the behavior you describe.

Summary: In your ISR, just store the current time and other relevant data in volatile variables, set a flag in a volatile variable, and in your main loop print stuff and clear the flag (or clear the flag and print stuff) whenever you see that the flag has been set.


Edit 1: I've struck out some erroneous numbers above. Here is a correction: 100 sends per second at 20 characters each is 2000 characters per second. 38400 bps of asynchronous data at 10 bits per transmitted byte is 3840 characters per second. So the raw data rate should be fast enough that the buffer ordinarily doesn't overfill.


In the summary above, I suggested that the ISR store the current time and other relevant data in volatile variables and set a flag in a volatile variable. That is, read millis() and store it, perhaps as follows:

// at file level ...
volatile unsigned long isrMillis;
volatile byte isrFlag;

// in ISR ...
  isrMillis = millis();
  isrFlag = true;

// in main loop ...
  unsigned long mlMillis;
  ...
  // when flag is true...
  cli();
  mlMillis = isrMillis;
  isrFlag = false;
  sei();
  // Now do stuff with mlMillis
  ...

However, looking at your ISR, perhaps it should go like the following instead:

// at file level ...
volatile float xf, yf, xfc, yfc;
volatile unsigned long t1, t2, tdelt;
volatile byte isrflag;

// in ISR ...
void myHandler(){
  tdelt = t2-t1;
  xfc = xf;
  yfc = yf;   
  isrFlag = true;    
}

// in main loop ...
  // when flag is true...
  isrFlag = false;
  // Now do stuff with tdelt, xfc, and yfc
  ...

Note that if an interrupt occurs while xf and yf are in the middle of being computed via your Kalman filter or whatever, the statements xfc = xf; and yfc = yf; may pick up partially-stored results. You can avoid that problem at least in part by protecting stores of t1, t2, xf, yf in the main loop:

  cli();
  xf = someXResult;
  yf = someYResult;  
  t1 = someT1Result;
  t2 = someT2Result;  
  sei(); 

In the above I've pointed out a few issues with races and concurrency and suggested technical solutions. Those suggestions may be quite wide of the mark rather than appropriate. In general I don't have a precise understanding of what you are trying to do with the software and don't know what redesign should be done to make it coherent.

Source Link

As noted in the last part of Nick Gammon's answer to the question How does the Arduino handle serial buffer overflow?, if the serial output buffer fills up, serial output blocks, waiting for an interrupt telling it it's ok to send the next byte out the serial port. When interrupts are turned off, that interrupt is never processed, so the program deadlocks. Don't do Serial prints in an ISR.

Looking at your code, it looks like a typical message has about 20 characters. Sending at 38400 bps, or 384 characters per second, it seems to me the buffer shouldn't fill, even if it's small (16 bytes) instead of large (64 bytes). However, I don't know of another explanation for the behavior you describe.

Summary: In your ISR, just store the current time and other relevant data in volatile variables, set a flag in a volatile variable, and in your main loop print stuff and clear the flag (or clear the flag and print stuff) whenever you see that the flag has been set.