Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 15 of 15

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

  1. #1
    Junior Member
    Join Date
    Apr 2019
    Posts
    6

    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 defragster; 07-23-2019 at 07:05 AM. Reason: added CODE # for readability

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,125
    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++;
      }
      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) {
        for (i = 0; i < MAX_SAMPS; i++) {
          while(Serial.availableForWrite()<LINE_BUFF_SIZE) {
            delayMicroseconds(100);
          }      
          Serial.print(i);
          Serial.print(" ");
          Serial.print(totalSamps+i);
          Serial.print(" ");
          Serial.println(timeTags[i]);
          digitalWriteFast(led,HIGH);  
        }
        noInterrupts();
        samp = 0;
        interrupts();
      }
    }

  3. #3
    Junior Member
    Join Date
    Apr 2019
    Posts
    6
    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[i]);
    }
    noInterrupts();
    samp = 0;
    interrupts();
    }
    digitalWriteFast(led,HIGH);
    intervalTimer1.update(MICRO_SECONDS_PER_SAMP);
    }

  4. #4
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    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);
    }
    Click image for larger version. 

Name:	ad.PNG 
Views:	9 
Size:	36.0 KB 
ID:	17060

  5. #5
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    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)

  6. #6
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,125
    Quote Originally Posted by luni View Post
    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.

  7. #7
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    OP referred to micros() usage
    Ups, didn't read carefully.... Anyway, looks like the unnecessary availableForWrite is the root cause of the problem...

  8. #8
    Junior Member
    Join Date
    Apr 2019
    Posts
    6
    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.

  9. #9
    Junior Member
    Join Date
    Apr 2019
    Posts
    6
    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.

  10. #10
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    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
    Click image for larger version. 

Name:	ad_burst.jpg 
Views:	9 
Size:	30.7 KB 
ID:	17066

    Here zoomed out, showing that it actually generates 1024 pulses
    Click image for larger version. 

Name:	ad_burst2.PNG 
Views:	9 
Size:	31.6 KB 
ID:	17067

    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.
    Click image for larger version. 

Name:	ad_burst3.jpg 
Views:	11 
Size:	32.8 KB 
ID:	17068

    Would be interesting if that sketch runs at your MAC as well.
    Last edited by luni; 07-25-2019 at 07:37 PM.

  11. #11
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    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...)

  12. #12
    Junior Member
    Join Date
    Apr 2019
    Posts
    6
    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!

  13. #13
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    deleted ------

  14. #14
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    578
    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.

    Click image for larger version. 

Name:	buf0.PNG 
Views:	7 
Size:	28.3 KB 
ID:	17072

    Zoomed in:
    Click image for larger version. 

Name:	buf1.jpg 
Views:	8 
Size:	30.6 KB 
ID:	17073

    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;

  15. #15
    Junior Member
    Join Date
    Apr 2019
    Posts
    6
    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •