Teensy4.0 does not receive data longer than 62 characters

Status
Not open for further replies.
Hello everybody. I'm writing a simple communication program with Teensy 4.0.

Please give me a hint as data reception from the terminal does not go well.

In the attached program, if I send characters over 62 bytes to Teensy4.0, it will no longer respond.

Where is my mistake?

Code:
String    hostString = "";

void setup() {
  // put your setup code here, to run once:
  Serial.begin(38400);
  hostString = "";
}

void    serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    hostString += inChar;
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  if (hostString.length()){
    Serial.print(hostString);
    hostString = "";
  }
}
 
Last edited by a moderator:
Tried that code here and it works - given "1234567890a1234567890b1234567890c1234567890d1234567890e1234567890f1234567890g1234567890h"

That is 8 sets of 10 digits and 8 letters - for 88 character total.

Works for MOST any length String EXCEPT exactly this string of "123456789012345678901234567890123456789012345678901234567890abc" 63 chars plus NewLine :: Total 64.

ANY set of 64 chars as such are Perfectly HIDDEN - until a longer or shorter string are send and then those buffered strings are released in order received.

@Paul - this seems to be a USB receive bug.
 
WITH A TWIST??? - written as a NULL term c string and not a STRING:
Code:
char szH[400];
uint32_t ii=0;
void setup() {
  Serial.begin(38400);
}

void serialEvent() {
  while (Serial.available()) {
    szH[ii++] = (char)Serial.read();
  }
}

void loop() {
  // put your main code here, to run repeatedly:
  if (ii) {
    Serial.print(szH);
    Serial.print("| #=");
    Serial.println(ii);
    for ( ii=0; ii<400; ii++) szH[ii]=0;
    ii=0;
  }
}

This works as in this SerMon output?
123456789012345678901234567890123456789012345678901234567890
| #=61
123456789012345678901234567890123456789012345678901234567890a
| #=62
123456789012345678901234567890123456789012345678901234567890ab
| #=63
123456789012345678901234567890123456789012345678901234567890abc
| #=64
123456789012345678901234567890123456789012345678901234567890abcd| #=64

| #=1
123456789012345678901234567890123456789012345678901234567890abcd| #=64
e
| #=2
 
I’m pretty sure this makes sense since the default serial buffer size is 64, I believe the number can be easily edited in one of the Teensy core files. So anything over 64 would be read in multiples instead of one long stream.
 
Post #3 shows expected sensible results - NO PROBLEM after all ? - the lines and '|' separator show the newline placement and where 64 byte expected buffer shows up.

>> post #1 && #2 with the STRING code is having an issue where the string isn't empty but somehow 'if (hostString.length()){' isn't triggering until it is a non 64 multiple?
 
Maybe the string isn’t be null terminated properly if the there’s an exact amount in the buffer?
 
Sorry about the very long delay on this urgent problem.

What I've learned so far is this problem which seems to be a USB receiving bug is actually happening on the transmit side. Teensy is receiving the 64 bytes promptly, and it is quickly sending the 64 byte reply. But it's not sending a zero length packet to inform the host side to process the data it has received, so the 64 bytes Teensy sends linger in a buffer on your PC until Teensy sends another packet.

Here's the actual USB packets. You can see Teensy quickly replies.

sc.png

This is testing with Teensyduino 1.48. The USB code has already changed somewhat on github for larger packets, but I wanted to reproduce it first with 1.48 and 64 bytes.

Now that I know what's happening, I should have a fix soon. This is also the bug that's been holding up work on USB MIDI and other USB protocols, so I hope to finally get a first beta for those sometime this weekend.
 
I've committed a fix on github. I was able to reproduce the problem with the latest code using a 512 byte string.

https://github.com/PaulStoffregen/cores/commit/24e0248267da3fc4c1db88eb863a707265d9c192

Fortunately the fix is very easy. If you want to patch your copy of 1.48, just find this line in {arduino}/hardware/teensy/avr/cores/teensy4/usb_serial.c

Code:
    usb_config_tx(CDC_TX_ENDPOINT, CDC_TX_SIZE, 0, NULL);

and change it to this:

Code:
    usb_config_tx(CDC_TX_ENDPOINT, CDC_TX_SIZE, 1, NULL);
 
Sorry about the very long delay on this urgent problem.

What I've learned so far is this problem which seems to be a USB receiving bug is actually happening on the transmit side. Teensy is receiving the 64 bytes promptly, and it is quickly sending the 64 byte reply. But it's not sending a zero length packet to inform the host side to process the data it has received, so the 64 bytes Teensy sends linger in a buffer on your PC until Teensy sends another packet.

Here's the actual USB packets. You can see Teensy quickly replies.

...

This is testing with Teensyduino 1.48. The USB code has already changed somewhat on github for larger packets, but I wanted to reproduce it first with 1.48 and 64 bytes.

Now that I know what's happening, I should have a fix soon. This is also the bug that's been holding up work on USB MIDI and other USB protocols, so I hope to finally get a first beta for those sometime this weekend.

Cool. I see github updated 14 mins ago

Will have to see if that reflects on this one too: Teensy-4-0-USB-serial-lockup

And maybe this one : Teensy-4-0-Serial-available()-stops-incrementing
 
Fortunately the fix is very easy. If you want to patch your copy of 1.48, just find this line in {arduino}/hardware/teensy/avr/cores/teensy4/usb_serial.c

Code:
    usb_config_tx(CDC_TX_ENDPOINT, CDC_TX_SIZE, 0, NULL);

and change it to this:

Code:
    usb_config_tx(CDC_TX_ENDPOINT, CDC_TX_SIZE, 1, NULL);

Ahh, thank you for finding that. That fixed an oddball error that had puzzled me. I had the Teensy sending a page of text, then waiting for a character before sending the next page. In one particular spot, in one particular file, I wouldn't see the last half of a line at the end of the page until I sent the character. I'd hacked around it in my program by flushing the Tx buffer every 32 characters. While it worked, I couldn't figure out why. After applying your patch and taking out the hack in my program, it no longer exhibits that odd behaviour. Remove your patch, and the oddity comes right back. Put your patch back in, and the oddity is gone again. Again, thank you! One less "why on earth is it doing THAT?" to puzzle over!
 
Updated code from Github runs post #1 code with post #2 FAIL string :: "1234567890123456789012345678901234567890123456789 01234567890abc"
 
Updated code from Github runs post #1 code with post #2 FAIL string :: "1234567890123456789012345678901234567890123456789 01234567890abc"

@defragster - @PaulStoffregen
Ran the code in Post 2 as well with the test string "1234567890123456789012345678901234567890123456789 01234567890abc" 63 chars plus NewLine :: Total 64". Got the same results as @PaulStoffregen on a Windows 10 x64 PC. Set longer strings as well:

CaptureSerial.PNG
 
The latest code on github is now using 512 byte packets. I did test with a 511 character (plus newline) string and I did watch with my USB protocol analyzer to check it was all in 1 packet, both receiving and sending, plus a ZLP sent after the full packet.
 
Updated code from Github runs post #1 code with post #2 FAIL string :: "1234567890123456789012345678901234567890123456789 01234567890abc"

Perhaps the "Github runs post #1 code " wasn't seen as CONFIRMATION that Github runs post #1 code - without problem or issue.
 
512 bytes Also WORKING - with yesterday's github USB update: Multiple of the 64 byte line in a single Send up to and including 512 works as a single read group.

Did CODE mod to show read count and string.length and count of .available() in serialEvent() call and they agree and 511 bytes and 512 bytes come in one packet.

Anything over 512 comes in the next group, and two sets of 512 in one string arrive in two packs of 512.

Code:
String    hostString = "";
int ii, jj;

void setup() {
  Serial.begin(38400);
  hostString = "";
  ii = jj = 0;
}

void    serialEvent() {
  if (Serial.available())
    jj = Serial.available();
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    hostString += inChar;
    ii++;
  }
}

void loop() {
  if (hostString.length()) {
    Serial.print(hostString);
    Serial.printf("\nString len is %u and read cnt=%u {.avail()=%u}\n", hostString.length(), ii, jj);
    hostString = "";
    ii = jj = 0;
  }
}
 
Status
Not open for further replies.
Back
Top