tozz88
March 9, 2019, 1:27am
1
I have noticed that whenever I try to send exactly 64 bytes of data from PC to MKRZERO the MKRZERO never sees it. Serial.avaialbe() returns 0 forever. This also happens if it is a residual 64 bytes off of a
multiple of 256. For example if I send 320 bytes I get the initial 256 but the final 64 bytes is never received.
I saw a thread that seemed to imply there is a known issue with SAMD21-based boards sending a 64
byte packet. Is this a similar issue? Can anybody point me to a solution?
pert
March 9, 2019, 1:45am
2
Do you happen to have a link to the thread you found? It might be helpful. I remembered seeing a bug report of something like this. I think I found the one I was thinking of, but it was being reported for the AVR-based Arduino Micro, rather than a SAMD21 board:
opened 02:37PM - 28 Jul 18 UTC
This issue was first reported in my project here https://github.com/kervinck/gig… atron-rom/issues/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:
```
void setup() {
Serial.begin(115200);
}
void loop() {
static int lineLength = 0;
if (Serial.available()) {
char next = Serial.read();
lineLength++;
if (next == '\n' || next == '\r') {
Serial.println(lineLength);
lineLength = 0;
}
}
}
```
Test Python program to demonstrate that the issue is with data messages of exactly 64 bytes:
```
import serial
from time import sleep
tty = '/dev/tty.usbmodem1411' # 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)
reply = ser.readline()
print('< %s %s' % (repr(reply), 'OK' if reply else 'TIMEOUT'))
```
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.
```
> 'AAAAAAAAA\n' (10 bytes)
< '10\r\n' OK
> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n' (70 bytes)
< '70\r\n' OK
> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n' (65 bytes)
< '65\r\n' OK
> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n' (64 bytes)
< '64\r\n' OK
> 'AAAAAAAAA\n' (10 bytes)
< '' TIMEOUT
> 'AAAAAAAAA\n' (10 bytes)
< '' TIMEOUT
```
Expected output is what the Arduino Uno does:
```
> 'AAAAAAAAA\n' (10 bytes)
< '10\r\n' OK
> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n' (70 bytes)
< '70\r\n' OK
> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n' (65 bytes)
< '65\r\n' OK
> 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n' (64 bytes)
< '64\r\n' OK
> 'AAAAAAAAA\n' (10 bytes)
< '10\r\n' OK
> 'AAAAAAAAA\n' (10 bytes)
< '10\r\n' OK
```
Somewhat related to https://github.com/arduino/Arduino/issues/6669 ("Arduino Micro USB Serial cannot receive more than 255 data once") and https://github.com/arduino/Arduino/pull/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:
> RXOUTI shall always be cleared before clearing FIFOCON
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 https://github.com/kervinck/gigatron-rom/commit/94d167dd755bdad22af6ae818f879f1d3e961e86 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.
- Why not use RWAL in USB_Available instead of UEBCLX. Tracing its value in different scenarios, UEBCLX doesn't always seem quite the right indicator. It can sometimes momentarily read 0 in the middle of a transfer sequence. (Besides the question what to to with UEBCHX in case that ever becomes relevant)
- What is the magic constant 0x6B in ReleaseRX? Why not address the desired bits explicitly with masking operations.
- USB_Recv() does some interesting things with its n and len, and the condition before ReleaseRX seems a bit suspect to me.
tozz88
March 9, 2019, 2:20am
3
Here is the post. Looking at the post it is for Leonardo. So maybe it isn't the same thing:
opened 07:37PM - 09 Oct 15 UTC
closed 04:02PM - 11 Jul 16 UTC
Type: Bug
Architecture: AVR
USB: CDC serial
When using the virtual serial port on the Leonardo I found that if I send exactl… y 64 bytes it doesn't send until another byte is sent. Below is a demo to show this problem.
```
void setup() {
// put your setup code here, to run once:
}
void loop() {
if (Serial) {
if (Serial.available() > 0) {
Serial.read();
char buff[65] = "D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE";
Serial.write(buff,64);
Serial.flush();
}
}
}
```
After sending a character, nothing appears in the terminal. However, sending another then prints all 128 characters. This happens regardless of the serial port monitor I've tried. I've also tried on Linux and Windows 10 with slightly different, but similar results. This is with 1.6.5.
tozz88
March 11, 2019, 6:17pm
4
Okay, I've ran several tests and found the following pattern:
size result
64 fails
128 fails
192 fails
256 succeeds
384 fails
448 fails
512 succeeds
576 fails
...
The failure case is:
if ((size%256)%64 == 0) then fails.
tozz88
March 11, 2019, 9:23pm
5
Here is an update to the table. I forgot 320 bytes and I have additional information as to what actual gets
delivered to the MKRZERO sketch
size results
64 fails
128 fails
192 fails
256 success
320 fails (first 256 bytes delivered)
384 fails (first 256 bytes delivered)
448 fails (first 256 bytes delivered)
512 success
576 fails (first 512 bytes delivered)
As you can see the failure occurs if size%64==0 and size%256!=0
Also all size - size%256 bytes are delivered. its just the residual size%256 bytes that are not.
tozz88
March 11, 2019, 9:30pm
6
Note. This issue was recently opened on github by a co-worker that is tracking essentially the same issue:
opened 03:36AM - 11 Mar 19 UTC
bug
Component: USB-CDC
I tried to write the data to Arduino MKR Zero but always read 0 (Serial1.println… (SerialUSB.available());) when data size exactly same as 64 bytes or 128 bytes. send 256bytes are fine.
If I work around this by issue another transaction to send the last bytes of 64/128byte data.
```
#Host side
if len(msg)%64 == 0 and len(msg) != 256:
self.comm.write(msg[0:len(msg)-1])
self.comm.write(msg[len(msg)-1:])
```
Does anyone meet this issue?
Thanks