-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Arduino Micro USB Serial cannot receive exactly 64 bytes at once #112
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
Comments
Correct me if I'm wrong, I'm new to Arduino / USB related stuff, so it's very likely I might misunderstood something. I'm working on a similar project, but it might sometimes tries to receive 64, 128 (64+64+64), 192 (64x3), 256(64x4) bytes. Like what Marcel said, I think there are a few problems in the code so it cannot work correctly. (And it seems working applying these fixes). In USB_Recv: 2). Before reading FifoByteCount / FIFOCON, we should check if RXOUTI is flipped? If it's flipped then we should clear RXOUTI bit (so Fifo queue will be freezed, otherwise if it's not fulled FifoByteCount may not be accurate?). If if RXOUTI = 0 then it means it's not ready and we should return -1? 3). We should always clear FIFOCON when FifoByteCount() ==0, as even len==0 we should still clear FIFOCON bit when RXOUTI is cleared. Similarly, I think USB_Send() has similar issue, it now always send a Zlp, which is not correct, as if I want to send 128bytes out, but due to out of memory issue I break it down into 2 USB_Send() calls, my first USB_Send() will send a Zlp which terminate the transfer already. |
Has there been any new info on this issue? I am seeing similar behavior on the MKRZERO board. Using the above method I see failure in the following way. Results when attempting to send bytes from host size results As you can see the failure occurs if size%64==0 and size%256!=0 |
the problem is in the available() function it modulates by the buffer sizes to return the number of bytes available, so if you send exactly the buffer size it returns 64 % 64 as the amount available. I suspect the data is being delivered fine and is in the receive buffer, you're just not being notified about it. Serial::available needs to be fixed. you can solve this by just sending one byte at a time but that shouldn't be the solution, we should be able to send any size frame of data and it should be reported as delivered. This is my literal working solution:
It's really stupid but it solves all of my problems. |
@Unreal-Dan I'm a bit confused. The report is about Arduino Micro USB serial, which is native CDC serial handled by https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/CDC.cpp, while you link to the HardwareSerial implementation that is used for UARTs only. As for the fix, you suggest a @tozz88 also wrote (before this issue was moved into the AVR core repo, I see):
For reference, the code that handles MKRZERO lives at https://github.com/arduino/ArduinoCore-samd, so that is a different issue resulting from different code that should ideally be reported in that repository (if there is no open issue about it yet - I have not checked). It could be that the same mistake was made in that code too, but maybe it's a different problem with the same symptom, so better to track them separately. |
I'm not super familiar with the arduino source code and I and just peeked quickly inside and assumed I knew the answer, I realize now that there are different implementations for available() Whatever the issue is, sending exactly 64 bytes is problematic when I send it to a trinket m0, the receiver (trinket) never indicates any data is available and by simply sending one byte ahead of time and sending the rest of the 63 afterward everything works well. Perhaps this information can help to solve the problem, or it can help others in similar situations as I was. Also apologies, the writeData function I provided is a routine I am using to communicate with my arduino from windows. I am manually connecting the COM port and sending serial data, when I send a block of exactly 64bytes the arduino never sees anything, and it just always returns 0 from available(). As soon as I send one more byte then available() returns non-zero and I am able to read all 65 bytes. When I say it is a solution, I mean it is a solution for people looking to communicate with their arduino without the 64 byte issue getting in their way. |
Oh, that's even yet another board. The trinket M0 is runs on the Adafruit's version of the samd core, which I guess is derived from Arduino's samd core. Good to know that all three of these cores (AVR, SAMD and Adafruit SAMD) are affected, though this issue is strictly about the AVR version only (but I suspect that there might be some shared code that is the underlying cause).
Ah, thanks for clarifying. |
I ran this on Arduino Leonardo using AVR boards 1.8.6. Could not reproduce the problem. Prints this:
I did have to modify the python script slightly to work with the python3 install on Ubuntu 22.04. import serial
from time import sleep
tty = '/dev/ttyACM0' # Adapt for your own computer
ser = serial.Serial(tty, baudrate=115200, timeout=1)
sleep(1) # For Arduinos that reboot
for length in [10, 70, 65, 64, 10, 10]:
line = (length-1)*'A' + '\n'
print('> %s (%d bytes)' % (repr(line), len(line)))
ser.write(line.encode())
reply = ser.readline()
print('< %s %s' % (repr(reply), 'OK' if reply else 'TIMEOUT')) |
Also tried on Arduino Zero using SAMD boards 1.8.14. To use the native port I had to replace "Serial" with "SerialUSB", as "Serial" talks to the debug port. This is the code I ran on Arduino Zero: void setup() {
SerialUSB.begin(115200);
}
void loop() {
static int lineLength = 0;
if (SerialUSB.available()) {
char next = SerialUSB.read();
lineLength++;
if (next == '\n' || next == '\r') {
SerialUSB.println(lineLength);
lineLength = 0;
}
}
} Also could not reproduce the problem, running the python script on Ubuntu 22.04. Got this again:
And FWIW, also tested on Teensy 4.1, Teensy 3.2, Teensy LC, Teensy++ 2.0 and Teensy 2.0. Could not reproduce the problem on any of those either. |
One last test, MKR1000 with the original code (not "SerialUSB"). Also works.
|
Unless someone can confirm the problem happen with Windows or MacOS, seems likely this issue is no longer an issue. |
This issue was first reported in my project here kervinck/gigatron-rom#36 but I now believe the root cause might be in USBCore.cpp
Tested in Ardiuno IDE 1.8.1 and 1.8.6 (arduino-PR-6886-BUILD-734-macosx.zip)
BN: Arduino/Genuino Micro
VID: 2341
PID: 8037
SN: Upload any sketch to obtain it
The example sketch just receives lines of text and reports their length:
Test Python program to demonstrate that the issue is with data messages of exactly 64 bytes:
Output shows that the Arduino Micro stops receiving data after having received the 64-byte "killer" line. It does see the 64-byte message itself and it is still able to send. But it doesn't see new data anymore.
Expected output is what the Arduino Uno does:
Somewhat related to https://github.com/arduino/Arduino/issues/6669 ("Arduino Micro USB Serial cannot receive more than 255 data once") and arduino/Arduino#6886 ("Handle receiving a ZLP in USB_Available"), however the proposed solution of that issue doesn't solve this.
I suspect the problem is caused by not following the datasheet's sequence, specifically:
The way USB_Recv is written I don't think ReleaseRX will ever be called twice in a row. And that is exactly what gets me out of the hangup situation. In my own project I have integrated a workaround kervinck/gigatron-rom@94d167d that seems to work by clearing FICOCON after Serial.read() and observing that UEBCLX has become 0. But I haven't considered every possible scenario (race conditions?).
I have some general remarks about USBCore.cpp, and this is very subjective, so please take no offense. But having studied the code with an actual problem, the Arduino Micro hooked up and the datasheets at hand, I have the impression some more issues might be lurking here. It is not obvious (to me) that the code and the datasheet match.
The text was updated successfully, but these errors were encountered: