Teensy 4.0 serial USB receive data loss

Status
Not open for further replies.
Hi ,guys

I try send image data (9844 bytes) to android every 9millisec at the serial USB,but sometime the data will be lost,that the probability of loss is about 7%.

How to solve this problem?
 
As mentioned hard to say much without seeing the code.

Also note, the T4.x USB can output a lot faster than T3.x and maybe it is simply your Android app can not keep up. Maybe the Androids USB is busy doing something else some of the time.
 
This is my code.I use USB serial that speed should always 12 Mbit/sec.I think android should have no problem with speed,that just receive data and print to screen.

Code:
#include <SPI.h>

#define VOSPI_FRAME_SIZE (60)
#define VOSPI_PACKET_SIZE (164)


int lepton_frame_packet[VOSPI_FRAME_SIZE][VOSPI_PACKET_SIZE];
int segment_line=0;
int segment_print=0;
int package_line[VOSPI_FRAME_SIZE];
int disc_cont=0,inva_timeout=0;
void setup()
{
  delay(5000);
  Serial.begin(12000000);

  pinMode(10, OUTPUT);
  pinMode(3, INPUT);
  SPI.begin();
  SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE3));
  Serial.println("setup complete");
  digitalWrite(10, HIGH);
}



void read_lepton_frame(void)
{
  int i ,j;
  disc_cont =0;
  for(j = 0; j < (VOSPI_FRAME_SIZE); j++){
    digitalWrite(10, LOW);
    for (i = 0; i < (VOSPI_PACKET_SIZE); i++){
        lepton_frame_packet[j][i] = SPI.transfer(0x00);
    }
    digitalWrite(10, HIGH);
    package_line[j] = ((lepton_frame_packet[j][0] & 0x0f) <<8) | lepton_frame_packet[j][1];
       
    if(package_line[j]>60){
      disc_cont++;
      if(disc_cont < 30){
        j--;
      }
      else if(disc_cont == 20) {
        inva_timeout++;
        segment_line = 0;
      }
    }
    else{
      if(package_line[j] == 20){
      segment_line = (lepton_frame_packet[j][0] & 0x70) >> 4;
      if(segment_line == 1){
        frame_flag=1;
        inva_timeout=0;
      }
      else if(segment_line == 0 || segment_line>4){
        inva_timeout++;
      }
     }
   }

    
    
    //7u sec packet delaytime
    delayMicroseconds(3);
  }   
}


void print_lepton_frame_data(void)
{
  int i,j;
  Serial.write(0xFF);
  Serial.write(0xFF);
  Serial.write(0xFF);
  Serial.write(segment_line);
  for (j = 0; j < VOSPI_FRAME_SIZE; j++){  
    for (i = 0; i < VOSPI_PACKET_SIZE; i++){
      Serial.write(lepton_frame_packet[j][i]);
    }
  }
}

void loop()
{
    if (digitalRead(3) == HIGH){
      if(inva_timeout > 20){
        delay(200);
        inva_timeout=0;
      }
      else{
       read_lepton_frame();
       if(segment_line>0 && segment_line<5 && disc_cont<20){
          print_lepton_frame_data();        
          segment_line=0;
       }
      }
    }

}
 
When tested does this work sending to a PC SerMon? Seeing the code it might take replacing actual data in :: print_lepton_frame_data(void)

With human readable/verifiable ASCII data to assure it is working as expected.

As @KurtE noted the T_4.0 USB output could be overwhelming the android ability to receive and process. The T_4.0 can blow away a PC unless regulated.
 
When tested does this work sending to a PC SerMon? Seeing the code it might take replacing actual data in :: print_lepton_frame_data(void)

With human readable/verifiable ASCII data to assure it is working as expected.

As @KurtE noted the T_4.0 USB output could be overwhelming the android ability to receive and process. The T_4.0 can blow away a PC unless regulated.

Yes,this does work to PC SerMon,but the PC SerMon has loss data.
I can't replacing to ASCII data,because I need to read SPI data and transmit to USB Serial in 9 millisec ,that takes 7 .millisec to read SPI data and 1millisec to transmit (raw)data to USB Serial,so ASCII data is too big for me.Also do you know how to only receive SPI data instead of receiving and transmitting at the same time?that can shorten the time for me.

Okay,I will check android.
 
Yes,this does work to PC SerMon,but the PC SerMon has loss data.
I can't replacing to ASCII data,because I need to read SPI data and transmit to USB Serial in 9 millisec ,that takes 7 .millisec to read SPI data and 1millisec to transmit (raw)data to USB Serial,so ASCII data is too big for me.Also do you know how to only receive SPI data instead of receiving and transmitting at the same time?that can shorten the time for me.

Okay,I will check android.

Not sure how to read the first line ... it works ... but data loss both with PC? That .write() data will present unprintable characters to SerMon.

Suggestion was byte for byte replacement of the Serial.write()'s with some ASCII chars - so exact same transfer size? Something like:
Code:
void print_lepton_frame_data_fake(void)
{
  int i,j;
  Serial.print('a');
  Serial.print('a');
  Serial.print('a');
  Serial.print('\n');
  for (j = 0; j < VOSPI_FRAME_SIZE; j++){  
    for (i = 0; i < VOSPI_PACKET_SIZE-1; i++){ // reduce by 1 for the newline
      Serial.print('A'+(i*j)%26);
    }
    Serial.print('\n');
  }
}
 
Not sure how to read the first line ... it works ... but data loss both with PC? That .write() data will present unprintable characters to SerMon.

Suggestion was byte for byte replacement of the Serial.write()'s with some ASCII chars - so exact same transfer size? Something like:
Code:
void print_lepton_frame_data_fake(void)
{
  int i,j;
  Serial.print('a');
  Serial.print('a');
  Serial.print('a');
  Serial.print('\n');
  for (j = 0; j < VOSPI_FRAME_SIZE; j++){  
    for (i = 0; i < VOSPI_PACKET_SIZE-1; i++){ // reduce by 1 for the newline
      Serial.print('A'+(i*j)%26);
    }
    Serial.print('\n');
  }
}

I using Serial Debug Assistant on win10,that can use HEX display,so I can read raw data.
And then I manually check whether the data is correct,that has found lose some data at the some time.
 
I using Serial Debug Assistant on win10,that can use HEX display,so I can read raw data.
And then I manually check whether the data is correct,that has found lose some data at the some time.

If the PC can't be shown to handle the data - it is coming out too fast to receive and parse and GUI present.

Of course the coding of the 'Serial Debug Assistant' may not be up to handling it. Paul worked a week or more to get SerMon to be able to buffer the data from a T_4.0 as well as it does. A T_3.6 with 12Mbps USB could overwhelm the old code with just over 1 MB/sec - the T_4.0 is 20 times faster

This is a large short burst - 111 times per second - only 1.094 MB /second - but it is surging at max speed at those times.

Doing the ASCII out to Paul's Teensy SerMon - would show if data is still/really being lost. It might take a bit more than the '_fake' code above to make it easily human readable/verifiable.
 
I want to reproduce this problem, but I need a little help. Two issues...

1: Does the problem happen if you disconnect the external hardware and just connect pin 3 and pin 12 to ground? What happens if code is added to write patterns into the "lepton_frame_packet" array? I'm hoping you can give this a try and if it "works", please post a modified program I can run here without the external hardware (ground pins 3 and 12) so the Teensy is still doing the same SPI communication but sending known data to the PC.

2: Can you be more specific about "Serial Debug Assistant"? I tried a quick Google search which found many sites offering programs with this name, even Microsoft's app store with one having in-app purchases! Please understand I use Linux and occasionally Macintosh (pretty much only for video editing) but almost never Windows, so I am not very familiar with Windows details. But I do have a dual-boot Macbook which can run Windows 10. Please help me to get the exact same software you're using, and please be very specific about any setup I need, since I'm not normally a Windows user. Hopefully with detailed info I can get my Macbook to closely reproduce what you're doing?


About this question:

Also do you know how to only receive SPI data instead of receiving and transmitting at the same time?that can shorten the time for me.

SPI always transmits and receives simultaneously. On every clock of SCK, the MOSI pin transmits 1 bit while the MISO pin receives 1 bit. This is simply how SPI works. Transmitting data doesn't make SPI speed any different.

However, using SPI one byte at a time is slower than doing a large transfer all at once. If you use SPI.transfer(buffer, length) the wasted time between each byte will be minimized. Remember, SPI always transmits while it receives, so fill the buffer to zeros before you call this. When it returns, the buffer will be filled with the received data.
 
This is my code.I use USB serial that speed should always 12 Mbit/sec.I think android should have no problem with speed,that just receive data and print to screen.
@Shawn and @Paul - I believe the T4.x's do USB at High Speed (480MBS), where as the T3.x runs at Full Speed of 12MBS... So the T4 can spit out USB data a lot faster than T3.x which is why things like the Serial monitor can be overrun...

However, using SPI one byte at a time is slower than doing a large transfer all at once. If you use SPI.transfer(buffer, length) the wasted time between each byte will be minimized. Remember, SPI always transmits while it receives, so fill the buffer to zeros before you call this. When it returns, the buffer will be filled with the received data.
For cases like this I prefer the other multi byte transfer methods...
That is I personally hate the API that overwrites your original buffer, except maybe for boards which have a real small memory. Instead use one, that you can pass in your TX buffer and your RX buffer, and either of which can be NULL. In the case where TX buffer is NULL, the code will output a constant value which defaults to 0, but can be changed by using the setTransferWriteFill method:
If rx buffer is NULL, it throws the results away.
Code:
	void setTransferWriteFill(uint8_t ch ) {_transferWriteFill = ch;}
	void transfer(const void * buf, void * retbuf, size_t count);

Also from above I thought the main target for the USB data was an Android?
 
If the PC can't be shown to handle the data - it is coming out too fast to receive and parse and GUI present.

Of course the coding of the 'Serial Debug Assistant' may not be up to handling it. Paul worked a week or more to get SerMon to be able to buffer the data from a T_4.0 as well as it does. A T_3.6 with 12Mbps USB could overwhelm the old code with just over 1 MB/sec - the T_4.0 is 20 times faster

This is a large short burst - 111 times per second - only 1.094 MB /second - but it is surging at max speed at those times.

Doing the ASCII out to Paul's Teensy SerMon - would show if data is still/really being lost. It might take a bit more than the '_fake' code above to make it easily human readable/verifiable.

I using the ASCII and check to Paul's Teensy SerMon,that looks like not loss data,maybe you're right, T_4.0 USB output be overwhelming the android.

But the android is just read and check data,is this really overwhelming?I am use the android on Quectel SC66.
 
There was another post with UNO using String - which is generally a scary thing depending on the volatility and chance for fragmentation - but general 'running out of memory' fails gracefully these days.

Was bored so put it on a T_4.0 that was plugged in - it DESTROYS the PC SerMon! IDE SerMon closes in a flash and TyCommander did better - garbage chars ( seen before as PC scrambles buffer data? ) and it hung - but not well. String grows by 3,4,5 bytes each loop adding the 'loop count' as ascii chars and loops so much faster and memory on T_4.0 doesn't get near used and RAM - printing the string of a few thousand chars kills Sermon. Added delay() and tried .substring prints to break up the output and never got it stable before I quit. The .substring prints appeared 'out of order'.

So yes bulk output of 9K chars is pushing it - luckily your code has breaks in it during SPI.

> Wonder if it might be better to print blocks as received rather than 9K at once? If buffered in 512 Byte blocks that fits into one USB packet on T_4. May complicate the SPI reading and slow it a bit (though if the SPI tips form Paul and KurtE work it might go faster too) - but make for more USB friendly transfer

Other historical note - other than IDE Sermon took days of work and refinement for Paul to get it where it is ... seeming up to PC USB data handling limits with GUI printing.
> Python on a PC would miss data in the past - unless the receive code was super efficient - and IIRC that was on a T_3.6? Not sure anyone has sent high speed T_4.x data to a PC receiving on Python yet, if so they had it working.

Not sure of Android USB data handling - but it has fewer resources and less testing for such an abusive case so would be surprised if it could keep up with code probably less speedy than Python on a PC with a slower processor.

You could run the 'ascii' test against the Android and see if you can make a data receiver expecting the ASCII data to parse or count in a usable fashion to verify throughput.
 
1: Does the problem happen if you disconnect the external hardware and just connect pin 3 and pin 12 to ground? What happens if code is added to write patterns into the "lepton_frame_packet" array? I'm hoping you can give this a try and if it "works", please post a modified program I can run here without the external hardware (ground pins 3 and 12) so the Teensy is still doing the same SPI communication but sending known data to the PC.

Thank your help. I found is not USB data loss.I use your method,the android is not loss data.so cause of the problem should spi or hardware.

2: Can you be more specific about "Serial Debug Assistant"? I tried a quick Google search which found many sites offering programs with this name, even Microsoft's app store with one having in-app purchases! Please understand I use Linux and occasionally Macintosh (pretty much only for video editing) but almost never Windows, so I am not very familiar with Windows details. But I do have a dual-boot Macbook which can run Windows 10. Please help me to get the exact same software you're using, and please be very specific about any setup I need, since I'm not normally a Windows user. Hopefully with detailed info I can get my Macbook to closely reproduce what you're doing?

I download this app from Microsoft's app store (https://www.microsoft.com/en-us/p/serial-debug-assistant/9nblggh43hdm?activetab=pivot:overviewtab)
 
However, using SPI one byte at a time is slower than doing a large transfer all at once. If you use SPI.transfer(buffer, length) the wasted time between each byte will be minimized. Remember, SPI always transmits while it receives, so fill the buffer to zeros before you call this. When it returns, the buffer will be filled with the received data.

For cases like this I prefer the other multi byte transfer methods...
That is I personally hate the API that overwrites your original buffer, except maybe for boards which have a real small memory. Instead use one, that you can pass in your TX buffer and your RX buffer, and either of which can be NULL. In the case where TX buffer is NULL, the code will output a constant value which defaults to 0, but can be changed by using the setTransferWriteFill method:
If rx buffer is NULL, it throws the results away.

@KurtE and @PaulStoffregen - I try to this solutions,but neither work.Maybe I use it wrong.

Code:
void setup()
{
  int i,j;  Serial.begin(12000000);

  pinMode(10, OUTPUT);
  pinMode(3, INPUT);
  SPI.begin();
  SPI.beginTransaction(SPISettings(20000000, MSBFIRST, SPI_MODE3));
  Serial.println("setup complete");
  digitalWrite(10, HIGH);
  
  for(j = 0; j < (VOSPI_FRAME_SIZE); j++){
    for (i = 0; i < (VOSPI_PACKET_SIZE); i++){
          lepton_frame_packet[j][i] = 0;
      }
  }
}



void read_lepton_frame(void)
{
  int i ,j;
  disc_cont =0;
  for(j = 0; j < (VOSPI_FRAME_SIZE); j++){
    digitalWrite(10, LOW);
    SPI.transfer(lepton_frame_packet[j], VOSPI_PACKET_SIZE);
    digitalWrite(10, HIGH);
    package_line[j] = ((lepton_frame_packet[j][0] & 0x0f) <<8) | lepton_frame_packet[j][1];
       
    if(package_line[j]>60){
      disc_cont++;
      if(disc_cont < 30){
        j--;
      }
      else if(disc_cont == 20) {
        inva_timeout++;
        segment_line = 0;
      }
    }
    else{
      if(package_line[j] == 20){
      segment_line = (lepton_frame_packet[j][0] & 0x70) >> 4;
      if(segment_line == 1){
        frame_flag=1;
        inva_timeout=0;
      }
      else if(segment_line == 0 || segment_line>4){
        inva_timeout++;
      }
     }
   }
    //7u sec packet delaytime
    delayMicroseconds(3);
  }   
}

and
Code:
SPI.transfer(nullptr,lepton_frame_packet[j], VOSPI_PACKET_SIZE);
 
Status
Not open for further replies.
Back
Top