Teensy 4.1 USB serial receive may hang for buffers over 2K

Status
Not open for further replies.

Goldfinch

Member
Hello
I'm having a program on a Raspberry PI (running Debian Linux) that sends data over USB, using the profile CDC serial. The length transferred from the PI is of variable size, from a few bytes (always a multiple of 4) to about 3K max every 16 ms. From time to time the communication locks up. The TEENSY detects a timeout condition, but the PI is still stuck in transmit. I have to disconnect and reconnect the cable, and restart the transfer on the the PI. Note that I tried the same program on a PC running Windows, and I have the same problem (maybe less frequently, but I have it also).

I have a Teensy 4.1
I am using Teensyduino 1.53

The teensy never transmits data, always receive
The PI never receive data, always transmit

I noticed that every time it hangs, the PI has over 2K of data to transmit. It does not seem to hang under the 2K limit.
For the moment, I have a workaround (never transmit over 2K), but still - there seems to be a problem on the receive size of the TEENSY.


Here is the code.
Teensy (receive side)

Code:
    static uint8_t  buf[BUF_SIZE];
        do {
            if (!usb_configuration) {
                return;
            }
            size = usb_serial_available();
            if (size) {
                size = MIN(size, sizeof(buf));
                usb_serial_read(buf, size);
            }
        } 
        while (size == 0);

...

RASPI (or PC)

static int serial_write(void *buf, uint32_t size)
{
result = write(s_serial_fd, buf, size);
return result > 0;
}
 
Last edited by a moderator:
Added code # to post #1

Should the final line of the while read as follows? :: while (size != 0);

Code:
    static uint8_t  buf[BUF_SIZE];
        do {
            if (!usb_configuration) {
                return;
            }
            size = usb_serial_available();
            if (size) {
                size = MIN(size, sizeof(buf));
                usb_serial_read(buf, size);
            }
        } 
        [B]while (size != 0);[/B]

...
 
No. I want to be out of the loop when I have something. I left out the timeout and the data processing portion which is not interesting here.

Code:
for (;;) {
        ...
        do {
            if (!usb_configuration) {
                return;
            }
            size = usb_serial_available();
            if (size) {
                size = MIN(size, sizeof(buf));
                usb_serial_read(buf, size);
            }

        } 
        while (size == 0);

        for (i = 0; i < size; i++) {
             // do something with the bytes received
        } 
        ...
}
 
Seeing other code that gets back into the loop might be useful.

One quick test would be to ignore the processing for now and try the code change above to see if it still fails when all available data is pulled when available.

If a simple sample like that can fail - then that would make identifying a problem easier.
If it works the problem is elsewhere in code not shown.

Maybe:
Code:
    static uint8_t  buf[BUF_SIZE];
        do {
            if (!usb_configuration) {
                return;
            }
            size = usb_serial_available();
            if (size) {
                size = MIN(size, sizeof(buf));
                usb_serial_read(buf, size);
            }
Serial.println( size );
        } 
        while (size != 0);
 
Here is the more complete code with timeout. I have a timeout because i have not received data for 3 seconds.
Code:
    for (;;) {
        tick = millis();
        do {
            if (!usb_configuration) {
                return;
            }
             size = usb_serial_available();
             if (size) {
                 size = MIN(size, sizeof(buf));
                 usb_serial_read(buf, size);
             }
             else {
                 curr_tick = millis();
                 if (curr_tick - tick > (3000)) {
                     return;  <=== goes there when I have the problem. usb_serial_available() returns 0 for 3 seconds.
                 }
            }
      }
 
If a fully functional sketch could be presented to show the problem it could be observed and then understood/fixed.

Snippets don't allow a repro of the situation at hand. Even if the time was taken to emulate the described issue in code - it might miss what is being seen.
 
If a fully functional sketch could be presented to show the problem it could be observed and then understood/fixed.

Snippets don't allow a repro of the situation at hand. Even if the time was taken to emulate the described issue in code - it might miss what is being seen.

Ok, i will do a simple sketch that reproduces the problem. I will supply the sender program which can be compiled with gcc.
 
Thanks. Looking forward to running it here and trying to reproduce this.

Please let me know which Raspberry Pi you're using, and if it's the new version 4, whether to plug Teensy into a USB 2 or USB 3 ports.
 
Thanks. Looking forward to running it here and trying to reproduce this.

Please let me know which Raspberry Pi you're using, and if it's the new version 4, whether to plug Teensy into a USB 2 or USB 3 ports.

It's a Pi 4. It's not the latest revision. The problem is reproduced on any USB port (2 or 3).

I will supply the code sometimes over the weekend.

Regards
 
I was not able to reproduce it in a simple setup, but I found a workaround by adding this code:

Code:
             size = usb_serial_available();
             
             [B]             
              if (size == 0) {
                 size = usb_serial_read(buf, 4);
             }[/B]
             else {
                 size = MIN(size, sizeof(buf));
                 usb_serial_read(buf, size);
             }

In usb_serial.c the code does the following:

Code:
// number of bytes available in the receive buffer
int usb_serial_available(void)
{
	return rx_available;
}

It looks like it is possible for rx_available to be 0, BUT in reality there is data in the receive ring.
 
Status
Not open for further replies.
Back
Top