Teensy 3.6 & 3.5 - IntervalTimer sketch crashes after thousands of activations

Using IntervalTimer to try and read ADC and write DAC on a regular interval (1kHz in this test). Step 1 is to simply gather time tags in an array. micros() failed earlier and I read where micros() in an interrupt service routine does not work because it sets off its own interrupts. But the Teensy 3.6 and 3.5 both crash after a few tens of thousands of timer interrupt activations.

Now using ARM_DWT_CYCCNT instead because of the recommendations I read on PJRC fora. Still getting crashes just as with micros(). I put a blinker on pin 13 to determine if the Teensy is crashing or the Serial Monitor of the Arduino IDE is crashing. The blinker stops dead. Pressing hardware reset on the Teensy gets the blinker going again, and Serial Monitor resumes without a restart of the IDE. The Teensy then runs for tens of thousands cycles (up to maybe 200k cycles) and crashes again.

Test code is as follows:

Code:
/--------------------------------------------------------------------------
// Name: intervalTimerTest
//
// Purpose - This program instruments the performance of teensyduino object
// IntervalTimer during:
//
// 1. Simple activation and timestamping using micros();
// 2. Time Stamping, and analog reading
// 3. Time Stamping, analog reading (ADC), and analog writing (DAC).
//
// Instruments with timestamp, to allow investiation of read/write
// frequencies in offline analyses
//
// Authors:
//
// Michael Stanford, Senior Software Engineer, Del Rey Analytics, LLC
// Vincent Stanford, Chief Engineer, Del Rey Analytics, LLC
//
// Date: July 16, 2019
//
// Language: Arduino C++ Arduino IDE 1.8.9.
// Library:  PJRC Teensyduino, Version 1.4.6 32bit ARM (Raspberry Pi)
//
//-----------------------------------------------------------------------
#define LINE_BUFF_SIZE           (32)
#define MAX_SAMPS              (1024)
#define MICRO_SECONDS_PER_SAMP (1000)

volatile unsigned long  samp                =  0;
volatile unsigned long  timeTags[MAX_SAMPS] = {0};
volatile unsigned long  totalSamps          =  0;

// Create an  IntervalTimer object
IntervalTimer intervalTimer1;

// blink to show it's alive
volatile int led=13;

void setup() {

  // set up cycle counter for Teensy 3.6
  ARM_DEMCR    |= ARM_DEMCR_TRCENA;
  ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;

  // blinker
  pinMode(led,OUTPUT);
  
  Serial.begin(115200);
  intervalTimer1.begin(processSamplingEvent, MICRO_SECONDS_PER_SAMP);
}

void processSamplingEvent() {
  if (samp < MAX_SAMPS) {
    timeTags[samp++] = ARM_DWT_CYCCNT;
    totalSamps++;
  }
}

// The main program will print the accumulated time tags
// to the Arduino Serial Monitor
void loop() {
  int i;
  digitalWrite(led,LOW);
  if (samp >= MAX_SAMPS) {
    for (i = 0; i < MAX_SAMPS; i++) {
      while(Serial.availableForWrite()<LINE_BUFF_SIZE) {
        delay(1);
      }      
      Serial.print(i);
      Serial.print(" ");
      Serial.print(totalSamps+i);
      Serial.print(" ");
      Serial.println(timeTags[i]);
    }
    noInterrupts();
    samp = 0;
    interrupts();
  }
  digitalWrite(led,HIGH);
  delay(10);
}

Any thoughts on how to fix this will be appreciated.

Vince Stanford
 
Last edited by a moderator:
Correct that micros() messes with interrupts - but as noted it didn't change observed behavior. I wrote an ARM_DWT_CYCCNT based version for Teensy_4 that does not off/on interrupts - expect it can backport to T_3.x's based on quick test - just haven't addressed that yet with ongoing T4 in Beta.

perhaps reducing the factor of multiple delay()'s - perhaps this will act differently?:
Code:
constant int led=13;
// ... 

void processSamplingEvent() {
  if (samp < MAX_SAMPS) {
    timeTags[samp++] = ARM_DWT_CYCCNT;
    totalSamps++;
  }
[B]  else
      digitalWriteFast(led,LOW);
[/B]}

// The main program will print the accumulated time tags
// to the Arduino Serial Monitor
void loop() {
  int i;
  if (samp >= MAX_SAMPS) {
    for (i = 0; i < MAX_SAMPS; i++) {
      while(Serial.availableForWrite()<LINE_BUFF_SIZE) {
        [B]delayMicroseconds(100);[/B]
      }      
      Serial.print(i);
      Serial.print(" ");
      Serial.print(totalSamps+i);
      Serial.print(" ");
      Serial.println(timeTags[i]);
[B]      digitalWriteFast(led,HIGH);[/B]  
    }
    noInterrupts();
    samp = 0;
    interrupts();
  }
}
 
Thanks defragster! lengthening the delay in the Loop from 1 to 25 or 50 solves the crash problem at a 1kHz IntervalTimer frequency.

while(Serial.availableForWrite()) {
delay(1);
}

I have run the IntervalTimer ISR for millions of cycles without the crash anymore. Looks like the pile up is in the serial I/O rather than the IntervalTimer.

Next phase is to shorten MICRO_SECONDS_PER_SAMP I'd like to get this down to about 10, though I can live with 20. But the program crashes when I drop this below 250 (about 4kHz). I really want to run the ISR at 100kHz, but that seems a long way off right now. Have you heard of anyone getting it to run that fast? Even to get it to 250 I had to add the lines in loop:

intervalTimer1.update(1000000);
... Serial data dump
intervalTimer1.update(MICRO_SECONDS_PER_SAMP);

This is an attempt to throttle back the ISR while the serial data dump goes on, otherwise nothing happens by way of data dump. Any further helpful thoughts?

V

/--------------------------------------------------------------------------
// Name: intervalTimerTest
//
// Purpose - This program instruments the performance of teensyduino object
// IntervalTimer during:
//
// 1. Simple activation and timestamping using micros();
// 2. Time Stamping, and analog reading
// 3. Time Stamping, analog reading (ADC), and analog writing (DAC).
//
// Instruments with timestamp, to allow investiation of read/write
// frequencies in offline analyses
//
// Authors:
//
// Michael Stanford, Senior Software Engineer, Del Rey Analytics, LLC
// Vincent Stanford, Chief Engineer, Del Rey Analytics, LLC
//
// Date: July 16, 2019
//
// Language: Arduino C++ Arduino IDE 1.8.9.
// Library: PJRC Teensyduino, Version 1.4.6 32bit ARM (Raspberry Pi)
//
//-----------------------------------------------------------------------
#define LINE_BUFF_SIZE (64)
#define MAX_SAMPS (1024)
#define MICRO_SECONDS_PER_SAMP (250)

volatile unsigned long samp = 0;
volatile unsigned long timeTags[MAX_SAMPS] = {0};
volatile unsigned long totalSamps = 0;

// Create an IntervalTimer object
IntervalTimer intervalTimer1;

// blink to show it's alive
volatile int led=13;

void setup() {

// set up cycle counter for Teensy 3.6
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;

// blinker
pinMode(led,OUTPUT);

Serial.begin(115200);
intervalTimer1.begin(processSamplingEvent, MICRO_SECONDS_PER_SAMP);
}

void processSamplingEvent() {
if (samp < MAX_SAMPS) {
timeTags[samp++] = ARM_DWT_CYCCNT;
totalSamps++;
} else {
digitalWriteFast(led,LOW);
}
}

// The main program will print the accumulated time tags
// to the Arduino Serial Monitor
void loop() {
int i;
if (samp >= MAX_SAMPS) {
intervalTimer1.update(1000000);
for (i = 0; i < MAX_SAMPS; i++) {
while(Serial.availableForWrite()<LINE_BUFF_SIZE) {
delay(25);
}
Serial.print(i);
Serial.print(" ");
Serial.print(totalSamps+i);
Serial.print(" ");
Serial.println(timeTags);
}
noInterrupts();
samp = 0;
interrupts();
}
digitalWriteFast(led,HIGH);
intervalTimer1.update(MICRO_SECONDS_PER_SAMP);
}
 
I tried your code and could reproduce the hanging after some time.

