Skip to content

Serial.available() only returns 0 or 1 when sending multiple single bytes to atmega32u4 #267

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
teliot opened this issue May 17, 2016 · 10 comments

Comments

@teliot
Copy link

teliot commented May 17, 2016

Serial.available() never returns anything other then 0 or 1 when sending single bytes to the software serial of a mega32u4.

test code

void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(Serial.available());
delay(100);
}

i can reproduce this on the client by using putty to send individual bytes.

while(Serial.available() < 4) ;
will lockup the program.

while(Serial.available() < 4) {
if (serialEventRun)
serialEventRun();
}
will not lockup the program but gets stuck in an infinite loop with single bytes being sent in. if i use the built in serial monitor sending a string of multiple bytes will exit the loop.

Example:
Serial.available() == 0
send one byte
Serial.available() == 1
send one byte
Serial.available() == 1

Restart device
Serial.available() == 0
send 4 bytes in one packet
Serial.available() == 4
send 1 byte
Serial.available() == 4

this behavior is different then a hardware serial of an uno

@teliot
Copy link
Author

teliot commented May 19, 2016

looking through the code and the data sheet it does not seem possible to get all the bytes available; only the byte count of the oldest packet. from what i can tell any subsequent packets sent do not make it into the endpoint. when bytes are read from serial it makes a call to available() to set max bytes to be retrieved. not sure if this should be changed to recheck available() after the endpoint has been emptied to see if more bytes should be fetched to attempt and read all the bytes or to the amount the sketch requested with readBytes.

i think the only possibility is to document the difference in software serial and move on. :(

@JulyJim
Copy link

JulyJim commented May 29, 2016

Serial.available returns 1 when there is a data in the serial buffer.
Explicitly checking for ANY other value, > 1, defeats the purpose of this function which is to simply detect the presence of data in buffer.

It is up to the rest of the code to process or count, if so desired, the characters in the buffer.

This "Serial.available > 1" can be source of nasty bugs ( missing data) since your program structure often processes the serial data much faster than it is arriving.

@teliot
Copy link
Author

teliot commented May 29, 2016

the online doc says it counts the number of bytes in the buffer.

https://www.arduino.cc/en/Serial/Available

@JulyJim
Copy link

JulyJim commented May 30, 2016

Yes, it does count the # of bytes, read my post again.

" purpose of this function which is to simply detect the presence of data in buffer."

@matthijskooijman
Copy link
Collaborator

Yes, it does count the # of bytes, read my post again.
" purpose of this function which is to simply detect the presence of data in buffer."

It seems that @teliot is arguing that the purpose of this function is to count the number of bytes in the buffer, not just detect the presence of data. I agree with him on that, as does the documentation he linked.

@teliot, As for the original issue, I haven't looked at the 32u4 serial code (I'm assuming you're talking about the CDC serial code, not software serial, which is usually used to refer to bit-banging serial on an I/O pin), but it would be preferable to make that behave like hardware serial as well. I don't quite follow what you're saying about this, though. Does the hardware buffer multiple USB packets and can you only access the byte count of one of them? Or does the USB host perhaps buffer the data until the 32u4 processed the packet completely?

@teliot
Copy link
Author

teliot commented May 30, 2016

i looked through the 32u4 data sheet and lufa docs a good deal but was unable to find any mention of gaining access to any packet other then the current one. additionally i am unsure myself as to how exactly the endpoints work. i may be getting overly confused on the data sheet or the info just isn't there.

if i were to guess, the packets come in and are buffered in DPRAM. the endpoint registers allow you to only access the first packet (FIFO). the LUFA docs did mention something about building a table, if it is talking about endpoints the overhead of accessing and decoding the dpram would be a waste of cycles.

at this point i believe the best thing is to add a blurb in the docs that USB serial endpoints of the 32u4 (leonardo and variants) can only read one packet at a time.

if someone more familiar with the chip knows of a way they can always chip in, users can always create a software buffer at the expense of ram if they wish.

@JulyJim
Copy link

JulyJim commented May 31, 2016

I am not sure why you have added "USB" .
The USB to UART conversion is part of the process, but "ahead" of "Serial".

"Serial" is an instance of "HardwareSerial" class which in an essence performs UART functions - collect incoming data into a buffer via 32u4.

If you code is
while(!Serial.available());
you are waiting for a data to be in this buffer.

Even the slowest processor will detect ONLY the first data and proceed into next instruction.
That is why I mentioned that collecting the data really depends on the rest of the code and counting characters , as you did, is not very good way to retrieve data from the serial buffer.

If this is not helping, I must have missed something in your OP.

@matthijskooijman
Copy link
Collaborator

@VaclavSal, what you describe is what happens on e.g. the Arduino Uno, which has an atmega328p running user code, and a atmega16u2 running the USB->serial conversion. This issue is about e.g. the Arduino Leonardo, which has a 32u4 that runs both user code and the virtual serial port over USB, with no separate USB part required.

@teliot
Copy link
Author

teliot commented May 31, 2016

i don't think the usb serial endpoint reuses any code from the HardwareSerial files directly and has all of it's code in the board file and the usb* (mostly usbcore) files.

EDIT: did not see matt's last comment above when i replied. his reply explains it better.

@sandeepmistry sandeepmistry transferred this issue from arduino/Arduino Sep 16, 2019
@RFreese
Copy link

RFreese commented Jun 27, 2021

the online doc says it counts the number of bytes in the buffer.

https://www.arduino.cc/en/Serial/Available

came across the same issue and found just recently that several answers were correct, while not helping to understand the issue. When reciving data Serial.Available() is returning the number of bytes. Key is that the receiving and processing is so fast that the 1st byte in reception is already processed. My sequence to allow the receive queue to get all bytes, before starting to read and process the complete receive buffer is simply:
iByteCount = Serial.available();
if (iByteCount > 0) {
delay(50);
iByteCount = Serial.available();
....
The 1st iByteCount always shows 1 when data are received and the 2nd Serial.available returns the correct number of bytes received. So with an apropriate delay, addapted to the expected amount of bytes and communication speed this is my solution for the reported confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants