Teensy 3.0 Serial.available() bug?

Bill Greiman

Well-known member
This sketch:
Code:
void setup() {
  Serial.begin(9600);
  while(!Serial);
}
void loop() {
  Serial.println(Serial.available());
  Serial.read();  
  delay(1000);
}
Produces these strange values for Serial.available()
0
57344
49152
40960
32768
24576
16384
8192
0
57344
49152
40960
32768
24576
16384
8192
 
I think your context assumes a boolean result from Serial.available() but indeed it returns an int. Or some such, with the way the class is written.
Look at, try this code. It works as you'd expect
Code:
void setup() {
  Serial.begin(9600);
  while(!Serial)
    {}; // for  clarity
}

void loop() {
  int n;
  n = Serial.available();
  if (n)
    while (n)
      Serial.printf("n=%d data=%02X\n", n--, Serial.read());
  else
    Serial.printf("no data available\n");
  delay(1000);
}
 
this code works as you'd expect as well
Code:
void setup() {
  Serial.begin(9600);
  while(!Serial)
    {}; // for  clarity
}

void loop() {
  while (Serial.available())
      Serial.printf("data=0x%02X\n", Serial.read());
  delay(1000);
  Serial.printf("no data at tick:%d\n", millis());
}
 
You are right, this is some kind of bug. I also get bogus numbers with a case like yours (different numbers though). The problem seems to be the Serial.read(). In your case if the Serial.read() is issued when there is no data, then somehow it is screwing up Serial.available().

If I make the following change, only reading when data exists, then it seems to work fine.

This sketch:
Code:
void setup() {
  Serial.begin(9600);
  while(!Serial);
}
void loop() {
  Serial.println(Serial.available());
  [COLOR="#FF0000"]if(Serial.available())[/COLOR]    
    Serial.read();  
  delay(1000);
}
Produces these strange values for Serial.available()
 
From your post #5, I'm confused.
The two examples I posted, on my hardware, seem to run correctly.
Are you saying the same code does not, you your devices and versions?
 
No, it was a reply to the top post. If I run the top post code as-is, I see the same odd behavior (well different but similar, my output alternates between 0, 32768, 0, 32768, ...). The problem can be traced to the Serial.read(), if it is blocked when there is no available data then everything works. Notice both your examples block read() unless data is available. Try doing a read() regardless of data available and see what you get.
 
Here, using your code, try running with this change instead:

Code:
void setup() {
  Serial.begin(9600);
  while(!Serial)
    {}; // for  clarity
}

void loop() {
  while (Serial.available())
      Serial.printf("data=0x%02X\n", Serial.read());
  delay(1000);
  Serial.printf("no data at tick:%d\n", millis());
  [COLOR="#FF0000"]Serial.read();[/COLOR]
}
 
Hmm. the added Serial.read() in the bottom should get back an undefined value, or -1 rather than a 8 bit value, since the read is done without regard to whether or not data is available.
But adding that causes mine to display, at the first Serial.read(), -1 in hex, 32 bits, with Serial.available() erroneously returning a non-zero value (true), to satisfy the while().
funny, the code cycles, with the correct value every 7 iterations.
 
Hrm, just a guess here, but I traced this down into the code, perhaps the bug is here (in usb_dev.c):
Code:
usb_packet_t *usb_rx(uint32_t endpoint)
{
	usb_packet_t *ret;
	endpoint--;
	if (endpoint >= NUM_ENDPOINTS) return NULL;
	__disable_irq();
	ret = rx_first[endpoint];
	if (ret) rx_first[endpoint] = ret->next;
	[COLOR="#FF0000"]usb_rx_byte_count_data[endpoint] -= ret->len;[/COLOR]
	__enable_irq();
	//serial_print("rx, epidx=");
	//serial_phex(endpoint);
	//serial_print(", packet=");
	//serial_phex32(ret);
	//serial_print("\n");
	return ret;
}

should this be instead:
Code:
usb_packet_t *usb_rx(uint32_t endpoint)
{
	usb_packet_t *ret;
	endpoint--;
	if (endpoint >= NUM_ENDPOINTS) return NULL;
	__disable_irq();
	ret = rx_first[endpoint];
[COLOR="#FF0000"]	if (ret) 
        {
            rx_first[endpoint] = ret->next;
	    usb_rx_byte_count_data[endpoint] -= ret->len;
        }
[/COLOR]	__enable_irq();
	//serial_print("rx, epidx=");
	//serial_phex(endpoint);
	//serial_print(", packet=");
	//serial_phex32(ret);
	//serial_print("\n");
	return ret;
}

otherwise usb_rx_byte_count_data[endpoint] is getting subtracted regardless of whether ret is a valid pointer or not.
 
Last edited:
RE the below... I see that there are posts here above this one; I wrote this before noticing the new ones above.

Further testing.. seems to me there's a subtle coding error, in the interface between usb_serial.c and stream.cpp.

It's somewhere in the arrangement of virtual functions alternatives for read() and readBytes(), if called when the buffer is empty, cause the next available() to return wrong value.
Somehow related to timeout too, as the value seen by available() changes every few loop iterations.

The c to cpp interfaces and virtual overrides aren't something I can find/follow (I hate that about c++ where there are no comments).
 
I made the change per commit 482a1f2.
Then tested.
Cured the edge case problem caused if a usb read() is done when there is no data available.
 
Back
Top