I don't know what the "Serial.availableForWrite()" is, never saw that. Usually you can just print. Teensy will simply wait if it runs out of transfer buffer which is unlikely since you only send the block once in 1s. I removed the check and cleaned up some strange things. No it works as expected.

Remarks (see also comments in the code)
1) no need to have the led pin number volatile. No need to even define it since there is LED_BUILTIN already defined
2) For teensy long is the same as int. Both are 32bit. If it matters ist is generally better to use int32_t, int16_t etc to be sure about the size of the variable.
3) No need to disable interrupts when you access a 32bit variable, the access is atomic and can not be interrupted
4) I don't see any reason why millis() should not work in an interrupt?

Here the code which runs for me (currently at cycle 750)


Code:
// --------------------------------------------------------------------------
// Name: intervalTimerTest
//
// Purpose - This program instruments the performance of teensyduino object
// IntervalTimer during:
//
// 1. Simple activation and timestamping using micros();
// 2. Time Stamping, and analog reading
// 3. Time Stamping, analog reading (ADC), and analog writing (DAC).
//
// Instruments with timestamp, to allow investiation of read/write
// frequencies in offline analyses
//
// Authors:
//
// Michael Stanford, Senior Software Engineer, Del Rey Analytics, LLC
// Vincent Stanford, Chief Engineer, Del Rey Analytics, LLC
//
// Date: July 16, 2019
//
// Language: Arduino C++ Arduino IDE 1.8.9.
// Library:  PJRC Teensyduino, Version 1.4.6 32bit ARM (Raspberry Pi)
//
//-----------------------------------------------------------------------

#include "Arduino.h"

#define LINE_BUFF_SIZE (32)
#define MAX_SAMPS (1024)
#define MICRO_SECONDS_PER_SAMP (1000)

volatile unsigned long samp = 0; // for a teensy "long" is the same as "int" which is 32bit.
volatile unsigned long timeTags[MAX_SAMPS] = {0};
volatile unsigned long totalSamps = 0;

// Create an  IntervalTimer object
IntervalTimer intervalTimer1;

// blink to show it's alive
// volatile int led = 13; // no need to have this volatile. No need to even define it, you can use LED_BUILTIN instead

void processSamplingEvent()
{
   if (samp < MAX_SAMPS)
   {
      //timeTags[samp++] = ARM_DWT_CYCCNT;
      timeTags[samp++] = millis();  // I don't see why millis should not work here???
      totalSamps++;
   }
}

void setup()
{
   // set up cycle counter for Teensy 3.6
   ARM_DEMCR |= ARM_DEMCR_TRCENA;
   ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;

   // blinker
   pinMode(LED_BUILTIN, OUTPUT);

   Serial.begin(115200);
   intervalTimer1.begin(processSamplingEvent, MICRO_SECONDS_PER_SAMP);
}

// The main program will print the accumulated time tags
// to the Arduino Serial Monitor
void loop()
{
   static unsigned loopCnt = 0; // want to see which loop we are in

   int i;
   // digitalWrite(LED_BUILTIN, LOW);  // that was placed somehow strange. Moved
   // it int the loop to be HIGH only when it is outputing data
   if (samp >= MAX_SAMPS)
   {
      digitalWrite(LED_BUILTIN, HIGH);
      for (i = 0; i < MAX_SAMPS; i++)
      {
         // I don't see why you would need that?, you can just print
         //  while (Serial.availableForWrite() < LINE_BUFF_SIZE)
         //  {
         //     delay(1);
         //  }

         Serial.print(i);
         Serial.print(" ");
         Serial.print(totalSamps + i);
         Serial.print(" ");
         Serial.println(timeTags[i]);
      }

      Serial.println("\n---------------");
      Serial.println(loopCnt++);

      //noInterrupts();    <- not necessary, samp=0 is atomar
      samp = 0;
      //interrupts();
      digitalWrite(LED_BUILTIN, LOW);
   }
   delay(10);
}

ad.PNG
 
Just tried it with MICRO_SECONDS_PER_SAMP (50)
Works without a problem...

(you might want to increase the last delay in loop if you go further down to not overrun your serial monitor. TyCommander is quite unimpressed though)
 
I tried your code and could reproduce the hanging after some time.

I don't know what the "Serial.availableForWrite()" is, never saw that. Usually you can just print. Teensy will simply wait if it runs out of transfer buffer which is unlikely since you only send the block once in 1s. I removed the check and cleaned up some strange things. No it works as expected.

Remarks (see also comments in the code)
1) no need to have the led pin number volatile. No need to even define it since there is LED_BUILTIN already defined
2) For teensy long is the same as int. Both are 32bit. If it matters ist is generally better to use int32_t, int16_t etc to be sure about the size of the variable.
3) No need to disable interrupts when you access a 32bit variable, the access is atomic and can not be interrupted
4) I don't see any reason why millis() should not work in an interrupt?

Here the code which runs for me (currently at cycle 650)

I was going to question the use of the availableForWrite() and comment it out. I've only ever used it on T4_Beta test and quickly on another Teensy and it seemed odd. Teensy USB buffers and moderates well - can overwhelm the Host - then some timely waits are called for.

1> in snippet post above LED pin was made constant as it allows ideal coding with digitalWriteFast(). Indeed more samples should use LED_BUILTIN
4> OP referred to micros() usage - and that changing it didn't affect the issue. But micros() coding is way more involved as written.
 
OP referred to micros() usage
Ups, didn't read carefully.... Anyway, looks like the unnecessary availableForWrite is the root cause of the problem...
 
First, thanks all for looking at this.

Some key points:

1. millis() won't work since I want to run at 100kHz. MICRO_SECONDS_PER_SAMP = 1000 was just to get it to run at all. I want to #define MICRO_SECONDS_PER_SAMP = 10. This fails. I got this down to #define MICRO_SECONDS_PER_SAMP = 250. That's only 4kHz. I had problems with micros() too.

2. Lots of posts here say millis() and micros() are not for interrupt service routines. ARM_DWT_CYCCNT apparently just store of the processor cycle count register. Paul and others say to avoid function calls in interrupt service routines.

3. The program just crashes without Serial.availableForWrite() based delays. It crashes after thousands of cycles a while with:

while(Serial.availableForWrite()<LINE_BUFF_SIZE) {
delay(1);
}

I just ran 24 hours with delay(25). It required hardware restarts on the teensy board. Less touchy at delay(100) kindly suggested by defragster (also slower in the data dump part of the duty cycle).

4. From Arduino reference for "int"

"On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1). On the Arduino Due and SAMD based boards (like MKR1000 and Zero), an int stores a 32-bit (4-byte) value. This yields a range of -2,147,483,648 to 2,147,483,647 (minimum value of -2^31 and a maximum value of (2^31) - 1)."

So it's board dependent. Using long guarantees 32 bit across all the Arduino board including the AVR's. No harm to use unsigned long certainly. unint32_t is another way to assure 32 bits, but int doesn't assure this on all the boards.

5. Any thoughts on getting this to run at 10 micro second intervals will be greatly appreciated.
 
Additional follow-up: Just ran on Big Mac for over an hour with
1. Delay loop based on Serial.availableForWrite was less than delay(5), and
2. MICRO_SECONDS_PER_SAMP = 1
Running without crashes.

Still wonder about why I can't run this with delay(1) in the serial wait loop. That could be a remaining bug to think about.
 
Here a version which runs with a sampling rate of 1µs, I still do not see any need for the Serial.availableForWrite.
Runs for an hour now on Win10 and TyCommander.
Code:
#include "Arduino.h"

constexpr unsigned LINE_BUFF_SIZE = 32;
constexpr unsigned MAX_SAMPS = 1024;
constexpr unsigned MICRO_SECONDS_PER_SAMP = 1;

volatile unsigned  samp = 0;
volatile unsigned  timeTags[MAX_SAMPS];
volatile unsigned  totalSamps = 0;

// Create an  IntervalTimer object
IntervalTimer intervalTimer1;

void processSamplingEvent()
{
   if (samp < MAX_SAMPS)
   {
      digitalWriteFast(0,HIGH);
      timeTags[samp++] = ARM_DWT_CYCCNT;      
      totalSamps++;
      digitalWriteFast(0,LOW);
   }
}

void setup()
{
   ARM_DEMCR |= ARM_DEMCR_TRCENA;
   ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;

   pinMode(LED_BUILTIN, OUTPUT);
   pinMode(0,OUTPUT);
   
   intervalTimer1.begin(processSamplingEvent, MICRO_SECONDS_PER_SAMP);
}
void loop()
{       
   if (samp >= MAX_SAMPS)
   {
      digitalWriteFast(LED_BUILTIN, HIGH);
      for (unsigned i = 0; i < MAX_SAMPS; i++)
      {
         Serial.printf("%u %u %u\n", i, totalSamps, timeTags[i]);
      }
      digitalWriteFast(LED_BUILTIN, LOW);

      Serial.println("\n---------------");
      delay(10); // give the attached hardware (RasPi, PC...) time to read in its buffer. 

      samp = 0;
   }  
}

I added a delay(10) after sending the data to the PC to give it time to empty its buffers. You might need to increase this for slow hardware (Raspi) Otherwise the serial monitor might get overrun and stop reading from serial and your Serial.availableForWrite might get confused?

Here a pic of the sampling ISR runing at 1MHz
ad_burst.jpg

Here zoomed out, showing that it actually generates 1024 pulses
ad_burst2.PNG

Further zoomed out, showing that the sending on serial takes about 44ms. After the sending you see the 10ms waiting time to make life easier for the serial monitor.
ad_burst3.jpg

Would be interesting if that sketch runs at your MAC as well.
 
Last edited:
If you are interested in some data:

The sketch from above (#10) ran for about 3h. It generated a total number of ~100 Mio ISR calls @1µs sample period and transferred some 2.3GByte over USB-Serial to the PC.
I didn't observe any crash or any other unusual behaviour. So that seems to work quite stable (at least for my setup...)
 
First, thank you for you kind assistance. The Teensy community is impressively helpful and vital. It is a treat to find a community like this. So thanks again.

As to the asynchronous I/O if fine the following in the Arduino release notes:

Release Notes ARDUINO 1.0 - 2011.11.30 [core / libraries]
“Serial transmission is now asynchronous - that is, calls to
Serial.print(), etc. add data to an outgoing buffer which is transmitted
in the background. Also, the Serial.flush() command has been repurposed
to wait for outgoing data to be transmitted, rather than dropping
received incoming data.”

Arduino.cc Reference pages:

Serial.availableForWrite()
Description
Get the number of bytes (characters) available for writing in the serial buffer without blocking the write operation.
Syntax
Serial.availableForWrite()
Parameters
Serial: serial port object. See the list of available serial ports for each board on the*Serial main page.
Returns
The number of bytes available to write.

So the Arduino Serial.print, etc. libraries are apparently asynchronous by design. This means you can overrun the output buffer unless you check.
------------------
Your code definitely does not crash on my Xeon Mac Pro. But it does show a few mangled lines like the one shown below. I compiled and uploaded your code into the T3.5. When I use my serial capture program to capture output from your program in the T3.5 I see occasional stuff like this:

26 428032 329300827
27 428032 329300944
28 428032 329301076
29 4280 89187328 4233050852 <— mangled line
1 89187328 4233050964
2 89187328 4233051092
3 89187328 4233051212
...
I've been seeing these mangled lines every several thousand lines in my Teensy Serial output since I started to use Teensy’s. I think this as symptomatic of buffer overruns. I don’t see them at all when I use Serial.availableForWrite(). Also, my program crashes without this check.

Thanks again!
 
So the Arduino Serial.print, etc. libraries are apparently asynchronous by design. This means you can overrun the output buffer unless you check.

I think you got that slightly wrong.
As long as there is enough buffer the print/write functions copy their stuff to the buffer and return immediately. If there is not enough buffer left, they will block, i.e. the functions will wait until there is enough free buffer and return afterwards. You can never overrun that buffer and checking for enough free space is (usually) not necessary.

Here a quick sketch to demonstrate that:
Code:
uint8_t buffer[64];

void setup()
{
   pinMode(0, OUTPUT);

   // fill the buffer with 'X' and put a \n at the end
   memset(buffer, 'X', sizeof(buffer));
   buffer[sizeof(buffer) - 1] = '\n';
}

void loop()
{
   for (int i = 0; i < 30; i++)            // try to overrun usb-serial buffer
   {
      digitalWriteFast(0, HIGH);            // check the timing of
      Serial.write(buffer, sizeof(buffer)); // writing to usb-serial
      digitalWriteFast(0, LOW);
   }

   delay(10);
}

The sketch copies 30 times a 64 char string to the bus as fast as possible. The required time for the Serial.write() can be monitored on pin 0.

buf0.PNG

Zoomed in:
buf1.jpg

As can be seen, the first 10 writes (10 x 64 bytes) are done in some 7µs per 64 bytes, after that the buffer is full and the write function needs to wait until there is free space which takes about 100µs. -> No buffer override, the Teensy manages that pretty well, so normally printing to Serial just works...


Your code definitely does not crash on my Xeon Mac Pro. But it does show a few mangled lines like the one shown below. I compiled and uploaded your code into the T3.5. When I use my serial capture program to capture output from your program in the T3.5 I see occasional stuff like this:

26 428032 329300827
27 428032 329300944
28 428032 329301076
29 4280 89187328 4233050852 <— mangled line
1 89187328 4233050964
2 89187328 4233051092
3 89187328 4233051212
...
I've been seeing these mangled lines every several thousand lines in my Teensy Serial output since I started to use Teensy’s. I think this as symptomatic of buffer overruns. I don’t see them at all when I use Serial.availableForWrite(). Also, my program crashes without this check.

I'm quite sure that the reason for this is that your serial monitor can't follow the high data rate. Teensy detects when the host doesn't read the sent bytes anymore and waits with sending for some time. If the host does not read the data for longer than ~70ms it will discard following data until the host listens again. This would lead to the "mangled line" you see above. You also see that after the "mangled line" the byte counter starts at 1. So, the delay(10) after sending the last block apparently was enough for your serial monitor to recover and the Teensy started to send again.

If you want to try you could add some delay after printing in my code. I.e.,
Code:
void loop()
{       
   if (samp >= MAX_SAMPS)
   {
      digitalWriteFast(LED_BUILTIN, HIGH);
      for (unsigned i = 0; i < MAX_SAMPS; i++)
      {
         Serial.printf("%u %u %u\n", i, totalSamps, timeTags[i]);
         delayMicroseconds(50); // <- value depends on the speed of you serial monitor... TyCommand is extremely fast and does not need any delay here
      }
      digitalWriteFast(LED_BUILTIN, LOW);

      Serial.println("\n---------------");
      delay(10); // give the attached hardware (RasPi, PC...) time to read in its buffer. 

      samp = 0;
   }  
}

Here some related code from usb-serial.c: which explains what is happening (line 147 ff)

Code:
/ When the PC isn't listening, how long do we wait before discarding data?  If this is
// too short, we risk losing data during the stalls that are common with ordinary desktop
// software.  If it's too long, we stall the user's program when no software is running.
#define TX_TIMEOUT_MSEC 70
#if F_CPU == 256000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1706)
#elif F_CPU == 240000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1600)
#elif F_CPU == 216000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1440)
#elif F_CPU == 192000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1280)
#elif F_CPU == 180000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1200)
#elif F_CPU == 168000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 1100)
#elif F_CPU == 144000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 932)
#elif F_CPU == 120000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 764)
#elif F_CPU == 96000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 596)
#elif F_CPU == 72000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 512)
#elif F_CPU == 48000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 428)
#elif F_CPU == 24000000
  #define TX_TIMEOUT (TX_TIMEOUT_MSEC * 262)
#endif

// When we've suffered the transmit timeout, don't wait again until the computer
// begins accepting data.  If no software is running to receive, we'll just discard
// data as rapidly as Serial.print() can generate it, until there's something to
// actually receive it.
static uint8_t transmit_previous_timeout=0;
 
luni,

Thank you very much for your thoughtful help, code, and suggestions. I now have a program that is working flawlessly, and you definitely helped get it working. Lots of food for thought in the discussion.

Best Regards,

vms
 
Back
Top